Skip to content

Commit 8bfe2e5

Browse files
authored
perf: 优化开发者模式编辑交互 (#266)
* perf: 优化开发者模式编辑交互 * fix: 修复编辑弹窗可访问性
1 parent 5faf34f commit 8bfe2e5

File tree

1 file changed

+41
-36
lines changed

1 file changed

+41
-36
lines changed

web/src/pages/api-tokens/index.tsx

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react';
1+
import { useId, useState } from 'react';
22
import { useTranslation } from 'react-i18next';
33
import {
44
Button,
@@ -73,22 +73,30 @@ export function APITokensPage() {
7373
name: string;
7474
} | null>(null);
7575
const [copied, setCopied] = useState(false);
76+
const devModeSwitchId = useId();
7677

7778
// Form state
7879
const [name, setName] = useState('');
7980
const [description, setDescription] = useState('');
8081
const [projectID, setProjectID] = useState<string>('0');
8182
const [expiresAt, setExpiresAt] = useState('');
83+
const [devMode, setDevMode] = useState(false);
8284
const [showProjectPicker, setShowProjectPicker] = useState(false);
8385

8486
const resetForm = () => {
8587
setName('');
8688
setDescription('');
8789
setProjectID('0');
8890
setExpiresAt('');
91+
setDevMode(false);
8992
setShowProjectPicker(false);
9093
};
9194

95+
const closeEditDialog = () => {
96+
setEditingToken(null);
97+
resetForm();
98+
};
99+
92100
const handleSubmit = (e: React.FormEvent) => {
93101
e.preventDefault();
94102
createToken.mutate(
@@ -121,13 +129,11 @@ export function APITokensPage() {
121129
description,
122130
projectID: parseInt(projectID) || 0,
123131
expiresAt: expiresAt ? new Date(expiresAt).toISOString() : undefined,
132+
devMode,
124133
},
125134
},
126135
{
127-
onSuccess: () => {
128-
setEditingToken(null);
129-
resetForm();
130-
},
136+
onSuccess: () => closeEditDialog(),
131137
},
132138
);
133139
};
@@ -139,13 +145,6 @@ export function APITokensPage() {
139145
});
140146
};
141147

142-
const handleToggleDevMode = (token: APIToken) => {
143-
updateToken.mutate({
144-
id: token.id,
145-
data: { devMode: !token.devMode },
146-
});
147-
};
148-
149148
const handleDelete = () => {
150149
if (!deletingToken) return;
151150
deleteToken.mutate(deletingToken.id, {
@@ -159,6 +158,7 @@ export function APITokensPage() {
159158
setDescription(token.description);
160159
setProjectID(token.projectID.toString());
161160
setExpiresAt(token.expiresAt ? token.expiresAt.split('T')[0] : '');
161+
setDevMode(!!token.devMode);
162162
};
163163

164164
const handleCopyToken = async () => {
@@ -268,7 +268,6 @@ export function APITokensPage() {
268268
<TableHead>{t('apiTokens.tokenPrefix')}</TableHead>
269269
<TableHead>{t('apiTokens.project')}</TableHead>
270270
<TableHead>{t('common.status')}</TableHead>
271-
<TableHead>{t('apiTokens.devMode')}</TableHead>
272271
<TableHead>{t('apiTokens.usage')}</TableHead>
273272
<TableHead>{t('apiTokens.lastUsed')}</TableHead>
274273
<TableHead className="text-right">{t('common.actions')}</TableHead>
@@ -332,27 +331,6 @@ export function APITokensPage() {
332331
)}
333332
</div>
334333
</TableCell>
335-
<TableCell>
336-
<div className="flex items-center gap-2">
337-
<Switch
338-
checked={!!token.devMode}
339-
onCheckedChange={() => handleToggleDevMode(token)}
340-
disabled={updateToken.isPending}
341-
/>
342-
{token.devMode ? (
343-
<Badge
344-
variant="default"
345-
className="text-xs bg-blue-500/10 text-blue-500 border-blue-500/20"
346-
>
347-
{t('apiTokens.devModeEnabled')}
348-
</Badge>
349-
) : (
350-
<Badge variant="secondary" className="text-xs">
351-
{t('apiTokens.devModeDisabled')}
352-
</Badge>
353-
)}
354-
</div>
355-
</TableCell>
356334
<TableCell>
357335
<div className="flex items-center gap-1 text-sm text-text-secondary">
358336
<Hash className="h-3 w-3" />
@@ -503,7 +481,11 @@ export function APITokensPage() {
503481
{/* Edit Dialog */}
504482
<Dialog
505483
open={!!editingToken}
506-
onOpenChange={(open: boolean) => !open && setEditingToken(null)}
484+
onOpenChange={(open: boolean) => {
485+
if (!open) {
486+
closeEditDialog();
487+
}
488+
}}
507489
>
508490
<DialogContent>
509491
<DialogHeader>
@@ -567,8 +549,31 @@ export function APITokensPage() {
567549
min={new Date().toISOString().split('T')[0]}
568550
/>
569551
</div>
552+
<div className="flex items-center justify-between">
553+
<label
554+
htmlFor={devModeSwitchId}
555+
className="text-xs font-medium text-text-secondary uppercase tracking-wider"
556+
>
557+
{t('apiTokens.devMode')}
558+
</label>
559+
<div className="flex items-center gap-2">
560+
<Switch
561+
id={devModeSwitchId}
562+
checked={devMode}
563+
onCheckedChange={setDevMode}
564+
disabled={updateToken.isPending}
565+
/>
566+
<span className="text-xs text-text-muted">
567+
{devMode ? t('apiTokens.devModeEnabled') : t('apiTokens.devModeDisabled')}
568+
</span>
569+
</div>
570+
</div>
570571
<DialogFooter>
571-
<Button type="button" variant="outline" onClick={() => setEditingToken(null)}>
572+
<Button
573+
type="button"
574+
variant="outline"
575+
onClick={closeEditDialog}
576+
>
572577
{t('common.cancel')}
573578
</Button>
574579
<Button type="submit" disabled={updateToken.isPending || !name}>

0 commit comments

Comments
 (0)