From 20e19633aeacf971dfc0c4855604a2c60d58198b Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Mon, 1 Apr 2024 01:00:34 +0800 Subject: [PATCH] feat(v2): add server page --- pnpm-lock.yaml | 30 +++++++ src/client/components/ui/switch.tsx | 27 ++++++ src/client/package.json | 3 +- src/client/pages/LayoutV2.tsx | 35 +++++--- src/client/routeTree.gen.ts | 11 +++ src/client/routes/page/add.tsx | 6 +- src/client/routes/register.tsx | 5 +- src/client/routes/server.tsx | 123 ++++++++++++++++++++++++++++ src/client/routes/telemetry/add.tsx | 6 +- src/client/routes/website/add.tsx | 6 +- 10 files changed, 232 insertions(+), 20 deletions(-) create mode 100644 src/client/components/ui/switch.tsx create mode 100644 src/client/routes/server.tsx diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ca75530..7a4a711 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -123,6 +123,9 @@ importers: '@radix-ui/react-slot': specifier: ^1.0.2 version: 1.0.2(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-switch': + specifier: ^1.0.3 + version: 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-tabs': specifier: ^1.0.4 version: 1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) @@ -7800,6 +7803,33 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-switch@1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-mxm87F88HyHztsI7N+ZUmEoARGkC22YVW5CaC+Byc+HRpuvCrOBPTAnXgf+tZ/7i0Sg/eOePGdMhUKhPaQEqow==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@types/react': 18.2.21 + '@types/react-dom': 18.2.7 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-tabs@1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==} peerDependencies: diff --git a/src/client/components/ui/switch.tsx b/src/client/components/ui/switch.tsx new file mode 100644 index 0000000..5361e78 --- /dev/null +++ b/src/client/components/ui/switch.tsx @@ -0,0 +1,27 @@ +import * as React from "react" +import * as SwitchPrimitives from "@radix-ui/react-switch" + +import { cn } from "@/utils/style" + +const Switch = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +Switch.displayName = SwitchPrimitives.Root.displayName + +export { Switch } diff --git a/src/client/package.json b/src/client/package.json index 1f35300..fe70154 100644 --- a/src/client/package.json +++ b/src/client/package.json @@ -20,8 +20,8 @@ "@ant-design/icons": "^5.2.6", "@antv/l7": "^2.20.14", "@antv/larkmap": "^1.4.13", - "@i18next-toolkit/react": "^1.0.6", "@hookform/resolvers": "^3.3.4", + "@i18next-toolkit/react": "^1.0.6", "@loadable/component": "^5.16.3", "@monaco-editor/react": "^4.6.0", "@radix-ui/react-alert-dialog": "^1.0.5", @@ -36,6 +36,7 @@ "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.7", "@tanstack/react-query": "4.33.0", diff --git a/src/client/pages/LayoutV2.tsx b/src/client/pages/LayoutV2.tsx index 1cad7a4..954883a 100644 --- a/src/client/pages/LayoutV2.tsx +++ b/src/client/pages/LayoutV2.tsx @@ -24,9 +24,10 @@ import { useCurrentWorkspaceId } from '@/store/user'; const defaultLayout: [number, number, number] = [265, 440, 655]; -export const LayoutV2: React.FC<{ - list: React.ReactNode; -}> = React.memo((props) => { +interface LayoutProps extends React.PropsWithChildren { + list?: React.ReactNode; +} +export const LayoutV2: React.FC = React.memo((props) => { const [layout = defaultLayout, setLayout] = useLocalStorageState( 'react-resizable-panels:layout', { defaultValue: defaultLayout } @@ -47,7 +48,13 @@ export const LayoutV2: React.FC<{ { - setLayout(sizes as typeof defaultLayout); + if (sizes.length === 3) { + setLayout(sizes as typeof defaultLayout); + } else if (sizes.length === 2) { + const listSize = layout[1]; + const rest = 100 - sizes[0] - listSize; + setLayout([sizes[0], listSize, rest]); + } }} className="h-full items-stretch" > @@ -119,14 +126,22 @@ export const LayoutV2: React.FC<{ + + {props.list && ( + <> + + +
{props.list}
+
+ + )} + - -
{props.list}
-
- - +
- + {props.children ?? }
diff --git a/src/client/routeTree.gen.ts b/src/client/routeTree.gen.ts index cf63cc7..c1ec572 100644 --- a/src/client/routeTree.gen.ts +++ b/src/client/routeTree.gen.ts @@ -13,6 +13,7 @@ import { Route as rootRoute } from './routes/__root' import { Route as WebsiteImport } from './routes/website' import { Route as TelemetryImport } from './routes/telemetry' +import { Route as ServerImport } from './routes/server' import { Route as RegisterImport } from './routes/register' import { Route as PageImport } from './routes/page' import { Route as MonitorImport } from './routes/monitor' @@ -41,6 +42,11 @@ const TelemetryRoute = TelemetryImport.update({ getParentRoute: () => rootRoute, } as any) +const ServerRoute = ServerImport.update({ + path: '/server', + getParentRoute: () => rootRoute, +} as any) + const RegisterRoute = RegisterImport.update({ path: '/register', getParentRoute: () => rootRoute, @@ -144,6 +150,10 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof RegisterImport parentRoute: typeof rootRoute } + '/server': { + preLoaderRoute: typeof ServerImport + parentRoute: typeof rootRoute + } '/telemetry': { preLoaderRoute: typeof TelemetryImport parentRoute: typeof rootRoute @@ -200,6 +210,7 @@ export const routeTree = rootRoute.addChildren([ MonitorRoute.addChildren([MonitorMonitorIdRoute, MonitorAddRoute]), PageRoute.addChildren([PageSlugRoute, PageAddRoute]), RegisterRoute, + ServerRoute, TelemetryRoute.addChildren([TelemetryTelemetryIdRoute, TelemetryAddRoute]), WebsiteRoute.addChildren([ WebsiteWebsiteIdRoute, diff --git a/src/client/routes/page/add.tsx b/src/client/routes/page/add.tsx index fd35979..46a9c5f 100644 --- a/src/client/routes/page/add.tsx +++ b/src/client/routes/page/add.tsx @@ -2,7 +2,7 @@ import { createFileRoute, useNavigate } from '@tanstack/react-router'; import { useTranslation } from '@i18next-toolkit/react'; import { useEvent } from '@/hooks/useEvent'; import { useCurrentWorkspaceId } from '@/store/user'; -import { trpc } from '@/api/trpc'; +import { defaultErrorHandler, trpc } from '@/api/trpc'; import { Card, CardContent } from '@/components/ui/card'; import { CommonWrapper } from '@/components/CommonWrapper'; import { routeAuthBeforeLoad } from '@/utils/route'; @@ -19,7 +19,9 @@ export const Route = createFileRoute('/page/add')({ function PageAddComponent() { const { t } = useTranslation(); const workspaceId = useCurrentWorkspaceId(); - const createPageMutation = trpc.monitor.createPage.useMutation(); + const createPageMutation = trpc.monitor.createPage.useMutation({ + onError: defaultErrorHandler, + }); const navigate = useNavigate(); const utils = trpc.useUtils(); diff --git a/src/client/routes/register.tsx b/src/client/routes/register.tsx index 90671aa..c67494e 100644 --- a/src/client/routes/register.tsx +++ b/src/client/routes/register.tsx @@ -1,5 +1,4 @@ import { Button, Form, Input, Typography } from 'antd'; -import React from 'react'; import { useNavigate } from 'react-router'; import { useRequest } from '../hooks/useRequest'; import { trpc } from '../api/trpc'; @@ -30,10 +29,10 @@ function RegisterComponent() { }); return ( -
+
- +
{t('Register Account')} diff --git a/src/client/routes/server.tsx b/src/client/routes/server.tsx new file mode 100644 index 0000000..7e6945f --- /dev/null +++ b/src/client/routes/server.tsx @@ -0,0 +1,123 @@ +import { defaultErrorHandler, trpc } from '@/api/trpc'; +import { CommonHeader } from '@/components/CommonHeader'; +import { CommonList } from '@/components/CommonList'; +import { CommonWrapper } from '@/components/CommonWrapper'; +import { + AlertDialog, + AlertDialogAction, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from '@/components/ui/alert-dialog'; +import { Button } from '@/components/ui/button'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import { Switch } from '@/components/ui/switch'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import { useEventWithLoading } from '@/hooks/useEvent'; +import { LayoutV2 } from '@/pages/LayoutV2'; +import { AddServerStep, InstallScript, ServerList } from '@/pages/Servers'; +import { useCurrentWorkspaceId } from '@/store/user'; +import { routeAuthBeforeLoad } from '@/utils/route'; +import { useTranslation } from '@i18next-toolkit/react'; +import { createFileRoute } from '@tanstack/react-router'; +import { Popconfirm } from 'antd'; +import React from 'react'; +import { useState } from 'react'; +import { LuPlus } from 'react-icons/lu'; + +export const Route = createFileRoute('/server')({ + beforeLoad: routeAuthBeforeLoad, + component: ServerComponent, +}); + +function ServerComponent() { + return ( + + + + ); +} + +export const ServerContent: React.FC = React.memo(() => { + const [hideOfflineServer, setHideOfflineServer] = useState(false); + const { t } = useTranslation(); + const workspaceId = useCurrentWorkspaceId(); + + const clearOfflineNodeMutation = + trpc.serverStatus.clearOfflineServerStatus.useMutation({ + onError: defaultErrorHandler, + }); + + const [handleClearOfflineNode, loading] = useEventWithLoading(async (e) => { + await clearOfflineNodeMutation.mutateAsync({ + workspaceId, + }); + }); + + return ( + + + + {t('Hide Offline')} + + + + + + + + + + +
+ + + {t('Auto')} + {t('Manual')} + + + + + + + + +
+ + + {t('Continue')} + +
+
+
+ } + /> + } + > + + + + + ); +}); +ServerContent.displayName = 'ServerContent'; diff --git a/src/client/routes/telemetry/add.tsx b/src/client/routes/telemetry/add.tsx index 4c893fd..f426e51 100644 --- a/src/client/routes/telemetry/add.tsx +++ b/src/client/routes/telemetry/add.tsx @@ -3,7 +3,7 @@ import { useTranslation } from '@i18next-toolkit/react'; import { Button } from '@/components/ui/button'; import { useEvent } from '@/hooks/useEvent'; import { useCurrentWorkspaceId } from '@/store/user'; -import { trpc } from '@/api/trpc'; +import { defaultErrorHandler, trpc } from '@/api/trpc'; import { Card, CardContent, CardFooter } from '@/components/ui/card'; import { CommonWrapper } from '@/components/CommonWrapper'; import { routeAuthBeforeLoad } from '@/utils/route'; @@ -33,7 +33,9 @@ const addFormSchema = z.object({ function TelemetryAddComponent() { const { t } = useTranslation(); const workspaceId = useCurrentWorkspaceId(); - const addTelemetryMutation = trpc.telemetry.upsert.useMutation(); + const addTelemetryMutation = trpc.telemetry.upsert.useMutation({ + onError: defaultErrorHandler, + }); const utils = trpc.useUtils(); const navigate = useNavigate(); diff --git a/src/client/routes/website/add.tsx b/src/client/routes/website/add.tsx index 8db7e2c..59eaafb 100644 --- a/src/client/routes/website/add.tsx +++ b/src/client/routes/website/add.tsx @@ -17,7 +17,7 @@ import { import { useEvent } from '@/hooks/useEvent'; import { Input } from '@/components/ui/input'; import { useCurrentWorkspaceId } from '@/store/user'; -import { trpc } from '@/api/trpc'; +import { defaultErrorHandler, trpc } from '@/api/trpc'; import { hostnameRegex } from '@tianji/shared'; import { Card, CardContent, CardFooter } from '@/components/ui/card'; import { CommonWrapper } from '@/components/CommonWrapper'; @@ -35,7 +35,9 @@ const addFormSchema = z.object({ function WebsiteAddComponent() { const { t } = useTranslation(); const workspaceId = useCurrentWorkspaceId(); - const addWebsiteMutation = trpc.website.add.useMutation(); + const addWebsiteMutation = trpc.website.add.useMutation({ + onError: defaultErrorHandler, + }); const utils = trpc.useUtils(); const navigate = useNavigate();