diff --git a/ee/tabby-ui/app/(dashboard)/page.tsx b/ee/tabby-ui/app/(dashboard)/page.tsx
index 00c7ff3..fdd777a 100644
--- a/ee/tabby-ui/app/(dashboard)/page.tsx
+++ b/ee/tabby-ui/app/(dashboard)/page.tsx
@@ -19,17 +19,21 @@ import { WorkerKind } from '@/lib/gql/generates/graphql'
import { CopyButton } from '@/components/copy-button'
import { graphql } from '@/lib/gql/generates'
import { useGraphQLQuery } from '@/lib/tabby/gql'
+import { useSession } from '@/lib/tabby/auth'
const COMMUNITY_DIALOG_SHOWN_KEY = 'community-dialog-shown'
export default function Home() {
+ const { status } = useSession()
const [open, setOpen] = useState(false)
useEffect(() => {
+ if (status !== 'authenticated') return
+
if (!localStorage.getItem(COMMUNITY_DIALOG_SHOWN_KEY)) {
setOpen(true)
localStorage.setItem(COMMUNITY_DIALOG_SHOWN_KEY, 'true')
}
- }, [])
+ }, [status])
return (
diff --git a/ee/tabby-ui/app/auth/components/signup.tsx b/ee/tabby-ui/app/auth/components/signup.tsx
deleted file mode 100644
index d8ab4e6..0000000
--- a/ee/tabby-ui/app/auth/components/signup.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-'use client'
-
-import { graphql } from '@/lib/gql/generates'
-import { UserAuthForm } from './user-auth-form'
-import { useSearchParams } from 'next/navigation'
-import { useGraphQLQuery } from '@/lib/tabby/gql'
-
-export const getIsAdminInitialized = graphql(/* GraphQL */ `
- query GetIsAdminInitialized {
- isAdminInitialized
- }
-`)
-
-export default function Signup() {
- const { data } = useGraphQLQuery(getIsAdminInitialized)
- const title = data?.isAdminInitialized
- ? 'Create an account'
- : 'Create an admin account'
-
- const searchParams = useSearchParams()
- const invitationCode = searchParams.get('invitationCode') || undefined
-
- return (
-
-
-
{title}
-
- Fill form below to create your account
-
-
-
-
- )
-}
diff --git a/ee/tabby-ui/app/auth/layout.tsx b/ee/tabby-ui/app/auth/layout.tsx
new file mode 100644
index 0000000..e8cae81
--- /dev/null
+++ b/ee/tabby-ui/app/auth/layout.tsx
@@ -0,0 +1,11 @@
+export default function RootLayout({
+ children
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+ {children}
+
+ )
+}
diff --git a/ee/tabby-ui/app/auth/page.tsx b/ee/tabby-ui/app/auth/page.tsx
deleted file mode 100644
index f6a9db4..0000000
--- a/ee/tabby-ui/app/auth/page.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Metadata } from 'next'
-
-import Signup from './components/signup'
-
-export const metadata: Metadata = {
- title: 'Authentication',
- description: 'Authentication forms built using the components.'
-}
-
-export default function AuthenticationPage() {
- return (
-
-
-
- )
-}
diff --git a/ee/tabby-ui/app/auth/signin/components/signin.tsx b/ee/tabby-ui/app/auth/signin/components/signin.tsx
new file mode 100644
index 0000000..1fc0929
--- /dev/null
+++ b/ee/tabby-ui/app/auth/signin/components/signin.tsx
@@ -0,0 +1,17 @@
+'use client'
+
+import UserSignInForm from './user-signin-form'
+
+export default function Signin() {
+ return (
+
+
+
Sign In
+
+ Enter credentials to login to your account
+
+
+
+
+ )
+}
diff --git a/ee/tabby-ui/app/auth/signin/components/user-signin-form.tsx b/ee/tabby-ui/app/auth/signin/components/user-signin-form.tsx
new file mode 100644
index 0000000..fb85323
--- /dev/null
+++ b/ee/tabby-ui/app/auth/signin/components/user-signin-form.tsx
@@ -0,0 +1,113 @@
+'use client'
+
+import * as React from 'react'
+
+import { zodResolver } from '@hookform/resolvers/zod'
+import { useForm } from 'react-hook-form'
+import * as z from 'zod'
+
+import { cn } from '@/lib/utils'
+import { IconSpinner } from '@/components/ui/icons'
+import { Button } from '@/components/ui/button'
+import { Input } from '@/components/ui/input'
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage
+} from '@/components/ui/form'
+import { graphql } from '@/lib/gql/generates'
+import { useGraphQLForm } from '@/lib/tabby/gql'
+import { useSignIn } from '@/lib/tabby/auth'
+import { useRouter } from 'next/navigation'
+
+export const tokenAuth = graphql(/* GraphQL */ `
+ mutation tokenAuth($email: String!, $password: String!) {
+ tokenAuth(email: $email, password: $password) {
+ accessToken
+ refreshToken
+ }
+ }
+`)
+
+const formSchema = z.object({
+ email: z.string().email('Invalid email address'),
+ password: z.string()
+})
+
+interface UserAuthFormProps extends React.HTMLAttributes
{
+ invitationCode?: string
+}
+
+export default function UserSignInForm({
+ className,
+ invitationCode,
+ ...props
+}: UserAuthFormProps) {
+ const form = useForm>({
+ resolver: zodResolver(formSchema)
+ })
+
+ const router = useRouter()
+ const signIn = useSignIn()
+ const { isSubmitting } = form.formState
+ const { onSubmit } = useGraphQLForm(tokenAuth, {
+ onSuccess: async values => {
+ if (await signIn(values.tokenAuth)) {
+ router.replace('/')
+ }
+ },
+ onError: (path, message) => form.setError(path as any, { message })
+ })
+
+ return (
+
+
+
+
+
+ )
+}
diff --git a/ee/tabby-ui/app/auth/signin/page.tsx b/ee/tabby-ui/app/auth/signin/page.tsx
new file mode 100644
index 0000000..07806cf
--- /dev/null
+++ b/ee/tabby-ui/app/auth/signin/page.tsx
@@ -0,0 +1,10 @@
+import { Metadata } from 'next'
+import Signin from './components/signin'
+
+export const metadata: Metadata = {
+ title: 'Sign In'
+}
+
+export default function Page() {
+ return
+}
diff --git a/ee/tabby-ui/app/auth/signup/components/signup.tsx b/ee/tabby-ui/app/auth/signup/components/signup.tsx
new file mode 100644
index 0000000..4b53c70
--- /dev/null
+++ b/ee/tabby-ui/app/auth/signup/components/signup.tsx
@@ -0,0 +1,50 @@
+'use client'
+
+import { UserAuthForm } from './user-register-form'
+import { useSearchParams } from 'next/navigation'
+
+export default function Signup() {
+ const searchParams = useSearchParams()
+ const invitationCode = searchParams.get('invitationCode') || undefined
+ const isAdmin = searchParams.get('isAdmin') || false
+
+ const title = isAdmin ? 'Create an admin account' : 'Create an account'
+
+ const description = isAdmin
+ ? 'The admin account has access to invite collaborators and manage Tabby configuration'
+ : 'Fill form below to create your account'
+
+ if (isAdmin || invitationCode) {
+ return
+ } else {
+ return (
+
+ )
+ }
+}
+
+function Content({
+ title,
+ description,
+ show
+}: {
+ title: string
+ description: string
+ show?: boolean
+}) {
+ const searchParams = useSearchParams()
+ const invitationCode = searchParams.get('invitationCode') || undefined
+
+ return (
+
+
+
{title}
+
{description}
+
+ {show &&
}
+
+ )
+}
diff --git a/ee/tabby-ui/app/auth/components/user-auth-form.tsx b/ee/tabby-ui/app/auth/signup/components/user-register-form.tsx
similarity index 90%
rename from ee/tabby-ui/app/auth/components/user-auth-form.tsx
rename to ee/tabby-ui/app/auth/signup/components/user-register-form.tsx
index 378add8..1eba9c5 100644
--- a/ee/tabby-ui/app/auth/components/user-auth-form.tsx
+++ b/ee/tabby-ui/app/auth/signup/components/user-register-form.tsx
@@ -20,6 +20,8 @@ import {
} from '@/components/ui/form'
import { graphql } from '@/lib/gql/generates'
import { useGraphQLForm } from '@/lib/tabby/gql'
+import { useSignIn } from '@/lib/tabby/auth'
+import { useRouter } from 'next/navigation'
export const registerUser = graphql(/* GraphQL */ `
mutation register(
@@ -59,15 +61,19 @@ export function UserAuthForm({
const form = useForm>({
resolver: zodResolver(formSchema),
defaultValues: {
- email: '',
- password1: '',
- password2: '',
invitationCode
}
})
+ const router = useRouter()
+ const signIn = useSignIn()
const { isSubmitting } = form.formState
const { onSubmit } = useGraphQLForm(registerUser, {
+ onSuccess: async values => {
+ if (await signIn(values.register)) {
+ router.replace('/')
+ }
+ },
onError: (path, message) => form.setError(path as any, { message })
})
@@ -125,14 +131,14 @@ export function UserAuthForm({
control={form.control}
name="invitationCode"
render={({ field }) => (
-
+
)}
/>
-