feat: monitor openapi and some type issue

This commit is contained in:
moonrailgun 2023-10-25 00:17:18 +08:00
parent c161219137
commit 111cf2f0eb
6 changed files with 180 additions and 33 deletions

View File

@ -3,9 +3,9 @@ import { DateUnit } from '../../utils/date';
import { queryClient } from '../cache'; import { queryClient } from '../cache';
import { request } from '../request'; import { request } from '../request';
import { getUserTimezone } from './user'; import { getUserTimezone } from './user';
import { Website as WebsiteInfo } from '@prisma/client'; import { AppRouterOutput } from '../trpc';
export type { WebsiteInfo }; export type WebsiteInfo = NonNullable<AppRouterOutput['website']['info']>;
export async function getWorkspaceWebsites( export async function getWorkspaceWebsites(
workspaceId: string workspaceId: string

View File

@ -31,7 +31,7 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
isLoading, isLoading,
} = trpc.monitor.get.useQuery({ } = trpc.monitor.get.useQuery({
workspaceId, workspaceId,
id: monitorId, monitorId,
}); });
if (isInitialLoading) { if (isInitialLoading) {

View File

@ -12,10 +12,10 @@ import { useCurrentWorkspaceId } from '../../store/user';
export const MonitorEdit: React.FC = React.memo(() => { export const MonitorEdit: React.FC = React.memo(() => {
const { monitorId } = useParams<{ monitorId: string }>(); const { monitorId } = useParams<{ monitorId: string }>();
const currentWorkspaceId = useCurrentWorkspaceId(); const workspaceId = useCurrentWorkspaceId();
const { data: monitor, isLoading } = trpc.monitor.get.useQuery({ const { data: monitor, isLoading } = trpc.monitor.get.useQuery({
id: monitorId!, monitorId: monitorId!,
workspaceId: currentWorkspaceId, workspaceId,
}); });
const mutation = useMonitorUpsert(); const mutation = useMonitorUpsert();
const navigate = useNavigate(); const navigate = useNavigate();
@ -40,7 +40,7 @@ export const MonitorEdit: React.FC = React.memo(() => {
onSave={async (value) => { onSave={async (value) => {
const monitor = await mutation.mutateAsync({ const monitor = await mutation.mutateAsync({
...value, ...value,
workspaceId: currentWorkspaceId, workspaceId,
}); });
navigate(`/monitor/${monitor.id}`, { replace: true }); navigate(`/monitor/${monitor.id}`, { replace: true });
}} }}

View File

@ -1,5 +1,15 @@
import { z } from 'zod'; import { z } from 'zod';
// Match prisma `JsonValue`
export const jsonFieldSchema = z.union([
z.null(),
z.record(z.any()),
z.array(z.any()),
z.string(),
z.boolean(),
z.number(),
]);
export const workspaceSchema = z.object({ export const workspaceSchema = z.object({
id: z.string(), id: z.string(),
name: z.string(), name: z.string(),
@ -34,3 +44,36 @@ export const websiteInfoSchema = z.object({
updatedAt: z.date(), updatedAt: z.date(),
deletedAt: z.date().nullable(), deletedAt: z.date().nullable(),
}); });
export const monitorInfoSchema = z.object({
id: z.string(),
workspaceId: z.string(),
name: z.string(),
type: z.string(),
active: z.boolean(),
interval: z.number(),
payload: jsonFieldSchema,
createdAt: z.date(),
});
export const monitorInfoWithNotificationIdSchema = monitorInfoSchema.and(
z.object({
notifications: z.array(z.object({ id: z.string() })),
})
);
export const monitorEventSchema = z.object({
id: z.string(),
message: z.string(),
monitorId: z.string(),
type: z.string(),
createdAt: z.date(),
});
export const monitorStatusSchema = z.object({
monitorId: z.string(),
statusName: z.string(),
payload: jsonFieldSchema,
createdAt: z.date(),
updatedAt: z.date(),
});

View File

@ -1,39 +1,36 @@
import { router, workspaceOwnerProcedure, workspaceProcedure } from '../trpc'; import {
OpenApiMetaInfo,
router,
workspaceOwnerProcedure,
workspaceProcedure,
} from '../trpc';
import { prisma } from '../../model/_client'; import { prisma } from '../../model/_client';
import { z } from 'zod'; import { z } from 'zod';
import { monitorManager } from '../../model/monitor'; import { monitorManager } from '../../model/monitor';
import { MonitorInfoWithNotificationIds } from '../../../types'; import { MonitorInfoWithNotificationIds } from '../../../types';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import {
monitorEventSchema,
monitorInfoSchema,
monitorInfoWithNotificationIdSchema,
monitorStatusSchema,
} from '../../model/_schema';
import { OPENAPI_TAG } from '../../utils/const';
import { OpenApiMeta } from 'trpc-openapi';
export const monitorRouter = router({ export const monitorRouter = router({
all: workspaceProcedure.query(async ({ input }) => { all: workspaceProcedure
const workspaceId = input.workspaceId; .meta(
const monitors = await prisma.monitor.findMany({ buildMonitorOpenapi({
where: { method: 'GET',
workspaceId, path: '/all',
},
include: {
notifications: {
select: {
id: true,
},
},
},
});
return monitors as MonitorInfoWithNotificationIds[];
}),
get: workspaceProcedure
.input(
z.object({
id: z.string().cuid2(),
}) })
) )
.output(z.array(monitorInfoWithNotificationIdSchema))
.query(async ({ input }) => { .query(async ({ input }) => {
const { id, workspaceId } = input; const workspaceId = input.workspaceId;
const monitor = await prisma.monitor.findUnique({ const monitors = await prisma.monitor.findMany({
where: { where: {
id,
workspaceId, workspaceId,
}, },
include: { include: {
@ -45,9 +42,46 @@ export const monitorRouter = router({
}, },
}); });
return monitor as MonitorInfoWithNotificationIds; return monitors as MonitorInfoWithNotificationIds[];
}),
get: workspaceProcedure
.meta(
buildMonitorOpenapi({
method: 'GET',
path: '/{monitorId}',
})
)
.input(
z.object({
monitorId: z.string().cuid2(),
})
)
.output(monitorInfoWithNotificationIdSchema.nullable())
.query(async ({ input }) => {
const { monitorId, workspaceId } = input;
const monitor = await prisma.monitor.findUnique({
where: {
id: monitorId,
workspaceId,
},
include: {
notifications: {
select: {
id: true,
},
},
},
});
return monitor;
}), }),
upsert: workspaceOwnerProcedure upsert: workspaceOwnerProcedure
.meta(
buildMonitorOpenapi({
method: 'POST',
path: '/upsert',
})
)
.input( .input(
z.object({ z.object({
id: z.string().cuid2().optional(), id: z.string().cuid2().optional(),
@ -59,6 +93,7 @@ export const monitorRouter = router({
payload: z.object({}).passthrough(), payload: z.object({}).passthrough(),
}) })
) )
.output(monitorInfoSchema)
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
const { const {
id, id,
@ -85,6 +120,12 @@ export const monitorRouter = router({
return monitor; return monitor;
}), }),
data: workspaceProcedure data: workspaceProcedure
.meta(
buildMonitorOpenapi({
method: 'GET',
path: '/{monitorId}/data',
})
)
.input( .input(
z.object({ z.object({
monitorId: z.string().cuid2(), monitorId: z.string().cuid2(),
@ -92,6 +133,14 @@ export const monitorRouter = router({
endAt: z.number(), endAt: z.number(),
}) })
) )
.output(
z.array(
z.object({
value: z.number(),
createdAt: z.date(),
})
)
)
.query(async ({ input }) => { .query(async ({ input }) => {
const { monitorId, workspaceId, startAt, endAt } = input; const { monitorId, workspaceId, startAt, endAt } = input;
@ -113,12 +162,26 @@ export const monitorRouter = router({
}); });
}), }),
recentData: workspaceProcedure recentData: workspaceProcedure
.meta(
buildMonitorOpenapi({
method: 'GET',
path: '/{monitorId}/recentData',
})
)
.input( .input(
z.object({ z.object({
monitorId: z.string().cuid2(), monitorId: z.string().cuid2(),
take: z.number(), take: z.number(),
}) })
) )
.output(
z.array(
z.object({
value: z.number(),
createdAt: z.date(),
})
)
)
.query(async ({ input }) => { .query(async ({ input }) => {
const { monitorId, take } = input; const { monitorId, take } = input;
@ -134,11 +197,26 @@ export const monitorRouter = router({
}); });
}), }),
dataMetrics: workspaceProcedure dataMetrics: workspaceProcedure
.meta(
buildMonitorOpenapi({
method: 'GET',
path: '/{monitorId}/dataMetrics',
})
)
.input( .input(
z.object({ z.object({
monitorId: z.string().cuid2(), monitorId: z.string().cuid2(),
}) })
) )
.output(
z.object({
recent1DayAvg: z.number(),
recent1DayOnlineCount: z.number(),
recent1DayOfflineCount: z.number(),
recent30DayOnlineCount: z.number(),
recent30DayOfflineCount: z.number(),
})
)
.query(async ({ input }) => { .query(async ({ input }) => {
const { monitorId } = input; const { monitorId } = input;
const now = dayjs(); const now = dayjs();
@ -219,11 +297,18 @@ export const monitorRouter = router({
}; };
}), }),
events: workspaceProcedure events: workspaceProcedure
.meta(
buildMonitorOpenapi({
method: 'GET',
path: '/events',
})
)
.input( .input(
z.object({ z.object({
monitorId: z.string().cuid2().optional(), monitorId: z.string().cuid2().optional(),
}) })
) )
.output(z.array(monitorEventSchema))
.query(async ({ input }) => { .query(async ({ input }) => {
const { monitorId } = input; const { monitorId } = input;
@ -240,12 +325,19 @@ export const monitorRouter = router({
return list; return list;
}), }),
getStatus: workspaceProcedure getStatus: workspaceProcedure
.meta(
buildMonitorOpenapi({
method: 'GET',
path: '/{monitorId}/status',
})
)
.input( .input(
z.object({ z.object({
monitorId: z.string().cuid2(), monitorId: z.string().cuid2(),
statusName: z.string(), statusName: z.string(),
}) })
) )
.output(monitorStatusSchema.nullable())
.query(async ({ input }) => { .query(async ({ input }) => {
const { monitorId, statusName } = input; const { monitorId, statusName } = input;
@ -259,3 +351,14 @@ export const monitorRouter = router({
}); });
}), }),
}); });
function buildMonitorOpenapi(meta: OpenApiMetaInfo): OpenApiMeta {
return {
openapi: {
tags: [OPENAPI_TAG.MONITOR],
protect: true,
...meta,
path: `/workspace/{workspaceId}/monitor${meta.path}`,
},
};
}

View File

@ -118,6 +118,7 @@ export enum OPENAPI_TAG {
GLOBAL = 'Global', GLOBAL = 'Global',
USER = 'User', USER = 'User',
WEBSITE = 'Website', WEBSITE = 'Website',
MONITOR = 'Monitor',
} }
export const hostnameRegex = export const hostnameRegex =