webdav token regeneration

This commit is contained in:
2025-10-31 20:37:07 +01:00
parent e9731ec691
commit 18352caabe
14 changed files with 304 additions and 69 deletions
+46
View File
@@ -322,6 +322,7 @@ const AppLayout = () => {
const [webdavTokensLoading, setWebdavTokensLoading] = useState(false);
const [creatingWebdavToken, setCreatingWebdavToken] = useState(false);
const [deletingWebdavTokenId, setDeletingWebdavTokenId] = useState(null);
const [regeneratingWebdavTokenId, setRegeneratingWebdavTokenId] = useState(null);
const [webdavTokenSecret, setWebdavTokenSecret] = useState(null);
const [searchQuery, setSearchQuery] = useState('');
const [activeTagFilters, setActiveTagFilters] = useState([]);
@@ -1597,6 +1598,47 @@ const AppLayout = () => {
[refreshWebdavTokens, notifyApiError, setStatusMessage],
);
const regenerateWebdavToken = useCallback(
async (tokenId) => {
if (!tokenId) {
return false;
}
setRegeneratingWebdavTokenId(tokenId);
try {
const { data } = await api.post(`/profile/webdav-tokens/${tokenId}/regenerate`);
if (data?.token_info) {
setWebdavTokens((previous) => {
let found = false;
const next = previous.map((entry) => {
if (entry.id === data.token_info.id) {
found = true;
return data.token_info;
}
return entry;
});
if (!found) {
return [data.token_info, ...previous];
}
return next;
});
} else {
await refreshWebdavTokens();
}
if (data?.token) {
setWebdavTokenSecret(data.token);
}
setStatusMessage('WebDAV token regenerated.', 'success');
return true;
} catch (error) {
notifyApiError(error, 'Failed to regenerate WebDAV token.');
return false;
} finally {
setRegeneratingWebdavTokenId(null);
}
},
[notifyApiError, refreshWebdavTokens, setStatusMessage],
);
const dismissCreatedWebdavToken = useCallback(() => {
setWebdavTokenSecret(null);
}, []);
@@ -5040,9 +5082,11 @@ const AppLayout = () => {
webdavTokensLoading,
creatingWebdavToken,
deletingWebdavTokenId,
regeneratingWebdavTokenId,
refreshWebdavTokens,
createWebdavToken,
deleteWebdavToken,
regenerateWebdavToken,
webdavTokenSecret,
dismissCreatedWebdavToken,
passkeys,
@@ -5098,9 +5142,11 @@ const AppLayout = () => {
webdavTokensLoading,
creatingWebdavToken,
deletingWebdavTokenId,
regeneratingWebdavTokenId,
refreshWebdavTokens,
createWebdavToken,
deleteWebdavToken,
regenerateWebdavToken,
webdavTokenSecret,
dismissCreatedWebdavToken,
passkeys,
+4
View File
@@ -10,9 +10,11 @@ const SettingsRoute = () => {
webdavTokensLoading,
creatingWebdavToken,
deletingWebdavTokenId,
regeneratingWebdavTokenId,
refreshWebdavTokens,
createWebdavToken,
deleteWebdavToken,
regenerateWebdavToken,
webdavTokenSecret,
dismissCreatedWebdavToken,
passkeys,
@@ -58,9 +60,11 @@ const SettingsRoute = () => {
loading={webdavTokensLoading}
creating={creatingWebdavToken}
deletingId={deletingWebdavTokenId}
regeneratingId={regeneratingWebdavTokenId}
onRefresh={refreshWebdavTokens}
onCreate={createWebdavToken}
onDelete={deleteWebdavToken}
onRegenerate={regenerateWebdavToken}
createdToken={webdavTokenSecret}
onDismissCreatedToken={dismissCreatedWebdavToken}
passkeys={passkeys}
+36 -8
View File
@@ -19,9 +19,11 @@ const SettingsModal = ({
loading = false,
creating = false,
deletingId = null,
regeneratingId = null,
onRefresh,
onCreate,
onDelete,
onRegenerate,
createdToken = null,
onDismissCreatedToken,
passkeys = [],
@@ -147,6 +149,16 @@ const SettingsModal = ({
[newTokenExpires, newTokenLabel, onCreate],
);
const handleRegenerateToken = useCallback(
async (token) => {
if (!token?.id) {
return;
}
await onRegenerate?.(token.id);
},
[onRegenerate],
);
const renderWebdavSection = useMemo(() => {
const hasTokens = Array.isArray(tokens) && tokens.length > 0;
@@ -240,14 +252,28 @@ const SettingsModal = ({
{isRevoked ? (
<span className="settings-status">Revoked</span>
) : (
<button
type="button"
className="danger"
onClick={() => onDelete?.(token.id)}
disabled={deletingId === token.id}
>
{deletingId === token.id ? 'Revoking…' : 'Revoke'}
</button>
<>
<button
type="button"
className="secondary"
onClick={() => handleRegenerateToken(token)}
disabled={
regeneratingId === token.id || deletingId === token.id
}
>
{regeneratingId === token.id ? 'Regenerating…' : 'Regenerate'}
</button>
<button
type="button"
className="danger"
onClick={() => onDelete?.(token.id)}
disabled={
deletingId === token.id || regeneratingId === token.id
}
>
{deletingId === token.id ? 'Revoking…' : 'Revoke'}
</button>
</>
)}
</td>
</tr>
@@ -264,12 +290,14 @@ const SettingsModal = ({
createdToken,
creating,
deletingId,
regeneratingId,
newTokenLabel,
newTokenExpires,
formError,
formatDateTime,
handleCopyToken,
handleCreateToken,
handleRegenerateToken,
handleRefresh,
onDelete,
handleDismissSecret,