feat(v2): add page list/add/detail

This commit is contained in:
moonrailgun 2024-03-30 00:08:02 +08:00
parent f27f3f2f11
commit d97c671913
8 changed files with 227 additions and 3 deletions

View File

@ -75,6 +75,7 @@ export const MonitorStatusPage: React.FC<MonitorStatusPageProps> = React.memo(
/> />
</div> </div>
)} )}
<div <div
className={clsx( className={clsx(
'mx-auto overflow-auto px-4 py-8', 'mx-auto overflow-auto px-4 py-8',

View File

@ -14,6 +14,7 @@ import { Route as rootRoute } from './routes/__root'
import { Route as WebsiteImport } from './routes/website' import { Route as WebsiteImport } from './routes/website'
import { Route as TelemetryImport } from './routes/telemetry' import { Route as TelemetryImport } from './routes/telemetry'
import { Route as RegisterImport } from './routes/register' import { Route as RegisterImport } from './routes/register'
import { Route as PageImport } from './routes/page'
import { Route as MonitorImport } from './routes/monitor' import { Route as MonitorImport } from './routes/monitor'
import { Route as LoginImport } from './routes/login' import { Route as LoginImport } from './routes/login'
import { Route as DashboardImport } from './routes/dashboard' import { Route as DashboardImport } from './routes/dashboard'
@ -22,6 +23,8 @@ import { Route as WebsiteAddImport } from './routes/website/add'
import { Route as WebsiteWebsiteIdImport } from './routes/website/$websiteId' import { Route as WebsiteWebsiteIdImport } from './routes/website/$websiteId'
import { Route as TelemetryAddImport } from './routes/telemetry/add' import { Route as TelemetryAddImport } from './routes/telemetry/add'
import { Route as TelemetryTelemetryIdImport } from './routes/telemetry/$telemetryId' import { Route as TelemetryTelemetryIdImport } from './routes/telemetry/$telemetryId'
import { Route as PageAddImport } from './routes/page/add'
import { Route as PageSlugImport } from './routes/page/$slug'
import { Route as MonitorAddImport } from './routes/monitor/add' import { Route as MonitorAddImport } from './routes/monitor/add'
import { Route as MonitorMonitorIdImport } from './routes/monitor/$monitorId' import { Route as MonitorMonitorIdImport } from './routes/monitor/$monitorId'
@ -42,6 +45,11 @@ const RegisterRoute = RegisterImport.update({
getParentRoute: () => rootRoute, getParentRoute: () => rootRoute,
} as any) } as any)
const PageRoute = PageImport.update({
path: '/page',
getParentRoute: () => rootRoute,
} as any)
const MonitorRoute = MonitorImport.update({ const MonitorRoute = MonitorImport.update({
path: '/monitor', path: '/monitor',
getParentRoute: () => rootRoute, getParentRoute: () => rootRoute,
@ -82,6 +90,16 @@ const TelemetryTelemetryIdRoute = TelemetryTelemetryIdImport.update({
getParentRoute: () => TelemetryRoute, getParentRoute: () => TelemetryRoute,
} as any) } as any)
const PageAddRoute = PageAddImport.update({
path: '/add',
getParentRoute: () => PageRoute,
} as any)
const PageSlugRoute = PageSlugImport.update({
path: '/$slug',
getParentRoute: () => PageRoute,
} as any)
const MonitorAddRoute = MonitorAddImport.update({ const MonitorAddRoute = MonitorAddImport.update({
path: '/add', path: '/add',
getParentRoute: () => MonitorRoute, getParentRoute: () => MonitorRoute,
@ -112,6 +130,10 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof MonitorImport preLoaderRoute: typeof MonitorImport
parentRoute: typeof rootRoute parentRoute: typeof rootRoute
} }
'/page': {
preLoaderRoute: typeof PageImport
parentRoute: typeof rootRoute
}
'/register': { '/register': {
preLoaderRoute: typeof RegisterImport preLoaderRoute: typeof RegisterImport
parentRoute: typeof rootRoute parentRoute: typeof rootRoute
@ -132,6 +154,14 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof MonitorAddImport preLoaderRoute: typeof MonitorAddImport
parentRoute: typeof MonitorImport parentRoute: typeof MonitorImport
} }
'/page/$slug': {
preLoaderRoute: typeof PageSlugImport
parentRoute: typeof PageImport
}
'/page/add': {
preLoaderRoute: typeof PageAddImport
parentRoute: typeof PageImport
}
'/telemetry/$telemetryId': { '/telemetry/$telemetryId': {
preLoaderRoute: typeof TelemetryTelemetryIdImport preLoaderRoute: typeof TelemetryTelemetryIdImport
parentRoute: typeof TelemetryImport parentRoute: typeof TelemetryImport
@ -158,6 +188,7 @@ export const routeTree = rootRoute.addChildren([
DashboardRoute, DashboardRoute,
LoginRoute, LoginRoute,
MonitorRoute.addChildren([MonitorMonitorIdRoute, MonitorAddRoute]), MonitorRoute.addChildren([MonitorMonitorIdRoute, MonitorAddRoute]),
PageRoute.addChildren([PageSlugRoute, PageAddRoute]),
RegisterRoute, RegisterRoute,
TelemetryRoute.addChildren([TelemetryTelemetryIdRoute, TelemetryAddRoute]), TelemetryRoute.addChildren([TelemetryTelemetryIdRoute, TelemetryAddRoute]),
WebsiteRoute.addChildren([WebsiteWebsiteIdRoute, WebsiteAddRoute]), WebsiteRoute.addChildren([WebsiteWebsiteIdRoute, WebsiteAddRoute]),

View File

@ -6,8 +6,6 @@ interface RouterContext {
userInfo: any; userInfo: any;
} }
const defaultLayout: [number, number, number] = [265, 440, 655];
export const Route = createRootRouteWithContext<RouterContext>()({ export const Route = createRootRouteWithContext<RouterContext>()({
component: () => { component: () => {
return ( return (

View File

@ -21,9 +21,9 @@ export const Route = createFileRoute('/monitor/add')({
function MonitorAddComponent() { function MonitorAddComponent() {
const { t } = useTranslation(); const { t } = useTranslation();
const workspaceId = useCurrentWorkspaceId(); const workspaceId = useCurrentWorkspaceId();
const addWebsiteMutation = trpc.website.add.useMutation();
const navigate = useNavigate(); const navigate = useNavigate();
const mutation = useMonitorUpsert(); const mutation = useMonitorUpsert();
const utils = trpc.useUtils();
const handleSubmit = useEvent(async (values: MonitorInfoEditorValues) => { const handleSubmit = useEvent(async (values: MonitorInfoEditorValues) => {
const res = await mutation.mutateAsync({ const res = await mutation.mutateAsync({
@ -31,6 +31,8 @@ function MonitorAddComponent() {
workspaceId, workspaceId,
}); });
utils.monitor.all.refetch();
navigate({ navigate({
to: '/monitor/$monitorId', to: '/monitor/$monitorId',
params: { params: {

View File

@ -0,0 +1,86 @@
import { trpc } from '@/api/trpc';
import { CommonHeader } from '@/components/CommonHeader';
import { CommonList } from '@/components/CommonList';
import { CommonWrapper } from '@/components/CommonWrapper';
import { Button } from '@/components/ui/button';
import { useDataReady } from '@/hooks/useDataReady';
import { useEvent } from '@/hooks/useEvent';
import { LayoutV2 } from '@/pages/LayoutV2';
import { useCurrentWorkspaceId } from '@/store/user';
import { routeAuthBeforeLoad } from '@/utils/route';
import { useTranslation } from '@i18next-toolkit/react';
import {
createFileRoute,
useNavigate,
useRouterState,
} from '@tanstack/react-router';
import { LuPlus } from 'react-icons/lu';
export const Route = createFileRoute('/page')({
beforeLoad: routeAuthBeforeLoad,
component: PageComponent,
});
function PageComponent() {
const workspaceId = useCurrentWorkspaceId();
const { t } = useTranslation();
const { data = [] } = trpc.monitor.getAllPages.useQuery({
workspaceId,
});
const navigate = useNavigate();
const pathname = useRouterState({
select: (state) => state.location.pathname,
});
const items = data.map((item) => ({
id: item.id,
title: item.title,
content: item.slug,
href: `/page/${item.slug}`,
}));
useDataReady(
() => data.length > 0,
() => {
if (pathname === Route.fullPath) {
navigate({
to: '/page/$slug',
params: {
slug: data[0].slug,
},
});
}
}
);
const handleClickAdd = useEvent(() => {
navigate({
to: '/page/add',
});
});
return (
<LayoutV2
list={
<CommonWrapper
header={
<CommonHeader
title={t('Pages')}
actions={
<Button
variant="outline"
Icon={LuPlus}
onClick={handleClickAdd}
>
{t('Add')}
</Button>
}
/>
}
>
<CommonList hasSearch={true} items={items} />
</CommonWrapper>
}
/>
);
}

View File

@ -0,0 +1,42 @@
import { trpc } from '@/api/trpc';
import { CommonHeader } from '@/components/CommonHeader';
import { CommonWrapper } from '@/components/CommonWrapper';
import { ErrorTip } from '@/components/ErrorTip';
import { Loading } from '@/components/Loading';
import { NotFoundTip } from '@/components/NotFoundTip';
import { MonitorStatusPage } from '@/components/monitor/StatusPage';
import { ScrollArea } from '@/components/ui/scroll-area';
import { routeAuthBeforeLoad } from '@/utils/route';
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/page/$slug')({
beforeLoad: routeAuthBeforeLoad,
component: PageDetailComponent,
});
function PageDetailComponent() {
const { slug } = Route.useParams<{ slug: string }>();
const { data: pageInfo, isLoading } = trpc.monitor.getPageInfo.useQuery({
slug,
});
if (!slug) {
return <ErrorTip />;
}
if (isLoading) {
return <Loading />;
}
if (!pageInfo) {
return <NotFoundTip />;
}
return (
<CommonWrapper header={<CommonHeader title={pageInfo.title} />}>
{/* <ScrollArea className="h-full overflow-hidden"> */}
<MonitorStatusPage slug={slug} />
{/* </ScrollArea> */}
</CommonWrapper>
);
}

View File

@ -0,0 +1,61 @@
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 { Card, CardContent } from '@/components/ui/card';
import { CommonWrapper } from '@/components/CommonWrapper';
import { routeAuthBeforeLoad } from '@/utils/route';
import {
MonitorStatusPageEditForm,
MonitorStatusPageEditFormValues,
} from '@/components/monitor/StatusPage/EditForm';
export const Route = createFileRoute('/page/add')({
beforeLoad: routeAuthBeforeLoad,
component: PageAddComponent,
});
function PageAddComponent() {
const { t } = useTranslation();
const workspaceId = useCurrentWorkspaceId();
const createPageMutation = trpc.monitor.createPage.useMutation();
const navigate = useNavigate();
const utils = trpc.useUtils();
const handleSubmit = useEvent(
async (values: MonitorStatusPageEditFormValues) => {
const res = await createPageMutation.mutateAsync({
...values,
workspaceId,
});
utils.monitor.getAllPages.refetch();
navigate({
to: '/page/$slug',
params: {
slug: res.slug,
},
});
}
);
return (
<CommonWrapper
header={<h1 className="text-xl font-bold">{t('Add Page')}</h1>}
>
<div className="p-4">
<Card>
<CardContent className="pt-4">
<MonitorStatusPageEditForm
saveButtonLabel="Next"
isLoading={createPageMutation.isLoading}
onFinish={handleSubmit}
/>
</CardContent>
</Card>
</div>
</CommonWrapper>
);
}

View File

@ -554,6 +554,9 @@ export const monitorRouter = router({
where: { where: {
workspaceId, workspaceId,
}, },
orderBy: {
updatedAt: 'desc',
},
}); });
}), }),
getPageInfo: publicProcedure getPageInfo: publicProcedure