feat(tabby-ui): support user auth token reset (#1003)
parent
03c418340a
commit
ae4dc5f8d0
|
|
@ -6,7 +6,8 @@ import { useHealth } from '@/lib/hooks/use-health'
|
||||||
import { useWorkers } from '@/lib/hooks/use-workers'
|
import { useWorkers } from '@/lib/hooks/use-workers'
|
||||||
import { useAuthenticatedGraphQLQuery, useGraphQLForm } from '@/lib/tabby/gql'
|
import { useAuthenticatedGraphQLQuery, useGraphQLForm } from '@/lib/tabby/gql'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { IconRefresh } from '@/components/ui/icons'
|
import { IconRotate } from '@/components/ui/icons'
|
||||||
|
import { Input } from '@/components/ui/input'
|
||||||
import { Separator } from '@/components/ui/separator'
|
import { Separator } from '@/components/ui/separator'
|
||||||
import { CopyButton } from '@/components/copy-button'
|
import { CopyButton } from '@/components/copy-button'
|
||||||
|
|
||||||
|
|
@ -66,16 +67,17 @@ export default function Workers() {
|
||||||
{!!registrationTokenRes?.registrationToken && (
|
{!!registrationTokenRes?.registrationToken && (
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
Registration token:
|
Registration token:
|
||||||
<code className="rounded-lg text-sm text-red-600">
|
<Input
|
||||||
{registrationTokenRes.registrationToken}
|
className="max-w-[320px] font-mono text-red-600"
|
||||||
</code>
|
value={registrationTokenRes.registrationToken}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
title="Reset"
|
title="Rotate"
|
||||||
size="icon"
|
size="icon"
|
||||||
variant="hover-destructive"
|
variant="hover-destructive"
|
||||||
onClick={() => resetRegistrationToken()}
|
onClick={() => resetRegistrationToken()}
|
||||||
>
|
>
|
||||||
<IconRefresh />
|
<IconRotate />
|
||||||
</Button>
|
</Button>
|
||||||
<CopyButton value={registrationTokenRes.registrationToken} />
|
<CopyButton value={registrationTokenRes.registrationToken} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,17 @@ import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { graphql } from '@/lib/gql/generates'
|
import { graphql } from '@/lib/gql/generates'
|
||||||
import { useHealth } from '@/lib/hooks/use-health'
|
import { useHealth } from '@/lib/hooks/use-health'
|
||||||
import { useAuthenticatedGraphQLQuery } from '@/lib/tabby/gql'
|
import { useAuthenticatedGraphQLQuery, useGraphQLForm } from '@/lib/tabby/gql'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
import {
|
import {
|
||||||
CardContent,
|
CardContent,
|
||||||
CardFooter,
|
CardFooter,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle
|
CardTitle
|
||||||
} from '@/components/ui/card'
|
} from '@/components/ui/card'
|
||||||
|
import { IconRotate } from '@/components/ui/icons'
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
|
import { Label } from '@/components/ui/label'
|
||||||
import { CopyButton } from '@/components/copy-button'
|
import { CopyButton } from '@/components/copy-button'
|
||||||
import SlackDialog from '@/components/slack-dialog'
|
import SlackDialog from '@/components/slack-dialog'
|
||||||
|
|
||||||
|
|
@ -32,14 +35,27 @@ const meQuery = graphql(/* GraphQL */ `
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
const resetUserAuthTokenDocument = graphql(/* GraphQL */ `
|
||||||
|
mutation ResetUserAuthToken {
|
||||||
|
resetUserAuthToken
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
function MainPanel() {
|
function MainPanel() {
|
||||||
const { data: healthInfo } = useHealth()
|
const { data: healthInfo } = useHealth()
|
||||||
const { data } = useAuthenticatedGraphQLQuery(meQuery)
|
const { data, mutate } = useAuthenticatedGraphQLQuery(meQuery)
|
||||||
const [origin, setOrigin] = useState('')
|
const [origin, setOrigin] = useState('')
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setOrigin(new URL(window.location.href).origin)
|
setOrigin(new URL(window.location.href).origin)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const { onSubmit: resetUserAuthToken } = useGraphQLForm(
|
||||||
|
resetUserAuthTokenDocument,
|
||||||
|
{
|
||||||
|
onSuccess: () => mutate()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if (!healthInfo || !data) return
|
if (!healthInfo || !data) return
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -47,21 +63,28 @@ function MainPanel() {
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Getting Started</CardTitle>
|
<CardTitle>Getting Started</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="flex max-w-[420px] flex-col gap-2">
|
<CardContent className="flex flex-col gap-4">
|
||||||
<span className="flex items-center justify-between gap-2">
|
<Label>Endpoint URL</Label>
|
||||||
<span>Endpoint URL</span>
|
<span className="flex items-center gap-1">
|
||||||
<span className="flex items-center">
|
<Input value={origin} className="max-w-[320px]" />
|
||||||
<Input value={origin} />
|
<CopyButton value={origin} />
|
||||||
<CopyButton value={origin} />
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span className="flex items-center justify-between gap-2">
|
<Label>Token</Label>
|
||||||
<span>Token</span>
|
<span className="flex items-center gap-1">
|
||||||
<span className="flex items-center">
|
<Input
|
||||||
<Input value={data.me.authToken} />
|
className="max-w-[320px] font-mono text-red-600"
|
||||||
<CopyButton value={data.me.authToken} />
|
value={data.me.authToken}
|
||||||
</span>
|
/>
|
||||||
|
<Button
|
||||||
|
title="Rotate"
|
||||||
|
size="icon"
|
||||||
|
variant="hover-destructive"
|
||||||
|
onClick={() => resetUserAuthToken()}
|
||||||
|
>
|
||||||
|
<IconRotate />
|
||||||
|
</Button>
|
||||||
|
<CopyButton value={data.me.authToken} />
|
||||||
</span>
|
</span>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardFooter>
|
<CardFooter>
|
||||||
|
|
|
||||||
|
|
@ -660,6 +660,27 @@ function IconNetwork({ className, ...props }: React.ComponentProps<'svg'>) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function IconRotate({ className, ...props }: React.ComponentProps<'svg'>) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
className={cn('h-4 w-4', className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
|
||||||
|
<path d="M3 3v5h5" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
IconEdit,
|
IconEdit,
|
||||||
IconNextChat,
|
IconNextChat,
|
||||||
|
|
@ -694,5 +715,6 @@ export {
|
||||||
IconLogout,
|
IconLogout,
|
||||||
IconUnlock,
|
IconUnlock,
|
||||||
IconHome,
|
IconHome,
|
||||||
IconNetwork
|
IconNetwork,
|
||||||
|
IconRotate
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue