From 2615fbfc1b34db050b440a5de20c13e8253c8811 Mon Sep 17 00:00:00 2001 From: aliang <1098486429@qq.com> Date: Fri, 26 Apr 2024 06:34:17 +0800 Subject: [PATCH] refactor(ui): simplify implementation of github provider using PAT (#1963) * refactor(ui): implify implementation of github provider using PAT * update * remove useless component * format * [autofix.ci] apply automated fixes * justify size * [autofix.ci] apply automated fixes * restructure-repository-providers * consolidate layouts * adjust ux * update ux * fix spacing * update * fix ui * update * update * update --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Meng Zhang --- .../app/(dashboard)/components/sidebar.tsx | 13 +- .../(integrations)/git/components/header.tsx | 13 - .../settings/(integrations)/git/page.tsx | 11 - .../gitops/components/basic-info-form.tsx | 101 -------- .../gitops/components/header.tsx | 13 - .../components/oauth-application-form.tsx | 101 -------- .../components/provider-detail-form.tsx | 243 ------------------ .../gitops/new/components/confirm-view.tsx | 63 ----- .../gitops/new/components/new-page.tsx | 194 -------------- .../settings/(integrations)/gitops/page.tsx | 11 - .../repository/components/tabs-header.tsx | 30 +++ .../git/components/git.tsx} | 6 +- .../git/components/repository-table.tsx | 0 .../components/create-repository-form.tsx | 16 +- .../git/new/components/new-page.tsx | 6 +- .../{ => repository}/git/new/page.tsx | 6 - .../(integrations)/repository/git/page.tsx | 5 + .../github/components/github-form.tsx | 156 +++++++++++ .../github/components/github.tsx} | 31 +-- .../github}/detail/components/detail.tsx | 144 +++++------ .../detail/components/new-repository-form.tsx | 22 +- .../components/provider-detail-form.tsx | 168 ++++++++++++ .../github}/detail/page.tsx | 6 - .../github}/detail/query.ts | 0 .../github/new/components/new-page.tsx | 87 +++++++ .../github}/new/page.tsx | 6 - .../(integrations)/repository/github/page.tsx | 5 + .../(integrations)/repository/layout.tsx | 31 +++ .../sso/components/oauth-credential-list.tsx | 6 +- ee/tabby-ui/components/steps/steps.css | 24 -- ee/tabby-ui/components/steps/steps.tsx | 161 ------------ ee/tabby-ui/lib/popup-window-management.ts | 125 --------- ee/tabby-ui/lib/tabby/gql.ts | 6 +- ee/tabby-ui/lib/tabby/query.ts | 1 - 34 files changed, 589 insertions(+), 1222 deletions(-) delete mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/header.tsx delete mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/page.tsx delete mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/basic-info-form.tsx delete mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/header.tsx delete mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/oauth-application-form.tsx delete mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/components/provider-detail-form.tsx delete mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/components/confirm-view.tsx delete mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/components/new-page.tsx delete mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/page.tsx create mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/components/tabs-header.tsx rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{git/components/repository.tsx => repository/git/components/git.tsx} (62%) rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{ => repository}/git/components/repository-table.tsx (100%) rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{git => repository/git/new}/components/create-repository-form.tsx (90%) rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{ => repository}/git/new/components/new-page.tsx (55%) rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{ => repository}/git/new/page.tsx (55%) create mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/page.tsx create mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/components/github-form.tsx rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{gitops/components/git-privoders-page.tsx => repository/github/components/github.tsx} (70%) rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{gitops => repository/github}/detail/components/detail.tsx (65%) rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{gitops => repository/github}/detail/components/new-repository-form.tsx (88%) create mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/components/provider-detail-form.tsx rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{gitops => repository/github}/detail/page.tsx (55%) rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{gitops => repository/github}/detail/query.ts (100%) create mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/new/components/new-page.tsx rename ee/tabby-ui/app/(dashboard)/settings/(integrations)/{gitops => repository/github}/new/page.tsx (55%) create mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/page.tsx create mode 100644 ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/layout.tsx delete mode 100644 ee/tabby-ui/components/steps/steps.css delete mode 100644 ee/tabby-ui/components/steps/steps.tsx delete mode 100644 ee/tabby-ui/lib/popup-window-management.ts diff --git a/ee/tabby-ui/app/(dashboard)/components/sidebar.tsx b/ee/tabby-ui/app/(dashboard)/components/sidebar.tsx index bb33237b4266..25e136d728a1 100644 --- a/ee/tabby-ui/app/(dashboard)/components/sidebar.tsx +++ b/ee/tabby-ui/app/(dashboard)/components/sidebar.tsx @@ -94,8 +94,8 @@ export default function Sidebar({ children, className }: SidebarProps) { } > - - Git Providers + + Repository Providers SSO @@ -135,9 +135,12 @@ const linkVariants = cva( function SidebarButton({ href, children }: SidebarButtonProps) { const pathname = usePathname() const isSelected = React.useMemo(() => { - return href === '/' - ? href === pathname - : shouldPathnameHighlight(pathname, href) + if (href === '/') return href === pathname + if (href.startsWith('/settings/repository/github')) { + return pathname.startsWith('/settings/repository/') + } + + return shouldPathnameHighlight(pathname, href) }, [pathname, href]) const state = isSelected ? 'selected' : 'not-selected' diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/header.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/header.tsx deleted file mode 100644 index 64277a8a0ccc..000000000000 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/header.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { SubHeader } from '@/components/sub-header' - -export const RepositoryHeader = ({ className }: { className?: string }) => { - return ( - - Connect to Git repositories and uses these repositories as a context to - enhance performance of large language model. - - ) -} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/page.tsx deleted file mode 100644 index 83ccaa12b3e5..000000000000 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Metadata } from 'next' - -import Repository from './components/repository' - -export const metadata: Metadata = { - title: 'Git Providers' -} - -export default function IndexPage() { - return -} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/basic-info-form.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/basic-info-form.tsx deleted file mode 100644 index d89f1a8331c0..000000000000 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/basic-info-form.tsx +++ /dev/null @@ -1,101 +0,0 @@ -'use client' - -import * as React from 'react' -import { UseFormReturn } from 'react-hook-form' -import * as z from 'zod' - -import { cn } from '@/lib/utils' -import { - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage -} from '@/components/ui/form' -import { IconGitHub } from '@/components/ui/icons' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' -import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group' - -export const basicInfoFormSchema = z.object({ - displayName: z - .string() - .trim() - .regex( - /^[\w-]+$/, - 'Display name must contain only alphanumeric characters, underscores, and hyphens' - ), - provider: z.string() -}) - -export type BasicInfoFormValues = z.infer - -interface BasicInfoFormProps extends React.HTMLAttributes { - form: UseFormReturn - isUpdate?: boolean -} - -export const BasicInfoForm = React.forwardRef< - HTMLDivElement, - BasicInfoFormProps ->(({ className, form, isUpdate, ...rest }, ref) => { - return ( -
- ( - - Choose Git provider - - -
- - -
-
-
- -
- )} - /> - ( - - Display name - - A display name to help identifying among different configs using - the same Git provider. - - - - - - - )} - /> -
- ) -}) - -BasicInfoForm.displayName = 'BasicInfoForm' diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/header.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/header.tsx deleted file mode 100644 index 64277a8a0ccc..000000000000 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/header.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { SubHeader } from '@/components/sub-header' - -export const RepositoryHeader = ({ className }: { className?: string }) => { - return ( - - Connect to Git repositories and uses these repositories as a context to - enhance performance of large language model. - - ) -} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/oauth-application-form.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/oauth-application-form.tsx deleted file mode 100644 index 70d9a105bbb2..000000000000 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/oauth-application-form.tsx +++ /dev/null @@ -1,101 +0,0 @@ -'use client' - -import React from 'react' -import type { UseFormReturn } from 'react-hook-form' -import * as z from 'zod' - -import { useExternalURL } from '@/lib/hooks/use-network-setting' -import { cn } from '@/lib/utils' -import { - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage -} from '@/components/ui/form' -import { Input } from '@/components/ui/input' -import { CopyButton } from '@/components/copy-button' - -export const oauthInfoFormSchema = z.object({ - applicationId: z.string(), - secret: z.string() -}) - -export type OAuthApplicationFormValues = z.infer - -interface OAuthApplicationFormProps - extends React.HTMLAttributes { - form: UseFormReturn -} - -export const OAuthApplicationForm = React.forwardRef< - HTMLDivElement, - OAuthApplicationFormProps ->(({ className, form }, ref) => { - const externalURL = useExternalURL() - const integrationsCallbackURL = externalURL - ? `${externalURL}/integrations/github/callback` - : '' - - return ( -
- {!!integrationsCallbackURL && ( - -
-
- Create your OAuth2 application with the following information -
-
-
- Authorization callback URL -
- - {integrationsCallbackURL} - - -
-
-
- )} - ( - - Application ID - - - - - - )} - /> - ( - - Application secret - - - - - - )} - /> -
- ) -}) - -OAuthApplicationForm.displayName = 'OAuthApplicationForm' diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/components/provider-detail-form.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/components/provider-detail-form.tsx deleted file mode 100644 index 82311d539b2e..000000000000 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/components/provider-detail-form.tsx +++ /dev/null @@ -1,243 +0,0 @@ -'use client' - -import React from 'react' -import { zodResolver } from '@hookform/resolvers/zod' -import { isEmpty, trim } from 'lodash-es' -import { useForm } from 'react-hook-form' -import { toast } from 'sonner' -import * as z from 'zod' - -import { graphql } from '@/lib/gql/generates' -import { useMutation } from '@/lib/tabby/gql' -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger -} from '@/components/ui/alert-dialog' -import { Button, buttonVariants } from '@/components/ui/button' -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage -} from '@/components/ui/form' -import { IconSpinner } from '@/components/ui/icons' -import { Input } from '@/components/ui/input' - -const deleteGithubRepositoryProviderMutation = graphql(/* GraphQL */ ` - mutation DeleteGithubRepositoryProvider($id: ID!) { - deleteGithubRepositoryProvider(id: $id) - } -`) - -const updateGithubRepositoryProviderMutation = graphql(/* GraphQL */ ` - mutation UpdateGithubRepositoryProvider( - $input: UpdateGithubRepositoryProviderInput! - ) { - updateGithubRepositoryProvider(input: $input) - } -`) - -export const formSchema = z.object({ - applicationId: z.string(), - displayName: z - .string() - .trim() - .regex( - /^[\w-]+$/, - 'Display name must contain only alphanumeric characters, underscores, and hyphens' - ), - secret: z.string().optional() -}) - -type FormValues = z.infer - -interface UpdateProviderFormProps { - id: string - defaultValues?: Partial - onSuccess?: () => void - onDelete: () => void - onBack: () => void -} - -export const UpdateProviderForm: React.FC = ({ - defaultValues, - onSuccess, - onDelete, - onBack, - id -}) => { - const [deleteAlertVisible, setDeleteAlertVisible] = React.useState(false) - const [isDeleting, setIsDeleting] = React.useState(false) - const form = useForm({ - resolver: zodResolver(formSchema), - defaultValues - }) - - const deleteGithubRepositoryProvider = useMutation( - deleteGithubRepositoryProviderMutation - ) - - const isDirty = !isEmpty(form.formState.dirtyFields) - - const updateGithubRepositoryProvider = useMutation( - updateGithubRepositoryProviderMutation, - { - form, - onCompleted(values) { - if (values?.updateGithubRepositoryProvider) { - toast.success('Updated repository provider successfully') - form.reset(form.getValues()) - onSuccess?.() - } - } - } - ) - - const onSubmit = async (values: FormValues) => { - await updateGithubRepositoryProvider({ - input: { - id, - ...values, - secret: trim(values.secret) || undefined - } - }) - } - - const handleDeleteRepositoryProvider: React.MouseEventHandler< - HTMLButtonElement - > = async e => { - e.preventDefault() - setIsDeleting(true) - try { - const res = await deleteGithubRepositoryProvider({ id }) - if (res?.data?.deleteGithubRepositoryProvider) { - toast.success('Deleted repository provider successfully') - onDelete?.() - } else { - toast.error( - res?.error?.message || 'Failed to delete repository provider' - ) - } - } catch (error) { - toast.error('Failed to delete repository provider') - } finally { - setIsDeleting(false) - } - } - - return ( -
-
- - ( - - Name - - - - - - )} - /> - ( - - Application ID - - - - - - )} - /> - ( - - Application secret - - - - - - )} - /> -
-
- - - - - - - - Are you absolutely sure? - - - This will delete the provider and remove any repositories - that have already been added to the provider. - - - - Cancel - - {isDeleting && ( - - )} - Yes, delete it - - - - - -
-
- - -
- - ) -} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/components/confirm-view.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/components/confirm-view.tsx deleted file mode 100644 index 8e7c5e49386a..000000000000 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/components/confirm-view.tsx +++ /dev/null @@ -1,63 +0,0 @@ -'use client' - -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle -} from '@/components/ui/card' -import { IconGitHub } from '@/components/ui/icons' -import { Separator } from '@/components/ui/separator' - -import { BasicInfoFormValues } from '../../components/basic-info-form' -import { OAuthApplicationFormValues } from '../../components/oauth-application-form' - -interface ConfirmViewProps { - data: BasicInfoFormValues & OAuthApplicationFormValues -} - -export default function ConfirmView({ data }: ConfirmViewProps) { - return ( -
- - - Confirm the info - - After creation, this Git provider can be chosen under Gitops - - - - - -
- - GitHub.com -
-
- - {data.displayName} - - {data.applicationId} - - {data.secret} -
-
-
- ) -} - -function InfoItem({ - title, - children -}: { - title: string - children: React.ReactNode -}) { - return ( -
-
{title}
-
{children}
-
- ) -} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/components/new-page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/components/new-page.tsx deleted file mode 100644 index 9b539d3ad41a..000000000000 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/components/new-page.tsx +++ /dev/null @@ -1,194 +0,0 @@ -'use client' - -import { useRef, useState } from 'react' -import { useRouter } from 'next/navigation' -import { zodResolver } from '@hookform/resolvers/zod' -import { createRequest } from '@urql/core' -import { omit } from 'lodash-es' -import { useForm, UseFormReturn } from 'react-hook-form' -import { toast } from 'sonner' -import * as z from 'zod' - -import { graphql } from '@/lib/gql/generates' -import { usePopupWindow } from '@/lib/popup-window-management' -import { client, useMutation } from '@/lib/tabby/gql' -import { listGithubRepositoryProviders } from '@/lib/tabby/query' -import { getAuthToken } from '@/lib/tabby/token-management' -import { Button } from '@/components/ui/button' -import { Form } from '@/components/ui/form' -import { IconSpinner } from '@/components/ui/icons' -import { StepItem, Steps, useSteps } from '@/components/steps/steps' - -import { - BasicInfoForm, - basicInfoFormSchema, - type BasicInfoFormValues -} from '../../components/basic-info-form' -import { RepositoryHeader } from '../../components/header' -import { - OAuthApplicationForm, - oauthInfoFormSchema, - type OAuthApplicationFormValues -} from '../../components/oauth-application-form' -import ConfirmView from '../components/confirm-view' - -const createGithubRepositoryProvider = graphql(/* GraphQL */ ` - mutation CreateGithubRepositoryProvider( - $input: CreateGithubRepositoryProviderInput! - ) { - createGithubRepositoryProvider(input: $input) - } -`) - -export const NewProvider = () => { - const router = useRouter() - const schemas = [basicInfoFormSchema, oauthInfoFormSchema, z.object({})] - - const stepState = useSteps({ - items: [ - { - title: 'Basic info' - }, - { - title: 'OAuth application info' - }, - { - title: 'Confirmation' - } - ] - }) - const { currentStep, setStep } = stepState - const form = useForm({ - resolver: zodResolver(schemas[currentStep]), - defaultValues: { - provider: 'github' - } - }) - const [errorMessage, setErrorMessage] = useState() - - const createdProviderId = useRef() - const { isSubmitting } = form.formState - - const getProvider = (id: string) => { - const queryProvider = client.createRequestOperation( - 'query', - createRequest(listGithubRepositoryProviders, { ids: [id] }) - ) - return client.executeQuery(queryProvider) - } - - const getPopupUrl = (id: string) => { - const accessToken = getAuthToken()?.accessToken - return `/integrations/github/connect/${id}?access_token=${accessToken}` - } - - const { open: openPopup } = usePopupWindow({ - async onMessage(data) { - if (data?.errorMessage) { - setErrorMessage(data.errorMessage) - } else { - const result = await getProvider(createdProviderId.current as string) - if ( - result?.data?.githubRepositoryProviders?.edges?.[0]?.node?.connected - ) { - toast.success('Provider Successfully Created') - router.replace('/settings/gitops') - } else { - setErrorMessage('Connection to GitHub failed, please try again') - } - } - } - }) - - const createGithubRepositoryProviderMutation = useMutation( - createGithubRepositoryProvider, - { - onCompleted(data) { - if (data?.createGithubRepositoryProvider) { - // store providerId - createdProviderId.current = data.createGithubRepositoryProvider - openPopup(getPopupUrl(data.createGithubRepositoryProvider)) - setErrorMessage(undefined) - } - }, - onError(err) { - toast.error(err?.message) - }, - form - } - ) - - const handleSubmit = async () => { - if (currentStep === 0) { - // basic info - setStep(currentStep + 1) - } else if (currentStep === 1) { - // oauth application info - setStep(currentStep + 1) - } else { - if (createdProviderId.current) { - openPopup(getPopupUrl(createdProviderId.current)) - setErrorMessage(undefined) - return - } - - const values = omit(form.getValues(), 'provider') - createGithubRepositoryProviderMutation({ - input: values - }) - } - } - - return ( - <> - - - {stepState.steps?.map((step, index) => { - return - })} - -
- - {currentStep === 0 && ( - } /> - )} - {currentStep === 1 && ( - } /> - )} - {currentStep === 2 && ( - <> - -
- {errorMessage} -
- - )} -
- -
- {currentStep > 0 && ( - - )} - -
-
- - - - ) -} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/page.tsx deleted file mode 100644 index 08f10332a566..000000000000 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Metadata } from 'next' - -import GitProvidersPage from './components/git-privoders-page' - -export const metadata: Metadata = { - title: 'Git Providers' -} - -export default function IndexPage() { - return -} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/components/tabs-header.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/components/tabs-header.tsx new file mode 100644 index 000000000000..18585b8e41c7 --- /dev/null +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/components/tabs-header.tsx @@ -0,0 +1,30 @@ +'use client' + +import Link from 'next/link' +import { usePathname } from 'next/navigation' + +import { IconGitHub } from '@/components/ui/icons' +import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs' + +export default function GitTabsHeader() { + const pathname = usePathname() + const defualtValue = pathname.indexOf('github') >= 0 ? 'github' : 'git' + + return ( + +
+ + + Git + + + + + GitHub + + + +
+
+ ) +} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/repository.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/components/git.tsx similarity index 62% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/repository.tsx rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/components/git.tsx index 636c5e60e179..29a7e35b4015 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/repository.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/components/git.tsx @@ -4,16 +4,14 @@ import Link from 'next/link' import { buttonVariants } from '@/components/ui/button' -import { RepositoryHeader } from './header' import RepositoryTable from './repository-table' -export default function Repository() { +export default function Git() { return ( <> -
- + Create
diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/repository-table.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/components/repository-table.tsx similarity index 100% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/repository-table.tsx rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/components/repository-table.tsx diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/create-repository-form.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/new/components/create-repository-form.tsx similarity index 90% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/create-repository-form.tsx rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/new/components/create-repository-form.tsx index 5ab8b953e47f..953b3a3acff7 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/components/create-repository-form.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/new/components/create-repository-form.tsx @@ -1,7 +1,7 @@ 'use client' import * as React from 'react' -import Link from 'next/link' +import { useRouter } from 'next/navigation' import { zodResolver } from '@hookform/resolvers/zod' import { useForm } from 'react-hook-form' import * as z from 'zod' @@ -48,6 +48,7 @@ export default function CreateRepositoryForm({ form }) + const router = useRouter() return (
@@ -93,11 +94,14 @@ export default function CreateRepositoryForm({ )} />
- - - + diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/new/components/new-page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/new/components/new-page.tsx similarity index 55% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/new/components/new-page.tsx rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/new/components/new-page.tsx index 88cb366003ff..6ac774d515bc 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/new/components/new-page.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/new/components/new-page.tsx @@ -2,19 +2,17 @@ import { useRouter } from 'next/navigation' -import RepositoryForm from '../../components/create-repository-form' -import { RepositoryHeader } from '../../components/header' +import RepositoryForm from './create-repository-form' export const NewRepository = () => { const router = useRouter() const onCreated = () => { - router.replace('/settings/git') + router.back() } return ( <> - ) diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/new/page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/new/page.tsx similarity index 55% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/new/page.tsx rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/new/page.tsx index eefd0fee06a1..b06ad0722e21 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/git/new/page.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/new/page.tsx @@ -1,11 +1,5 @@ -import { Metadata } from 'next' - import { NewRepository } from './components/new-page' -export const metadata: Metadata = { - title: 'New Repository' -} - export default function IndexPage() { return } diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/page.tsx new file mode 100644 index 000000000000..eb59397f42b7 --- /dev/null +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/git/page.tsx @@ -0,0 +1,5 @@ +import Git from './components/git' + +export default function Generic() { + return +} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/components/github-form.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/components/github-form.tsx new file mode 100644 index 000000000000..a2015493a17b --- /dev/null +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/components/github-form.tsx @@ -0,0 +1,156 @@ +'use client' + +import * as React from 'react' +import Link from 'next/link' +import { zodResolver } from '@hookform/resolvers/zod' +import { useForm, UseFormReturn } from 'react-hook-form' +import * as z from 'zod' + +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage +} from '@/components/ui/form' +import { IconExternalLink } from '@/components/ui/icons' +import { Input } from '@/components/ui/input' + +export const createGithubProviderSchema = z.object({ + displayName: z + .string() + .trim() + .regex( + /^[\w-]+$/, + 'Display name must contain only alphanumeric characters, underscores, and hyphens' + ), + accessToken: z.string() +}) + +export const updateGithubProviderSchema = createGithubProviderSchema.extend({}) + +export type CreateGithubProviderFormValues = z.infer< + typeof createGithubProviderSchema +> +export type UpdateGithubProviderFormValues = z.infer< + typeof updateGithubProviderSchema +> + +interface GithubProviderFormProps { + isNew?: boolean + defaultValues?: Partial> + footer: React.ReactNode + onSubmit: (values: any) => Promise +} + +export const GithubProviderForm = React.forwardRef< + { + form: UseFormReturn< + CreateGithubProviderFormValues | UpdateGithubProviderFormValues + > + }, + GithubProviderFormProps +>(({ isNew, defaultValues, footer, onSubmit }, ref) => { + const formSchema = isNew + ? createGithubProviderSchema + : updateGithubProviderSchema + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues + }) + + React.useImperativeHandle( + ref, + () => { + return { + form + } + }, + [form] + ) + + return ( + +
+ + ( + + Display name + + A display name to help identifying different providers. + + + + + + + )} + /> + ( + + Personal Access Token + +
+ Create a dedicated service user and generate a{' '} + + fine-grained personal access + {' '} + token with the member role for the organization or all + projects to be managed. +
+
• Contents (Read-only)
+
+ + + + +
+ )} + /> + {footer} + +
+ + ) +}) + +GithubProviderForm.displayName = 'GithubProviderForm' + +function ExternalLink({ + href, + children +}: { + href: string + children: React.ReactNode +}) { + return ( + + {children} + + + ) +} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/git-privoders-page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/components/github.tsx similarity index 70% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/git-privoders-page.tsx rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/components/github.tsx index 32347d88be14..0535c097248c 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/components/git-privoders-page.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/components/github.tsx @@ -7,11 +7,8 @@ import { ListGithubRepositoryProvidersQuery } from '@/lib/gql/generates/graphql' import { listGithubRepositoryProviders } from '@/lib/tabby/query' import { buttonVariants } from '@/components/ui/button' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { IconGitHub } from '@/components/ui/icons' import LoadingWrapper from '@/components/loading-wrapper' -import { RepositoryHeader } from './header' - export default function GitProvidersPage() { const [{ data, fetching }] = useQuery({ query: listGithubRepositoryProviders @@ -20,13 +17,12 @@ export default function GitProvidersPage() { return ( <> - {githubRepositoryProviders?.length ? (
- + Create
@@ -53,35 +49,26 @@ const GitProvidersList: React.FC = ({ data }) => {
- - GitHub.com + {item.node.displayName}
View
- -
- Name - {item.node.displayName} -
-
- - Application ID - - {item.node.applicationId} -
-
+ +
Status - {item.node?.connected ? 'Connected' : 'Not Connected'} + {item.node?.connected + ? 'Connected' + : 'access_token needs update'}
@@ -98,7 +85,7 @@ const GitProvidersPlaceholder = () => {
No Data
Create diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/components/detail.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/components/detail.tsx similarity index 65% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/components/detail.tsx rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/components/detail.tsx index ac9a3ef3e7b6..5427f9251f5f 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/components/detail.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/components/detail.tsx @@ -2,7 +2,6 @@ import React, { useEffect, useMemo, useState } from 'react' import { useRouter, useSearchParams } from 'next/navigation' -import { toast } from 'sonner' import { useQuery } from 'urql' import { DEFAULT_PAGE_SIZE } from '@/lib/constants' @@ -13,7 +12,7 @@ import { } from '@/lib/tabby/query' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' -import { CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { CardContent, CardTitle } from '@/components/ui/card' import { Dialog, DialogContent, @@ -22,7 +21,7 @@ import { DialogTitle, DialogTrigger } from '@/components/ui/dialog' -import { IconChevronLeft, IconGitHub, IconTrash } from '@/components/ui/icons' +import { IconChevronLeft, IconPlus, IconTrash } from '@/components/ui/icons' import { Table, TableBody, @@ -52,29 +51,13 @@ const DetailPage: React.FC = () => { pause: !id }) const provider = data?.githubRepositoryProviders?.edges?.[0]?.node - const [githubRepositories, fetchingRepositories] = + const [githubRepositories, isGithubRepositoriesLoading] = useAllProvidedRepositories(id) - console.log(githubRepositories) - - const [open, setOpen] = React.useState(false) - - const onCreated = () => { - toast.success('Added successfully') - setOpen(false) - } const onDeleteProvider = () => { - router.replace('/settings/gitops') + router.back() } - const unlinkedRepos = useMemo(() => { - return githubRepositories?.filter(item => !item.node.active) - }, [githubRepositories]) - - const linkedRepos = useMemo(() => { - return githubRepositories?.filter(item => item.node.active) - }, [githubRepositories]) - if (!id || (!!id && !fetching && !provider)) { return (
@@ -85,70 +68,42 @@ const DetailPage: React.FC = () => { return ( - - -
+
+
-
- - GitHub.com -
- {provider?.connected ? ( - Connected - ) : ( - Not Connected - )} -
+ + + {provider?.displayName} +
+
+
+ {provider?.connected ? ( + Connected + ) : ( + Not Connected + )}
- - - +
+ + }> { - router.push('/settings/gitops') - }} id={id} /> - - - Repositories - - - - Add repository - - Add a new repository to this provider. - - - setOpen(false)} - onCreated={onCreated} - repositories={unlinkedRepos} - fetchingRepositories={fetchingRepositories} - /> - - - - - - - - - - +
+ + - +
) } @@ -181,19 +136,54 @@ const LinkedRepoTable: React.FC<{ }) } + const [open, setOpen] = React.useState(false) + + const onCreated = () => { + setOpen(false) + } + + const linkedRepos = useMemo(() => { + return data?.filter(item => item.node.active) + }, [data]) + + const unlinkedRepos = useMemo(() => { + return data?.filter(item => !item.node.active) + }, [data]) + return ( - +
Name - Git URL - + URL + + + + + Add new repository + + Add new GitHub repository from this provider + + + setOpen(false)} + onCreated={onCreated} + repositories={unlinkedRepos} + /> + + + + + + - {data?.length ? ( + {linkedRepos?.length ? ( <> - {data?.map(x => { + {linkedRepos?.map(x => { return ( {x.node.name} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/components/new-repository-form.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/components/new-repository-form.tsx similarity index 88% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/components/new-repository-form.tsx rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/components/new-repository-form.tsx index 22287d6c871c..f1d76bca2be2 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/components/new-repository-form.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/components/new-repository-form.tsx @@ -22,14 +22,9 @@ import { FormControl, FormField, FormItem, - FormLabel, FormMessage } from '@/components/ui/form' -import { - IconCheck, - IconChevronUpDown, - IconSpinner -} from '@/components/ui/icons' +import { IconCheck, IconChevronUpDown } from '@/components/ui/icons' import { Popover, PopoverContent, @@ -47,8 +42,7 @@ type LinkRepositoryFormValues = z.infer export default function LinkRepositoryForm({ onCreated, onCancel, - repositories, - fetchingRepositories + repositories }: { onCreated?: () => void onCancel: () => void @@ -57,7 +51,6 @@ export default function LinkRepositoryForm({ typeof listGithubRepositories >['githubRepositories']['edges'] | undefined - fetchingRepositories: boolean }) { const [open, setOpen] = React.useState(false) const form = useForm({ @@ -94,7 +87,6 @@ export default function LinkRepositoryForm({ name="id" render={({ field }) => ( - Repository @@ -123,15 +115,7 @@ export default function LinkRepositoryForm({ - - {fetchingRepositories ? ( -
- -
- ) : ( - 'No repository found.' - )} -
+ No repository found. {repositories?.map(repo => ( + +interface UpdateProviderFormProps { + id: string + defaultValues?: Partial + onSuccess?: () => void + onDelete: () => void +} + +export const UpdateProviderForm: React.FC = ({ + defaultValues, + onSuccess, + onDelete, + id +}) => { + const formRef = React.useRef<{ + form: UseFormReturn + }>(null) + const [deleteAlertVisible, setDeleteAlertVisible] = React.useState(false) + const [isDeleting, setIsDeleting] = React.useState(false) + const form = formRef.current?.form + const isSubmitting = form?.formState?.isSubmitting + const isDirty = !isEmpty(form?.formState?.dirtyFields) + + const deleteGithubRepositoryProvider = useMutation( + deleteGithubRepositoryProviderMutation + ) + + const updateGithubRepositoryProvider = useMutation( + updateGithubRepositoryProviderMutation, + { + form, + onCompleted(values) { + if (values?.updateGithubRepositoryProvider) { + toast.success('Updated GitHub repository provider successfully') + form?.reset(form?.getValues()) + onSuccess?.() + } + } + } + ) + + const onSubmit = async (values: FormValues) => { + await updateGithubRepositoryProvider({ + input: { + id, + ...values + } + }) + } + + const handleDeleteRepositoryProvider: React.MouseEventHandler< + HTMLButtonElement + > = async e => { + e.preventDefault() + setIsDeleting(true) + try { + const res = await deleteGithubRepositoryProvider({ id }) + if (res?.data?.deleteGithubRepositoryProvider) { + onDelete?.() + } else { + toast.error( + res?.error?.message || 'Failed to delete GitHub repository provider' + ) + } + } catch (error) { + toast.error('Failed to delete GitHub repository provider') + } finally { + setIsDeleting(false) + } + } + + return ( + +
+ +
+
+ + + + + + + Are you absolutely sure? + + This will delete the provider and remove any repositories + that have already been added to the provider. + + + + Cancel + + {isDeleting && } + Yes, delete it + + + + + +
+ + } + onSubmit={onSubmit} + /> + ) +} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/page.tsx similarity index 55% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/page.tsx rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/page.tsx index 7e2adffaa09f..a631dd12d106 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/page.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/page.tsx @@ -1,11 +1,5 @@ -import { Metadata } from 'next' - import ProviderDetail from './components/detail' -export const metadata: Metadata = { - title: 'New Provider' -} - export default function IndexPage() { return } diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/query.ts b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/query.ts similarity index 100% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/detail/query.ts rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/detail/query.ts diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/new/components/new-page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/new/components/new-page.tsx new file mode 100644 index 000000000000..dc78637d0aca --- /dev/null +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/new/components/new-page.tsx @@ -0,0 +1,87 @@ +'use client' + +import React from 'react' +import { useRouter } from 'next/navigation' +import { omit } from 'lodash-es' +import { UseFormReturn } from 'react-hook-form' +import { toast } from 'sonner' + +import { graphql } from '@/lib/gql/generates' +import { useMutation } from '@/lib/tabby/gql' +import { Button } from '@/components/ui/button' +import { FormMessage } from '@/components/ui/form' +import { IconSpinner } from '@/components/ui/icons' + +import { + CreateGithubProviderFormValues, + GithubProviderForm, + UpdateGithubProviderFormValues +} from '../../components/github-form' + +const createGithubRepositoryProvider = graphql(/* GraphQL */ ` + mutation CreateGithubRepositoryProvider( + $input: CreateGithubRepositoryProviderInput! + ) { + createGithubRepositoryProvider(input: $input) + } +`) + +export const NewProvider = () => { + const router = useRouter() + const formRef = React.useRef<{ + form: UseFormReturn + }>(null) + const isSubmitting = formRef.current?.form?.formState?.isSubmitting + + const createGithubRepositoryProviderMutation = useMutation( + createGithubRepositoryProvider, + { + onCompleted(data) { + if (data?.createGithubRepositoryProvider) { + router.back() + } + }, + onError(err) { + toast.error(err?.message) + }, + form: formRef.current + } + ) + + const handleSubmit = async (values: CreateGithubProviderFormValues) => { + return createGithubRepositoryProviderMutation({ + input: omit(values, 'provider') + }) + } + + return ( +
+ +
+ +
+
+ + +
+
+ } + onSubmit={handleSubmit} + /> + + ) +} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/new/page.tsx similarity index 55% rename from ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/page.tsx rename to ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/new/page.tsx index 8bd235f9fb85..22c998b7c6d7 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/gitops/new/page.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/new/page.tsx @@ -1,11 +1,5 @@ -import { Metadata } from 'next' - import { NewProvider } from './components/new-page' -export const metadata: Metadata = { - title: 'New Provider' -} - export default function IndexPage() { return } diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/page.tsx new file mode 100644 index 000000000000..cea9a7d5bbf4 --- /dev/null +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/github/page.tsx @@ -0,0 +1,5 @@ +import GithubPage from './components/github' + +export default function Github() { + return +} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/layout.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/layout.tsx new file mode 100644 index 000000000000..ddf42e81a095 --- /dev/null +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/repository/layout.tsx @@ -0,0 +1,31 @@ +import { Metadata } from 'next' + +import { SubHeader } from '@/components/sub-header' + +import RepositoryTabsHeader from './components/tabs-header' + +const Header = ({ className }: { className?: string }) => { + return ( + + Connect to Git repositories and uses these repositories as a context to + enhance performance of large language model. + + ) +} + +export default function GitLayout({ children }: { children: React.ReactNode }) { + return ( + <> +
+ +
{children}
+ + ) +} + +export const metadata: Metadata = { + title: 'Repository Providers' +} diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/oauth-credential-list.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/oauth-credential-list.tsx index e09e7a18b22b..95ccb787537f 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/oauth-credential-list.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/oauth-credential-list.tsx @@ -130,12 +130,12 @@ const OauthCredentialCard = ({ - -
+ +
Type OAuth 2.0
-
+
Domain {meta?.domain}
diff --git a/ee/tabby-ui/components/steps/steps.css b/ee/tabby-ui/components/steps/steps.css deleted file mode 100644 index 30adbeece27c..000000000000 --- a/ee/tabby-ui/components/steps/steps.css +++ /dev/null @@ -1,24 +0,0 @@ -.steps-item-title { - position: relative; -} -.steps-item:not(:last-child) .steps-item-title::after { - position: absolute; - top: 1rem; - inset-inline-start: 100%; - display: block; - width: 9999px; - height: 1px; - background: hsl(var(--border)); - content: ""; -} - -.steps-item:last-child { - flex-grow: 0; -} - -.steps-item[data-state=finish] .steps-item-title::after { - background: hsl(var(--primary)); -} -.steps-item[data-state=error] .steps-item-title::after { - background: hsl(var(--destructive)); -} \ No newline at end of file diff --git a/ee/tabby-ui/components/steps/steps.tsx b/ee/tabby-ui/components/steps/steps.tsx deleted file mode 100644 index 72fcd243f96b..000000000000 --- a/ee/tabby-ui/components/steps/steps.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import React from 'react' - -import { cn } from '@/lib/utils' - -import { IconCheck, IconClose } from '../ui/icons' - -import './steps.css' - -type StepStatus = 'current' | 'finish' | 'error' | 'loading' | 'wait' - -type SourceStepItem = { - title: string - description?: string - icon?: React.ReactNode - disabled?: boolean - status?: StepStatus -} - -type ComputedStepItem = SourceStepItem & { - status: StepStatus -} - -interface UseStepsReturn { - currentStep: number - steps: ComputedStepItem[] - setStep: (step: number) => void - // status for currentStep - status?: StepStatus -} - -interface StepsContextValue extends UseStepsReturn {} - -interface StepsProps extends UseStepsReturn { - children: React.ReactNode - className?: string -} - -const StepsContext = React.createContext( - {} as StepsContextValue -) - -const StepsContextProvider: React.FC = ({ - children, - className, - ...props -}) => { - return ( - -
{children}
-
- ) -} - -const Steps = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, children, ...props }, ref) => { - return ( -
- {children} -
- ) -}) -Steps.displayName = 'Steps' - -interface StepItemProps - extends Omit, 'title'>, - ComputedStepItem { - index: number -} - -const StepItem = React.forwardRef( - ({ className, children, ...props }, ref) => { - return ( -
-
- -
-
{props.title}
-
{props.description}
-
-
-
- ) - } -) -StepItem.displayName = 'StepItem' - -const StepIcon: React.FC< - Pick & { index: number } -> = ({ icon, index, status }) => { - const getIcon = () => { - if (icon) { - return icon - } - if (status === 'finish') { - return - } - if (status === 'error') { - return - } - return index + 1 - } - - return ( -
- {getIcon()} -
- ) -} - -interface UseStepsOptions { - items: SourceStepItem[] - initialStep?: number -} - -function useSteps(options: UseStepsOptions): UseStepsReturn { - const { items } = options - const [currentStep, setCurrentStep] = React.useState(options.initialStep || 0) - - const computedSteps = React.useMemo(() => { - return items.map((item, index) => { - const isPrevStep = index < currentStep - const isCurrentStep = index === currentStep - const computedStatusFromIndex = isPrevStep - ? 'finish' - : isCurrentStep - ? 'current' - : 'wait' - return { - ...item, - status: item.status || computedStatusFromIndex - } - }) - }, [items, currentStep]) - - return { - currentStep, - setStep: setCurrentStep, - steps: computedSteps - } -} - -export type { ComputedStepItem } - -export { StepsContextProvider, Steps, StepItem, useSteps } diff --git a/ee/tabby-ui/lib/popup-window-management.ts b/ee/tabby-ui/lib/popup-window-management.ts deleted file mode 100644 index 10316aea2ea1..000000000000 --- a/ee/tabby-ui/lib/popup-window-management.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { useEffect, useRef } from 'react' - -interface PopupWindowManagementOptions { - popupUrl: string - width?: number - height?: number - onMessage?: (data: any) => any -} - -class PopupWindowManagement { - private popupUrl: string | undefined - private width: number - private height: number - private onMessage: ((data: any) => any) | void - private popup: Window | null - - constructor({ - popupUrl, - width = 600, - height = 700, - onMessage - }: PopupWindowManagementOptions) { - this.popupUrl = popupUrl - this.popup = null - this.onMessage = onMessage - this.width = width - this.height = height - window.addEventListener('message', this.handleMessage, false) - } - - destory() { - window.removeEventListener('message', this.handleMessage, false) - - this.close() - this.onMessage = undefined - } - - open() { - if (this.popup && !this.popup.closed) { - this.popup.focus() - return - } - - const left = window.screenX + (window.outerWidth - this.width) / 2 - const top = window.screenY + (window.outerHeight - this.height) / 2.5 - const windowFeatures = `toolbar=no, menubar=no, width=${this.width}, height=${this.height}, top=${top}, left=${left}` - this.popup = window.open(this.popupUrl, 'PopupWindow', windowFeatures) - } - - close() { - if (this.popup && !this.popup.closed) { - this.popup.close() - this.popup = null - } - } - - getPopupUrl() { - return this.popupUrl - } - - private handleMessage = (event: MessageEvent) => { - if (event.origin === window.origin) { - if (event.source === this.popup) { - const data = event.data - this.onMessage?.(data) - } - } - } -} - -const usePopupWindow = ( - options: Omit -) => { - const managementRef = useRef(null) - - const open = (url: string) => { - if (managementRef.current) { - const popupUrl = managementRef.current.getPopupUrl() - if (popupUrl === url) { - managementRef.current.open() - } else { - managementRef.current.destory() - managementRef.current = new PopupWindowManagement({ - ...options, - popupUrl: url - }) - managementRef.current.open() - } - } else { - managementRef.current = new PopupWindowManagement({ - ...options, - popupUrl: url - }) - managementRef.current.open() - } - } - - const close = () => { - managementRef.current?.close() - } - - const destory = () => { - if (managementRef.current) { - managementRef.current.destory() - managementRef.current = null - } - } - - useEffect(() => { - return () => { - if (managementRef.current) { - managementRef.current.destory() - managementRef.current = null - } - } - }, []) - - return { - open, - close, - destory - } -} - -export { usePopupWindow, PopupWindowManagement } diff --git a/ee/tabby-ui/lib/tabby/gql.ts b/ee/tabby-ui/lib/tabby/gql.ts index 4a76235dbceb..b68c2f660098 100644 --- a/ee/tabby-ui/lib/tabby/gql.ts +++ b/ee/tabby-ui/lib/tabby/gql.ts @@ -138,11 +138,11 @@ const client = new Client({ }) } }, - deleteRepository(result, args, cache, info) { - if (result.deleteRepository) { + deleteGitRepository(result, args, cache, info) { + if (result.deleteGitRepository) { cache .inspectFields('Query') - .filter(field => field.fieldName === 'repositories') + .filter(field => field.fieldName === 'gitRepositories') .forEach(field => { cache.updateQuery( { diff --git a/ee/tabby-ui/lib/tabby/query.ts b/ee/tabby-ui/lib/tabby/query.ts index 0b62b5a466a4..3b630e042025 100644 --- a/ee/tabby-ui/lib/tabby/query.ts +++ b/ee/tabby-ui/lib/tabby/query.ts @@ -186,7 +186,6 @@ export const listGithubRepositoryProviders = graphql(/* GraphQL */ ` node { id displayName - applicationId connected } cursor