From 0dbc35a2ba9518bc33c3cd47d3fb0a5d6ee67abe Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 2 Feb 2026 20:31:22 +0800 Subject: [PATCH] fix: restore access token creation flow Fixes #5563 --- .../components/CreateAccessTokenDialog.tsx | 108 ++++++++++++------ .../Settings/AccessTokenSection.tsx | 22 +++- 2 files changed, 93 insertions(+), 37 deletions(-) diff --git a/web/src/components/CreateAccessTokenDialog.tsx b/web/src/components/CreateAccessTokenDialog.tsx index 4b23dff3c..845df571b 100644 --- a/web/src/components/CreateAccessTokenDialog.tsx +++ b/web/src/components/CreateAccessTokenDialog.tsx @@ -1,10 +1,12 @@ -import React, { useState } from "react"; +import copy from "copy-to-clipboard"; +import React, { useEffect, useState } from "react"; import { toast } from "react-hot-toast"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import { Textarea } from "@/components/ui/textarea"; import { userServiceClient } from "@/connect"; import useCurrentUser from "@/hooks/useCurrentUser"; import useLoading from "@/hooks/useLoading"; @@ -30,6 +32,7 @@ function CreateAccessTokenDialog({ open, onOpenChange, onSuccess }: Props) { description: "", expiration: 30, // Default: 30 days }); + const [createdToken, setCreatedToken] = useState(null); const requestState = useLoading(false); // Expiration options in days (0 = never expires) @@ -83,7 +86,11 @@ function CreateAccessTokenDialog({ open, onOpenChange, onSuccess }: Props) { requestState.setFinish(); onSuccess(response); - onOpenChange(false); + if (response.token) { + setCreatedToken(response.token); + } else { + onOpenChange(false); + } } catch (error: unknown) { handleError(error, toast.error, { context: "Create access token", @@ -92,46 +99,81 @@ function CreateAccessTokenDialog({ open, onOpenChange, onSuccess }: Props) { } }; + const handleCopyToken = () => { + if (!createdToken) return; + copy(createdToken); + toast.success(t("message.copied")); + }; + + useEffect(() => { + if (!open) return; + setState({ + description: "", + expiration: 30, + }); + setCreatedToken(null); + }, [open]); + return ( {t("setting.access-token-section.create-dialog.create-access-token")} -
-
- - + {createdToken ? ( +
+
+ +