Update CreateAccessTokenDialog and AccessTokenSection; improve handling

pull/5111/head
Nic Luckie 3 weeks ago
parent 1684b78cd3
commit c7b53930cc

@ -8,12 +8,13 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { userServiceClient } from "@/grpcweb"; import { userServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import { UserAccessToken } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
interface Props { interface Props {
open: boolean; open: boolean;
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
onSuccess: () => void; onSuccess: (created: UserAccessToken) => void;
} }
interface State { interface State {
@ -72,7 +73,7 @@ function CreateAccessTokenDialog({ open, onOpenChange, onSuccess }: Props) {
try { try {
requestState.setLoading(); requestState.setLoading();
await userServiceClient.createUserAccessToken({ const created = await userServiceClient.createUserAccessToken({
parent: currentUser.name, parent: currentUser.name,
accessToken: { accessToken: {
description: state.description, description: state.description,
@ -81,7 +82,7 @@ function CreateAccessTokenDialog({ open, onOpenChange, onSuccess }: Props) {
}); });
requestState.setFinish(); requestState.setFinish();
onSuccess(); onSuccess(created);
onOpenChange(false); onOpenChange(false);
} catch (error: any) { } catch (error: any) {
toast.error(error.details); toast.error(error.details);

@ -29,14 +29,13 @@ const AccessTokenSection = () => {
}); });
}, []); }, []);
const handleCreateAccessTokenDialogConfirm = async () => { const handleCreateAccessTokenDialogConfirm = async (created?: UserAccessToken) => {
const prevTokensSet = new Set(userAccessTokens.map((token) => token.accessToken)); // Refresh list to reflect server state and include stable fields like issuedAt/expiresAt
const accessTokens = await listAccessTokens(currentUser.name); const accessTokens = await listAccessTokens(currentUser.name);
setUserAccessTokens(accessTokens); setUserAccessTokens(accessTokens);
const newToken = accessTokens.find((token) => !prevTokensSet.has(token.accessToken));
toast.success( toast.success(
t("setting.access-token-section.create-dialog.access-token-created", { t("setting.access-token-section.create-dialog.access-token-created", {
description: newToken?.description ?? t("setting.access-token-section.create-dialog.access-token-created-default"), description: created?.description ?? t("setting.access-token-section.create-dialog.access-token-created-default"),
}), }),
); );
}; };
@ -56,9 +55,10 @@ const AccessTokenSection = () => {
const confirmDeleteAccessToken = async () => { const confirmDeleteAccessToken = async () => {
if (!deleteTarget) return; if (!deleteTarget) return;
const { name, accessToken, description } = deleteTarget; const { name: tokenName, description } = deleteTarget;
await userServiceClient.deleteUserAccessToken({ name }); await userServiceClient.deleteUserAccessToken({ name: tokenName });
setUserAccessTokens((prev) => prev.filter((token) => token.accessToken !== accessToken)); // Filter by stable resource name to avoid ambiguity with duplicate token strings
setUserAccessTokens((prev) => prev.filter((token) => token.name !== tokenName));
setDeleteTarget(undefined); setDeleteTarget(undefined);
toast.success(t("setting.access-token-section.access-token-deleted", { description })); toast.success(t("setting.access-token-section.access-token-deleted", { description }));
}; };
@ -108,7 +108,7 @@ const AccessTokenSection = () => {
</thead> </thead>
<tbody className="divide-y divide-border"> <tbody className="divide-y divide-border">
{userAccessTokens.map((userAccessToken) => ( {userAccessTokens.map((userAccessToken) => (
<tr key={userAccessToken.accessToken}> <tr key={userAccessToken.name}>
<td className="whitespace-nowrap px-3 py-2 text-sm text-foreground flex flex-row justify-start items-center gap-x-1"> <td className="whitespace-nowrap px-3 py-2 text-sm text-foreground flex flex-row justify-start items-center gap-x-1">
<span className="font-mono">{getFormatedAccessToken(userAccessToken.accessToken)}</span> <span className="font-mono">{getFormatedAccessToken(userAccessToken.accessToken)}</span>
<Button variant="ghost" onClick={() => copyAccessToken(userAccessToken.accessToken)}> <Button variant="ghost" onClick={() => copyAccessToken(userAccessToken.accessToken)}>

Loading…
Cancel
Save