Skip to content

Commit e360be1

Browse files
Vann-DevKaito
andauthored
feat(settings): add company token copy action (#72)
Co-authored-by: Kaito <kaito@agentbridge.local>
1 parent 0af9b75 commit e360be1

1 file changed

Lines changed: 57 additions & 4 deletions

File tree

apps/web/app/dashboard/settings/company-settings-form.tsx

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export function CompanySettingsForm({ company }: CompanySettingsFormProps) {
3838
const router = useRouter()
3939
const queryClient = useQueryClient()
4040
const [deleteConfirmation, setDeleteConfirmation] = useState("")
41+
const [copyStatus, setCopyStatus] = useState<"idle" | "copied" | "error">("idle")
4142
const updateMutation = useMutation({
4243
mutationFn: (payload: { name: string; description: string }) =>
4344
updateCompanyAction(company.id, payload).then((result) => {
@@ -76,8 +77,37 @@ export function CompanySettingsForm({ company }: CompanySettingsFormProps) {
7677

7778
return result
7879
}),
80+
onSuccess: () => {
81+
setCopyStatus("idle")
82+
},
7983
})
8084

85+
async function copyToken(token: string) {
86+
try {
87+
if (navigator.clipboard?.writeText) {
88+
await navigator.clipboard.writeText(token)
89+
} else {
90+
const textArea = document.createElement("textarea")
91+
textArea.value = token
92+
textArea.setAttribute("readonly", "")
93+
textArea.style.position = "fixed"
94+
textArea.style.opacity = "0"
95+
document.body.appendChild(textArea)
96+
textArea.select()
97+
const copied = document.execCommand("copy")
98+
document.body.removeChild(textArea)
99+
100+
if (!copied) {
101+
throw new Error("Copy command failed")
102+
}
103+
}
104+
105+
setCopyStatus("copied")
106+
} catch {
107+
setCopyStatus("error")
108+
}
109+
}
110+
81111
function updateCompany(formData: FormData) {
82112
updateMutation.mutate({
83113
name: String(formData.get("name") ?? ""),
@@ -130,10 +160,33 @@ export function CompanySettingsForm({ company }: CompanySettingsFormProps) {
130160
</p>
131161
{tokenMutation.data?.token ? (
132162
<div className="mt-4 rounded-2xl border border-border bg-muted p-3">
133-
<p className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">
134-
New company bearer token · copy now
135-
</p>
136-
<p className="mt-2 break-all font-mono text-xs">{tokenMutation.data.token}</p>
163+
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
164+
<div>
165+
<p className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">
166+
New company bearer token · copy now
167+
</p>
168+
<p className="mt-2 break-all font-mono text-xs">{tokenMutation.data.token}</p>
169+
</div>
170+
<Button
171+
className="shrink-0"
172+
size="sm"
173+
type="button"
174+
variant="secondary"
175+
onClick={() => copyToken(tokenMutation.data.token)}
176+
>
177+
{copyStatus === "copied" ? "Copied" : "Copy token"}
178+
</Button>
179+
</div>
180+
{copyStatus === "copied" ? (
181+
<p className="mt-2 text-xs font-medium text-emerald-700 dark:text-emerald-300">
182+
Token copied to clipboard.
183+
</p>
184+
) : null}
185+
{copyStatus === "error" ? (
186+
<p className="mt-2 text-xs font-medium text-destructive">
187+
Could not copy automatically. Select and copy the token manually.
188+
</p>
189+
) : null}
137190
<p className="mt-2 text-xs text-muted-foreground">
138191
This token cannot be viewed again. Update `.openclaw/agentbridge/.env` or any other
139192
external agent configuration that uses the old token.

0 commit comments

Comments
 (0)