feat: add monitor bind website

This commit is contained in:
moonrailgun 2023-10-15 00:51:03 +08:00
parent df7d18c2a0
commit 194103eb2d
10 changed files with 89 additions and 22 deletions

View File

@ -63,6 +63,7 @@
"request-ip": "^3.3.0",
"socket.io": "^4.7.2",
"socket.io-client": "^4.7.2",
"str2int": "^1.1.0",
"ts-node": "^10.9.1",
"uuid": "^9.0.0",
"vite-express": "^0.10.0",

View File

@ -142,6 +142,9 @@ dependencies:
socket.io-client:
specifier: ^4.7.2
version: 4.7.2
str2int:
specifier: ^1.1.0
version: 1.1.0
ts-node:
specifier: ^10.9.1
version: 10.9.1(@types/node@18.17.12)(typescript@5.2.2)
@ -6263,6 +6266,10 @@ packages:
engines: {node: '>= 0.8'}
dev: false
/str2int@1.1.0:
resolution: {integrity: sha512-Eb9eGdySBmA2cQyJaxsiB9a6IJ7t1RCQK6o3pUZf6dTI3CVq9TkMcUCVNoWeonv7mNza3Hcp3cf1j73vEhL4ag==}
dev: false
/streamx@2.15.1:
resolution: {integrity: sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==}
dependencies:

View File

@ -54,16 +54,18 @@ model WorkspacesOnUsers {
model Website {
id String @id @unique @default(cuid()) @db.VarChar(30)
workspaceId String @db.VarChar(30)
name String @db.VarChar(100)
domain String? @db.VarChar(500)
shareId String? @unique @db.VarChar(50)
resetAt DateTime? @db.Timestamptz(6)
workspaceId String @db.VarChar(30)
monitorId String? @db.VarChar(30)
createdAt DateTime @default(now()) @db.Timestamptz(6)
updatedAt DateTime @updatedAt @db.Timestamptz(6)
deletedAt DateTime? @db.Timestamptz(6)
workspace Workspace @relation(fields: [workspaceId], references: [id], onUpdate: Cascade, onDelete: Cascade)
monitor Monitor? @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade)
sessions WebsiteSession[]
eventData WebsiteEventData[]
@ -242,6 +244,7 @@ model Monitor {
workspace Workspace @relation(fields: [workspaceId], references: [id])
websites Website[]
notifications Notification[]
events MonitorEvent[]
datas MonitorData[]

View File

@ -3,18 +3,9 @@ import { DateUnit } from '../../utils/date';
import { queryClient } from '../cache';
import { request } from '../request';
import { getUserTimezone } from './user';
import { Website as WebsiteInfo } from '@prisma/client';
export interface WebsiteInfo {
id: string;
name: string;
domain: string | null;
shareId: string | null;
resetAt: string | null;
workspaceId: string;
createdAt: string | null;
updatedAt: string | null;
deletedAt: string | null;
}
export type { WebsiteInfo };
export async function getWorkspaceWebsites(
workspaceId: string

View File

@ -0,0 +1,29 @@
import { Tag } from 'antd';
import React, { useMemo } from 'react';
import str2int from 'str2int';
const builtinColors = [
'magenta',
'red',
'volcano',
'orange',
'gold',
'lime',
'green',
'cyan',
'blue',
'geekblue',
'purple',
];
export const ColorTag: React.FC<{ label: string; colors?: string[] }> =
React.memo((props) => {
const { label, colors = builtinColors } = props;
const color = useMemo(
() => colors[str2int(label) % colors.length],
[label]
);
return <Tag color={color}>{label}</Tag>;
});
ColorTag.displayName = 'ColorTag';

View File

@ -10,6 +10,7 @@ import { useCurrentWorkspaceId } from '../store/user';
import { ErrorTip } from './ErrorTip';
import { Loading } from './Loading';
import { NoWorkspaceTip } from './NoWorkspaceTip';
import { MonitorPicker } from './monitor/MonitorPicker';
import { defaultErrorHandler, defaultSuccessHandler, trpc } from '../api/trpc';
import { useQueryClient } from '@tanstack/react-query';
import { useEvent } from '../hooks/useEvent';
@ -35,12 +36,13 @@ export const WebsiteInfo: React.FC = React.memo(() => {
});
const handleSave = useEvent(
async (values: { name: string; domain: string }) => {
async (values: { name: string; domain: string; monitorId: string }) => {
await updateMutation.mutateAsync({
workspaceId,
websiteId: websiteId!,
name: values.name,
domain: values.domain,
monitorId: values.monitorId,
});
}
);
@ -84,6 +86,7 @@ export const WebsiteInfo: React.FC = React.memo(() => {
id: website.id,
name: website.name,
domain: website.domain,
monitorId: website.monitorId,
}}
onFinish={handleSave}
>
@ -101,6 +104,10 @@ export const WebsiteInfo: React.FC = React.memo(() => {
<Input size="large" />
</Form.Item>
<Form.Item label="Monitor" name="monitorId">
<MonitorPicker size="large" allowClear={true} />
</Form.Item>
<Form.Item>
<Button size="large" htmlType="submit">
Save

View File

@ -1,4 +1,4 @@
import { Card, Select, Space, Tag } from 'antd';
import { Card, Select, Space } from 'antd';
import dayjs, { Dayjs } from 'dayjs';
import React, { useMemo, useState } from 'react';
import { trpc } from '../../api/trpc';
@ -12,6 +12,7 @@ import { MonitorHealthBar } from './MonitorHealthBar';
import { useSocketSubscribeList } from '../../api/socketio';
import { last, uniqBy } from 'lodash-es';
import { ErrorTip } from '../ErrorTip';
import { ColorTag } from '../ColorTag';
interface MonitorInfoProps {
monitorId: string;
@ -42,7 +43,7 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
<div className="text-2xl">{monitorInfo.name}</div>
<div>
<Tag color="cyan">{monitorInfo.type}</Tag>
<ColorTag label={monitorInfo.type} />
<span>
{getMonitorLink(monitorInfo as any as MonitorInfoType)}
</span>

View File

@ -0,0 +1,27 @@
import { Select, SelectProps } from 'antd';
import React from 'react';
import { trpc } from '../../api/trpc';
import { useCurrentWorkspaceId } from '../../store/user';
import { ColorTag } from '../ColorTag';
interface MonitorPickerProps extends SelectProps<string> {}
export const MonitorPicker: React.FC<MonitorPickerProps> = React.memo(
(props) => {
const workspaceId = useCurrentWorkspaceId();
const { data: allMonitor = [] } = trpc.monitor.all.useQuery({
workspaceId,
});
return (
<Select {...props}>
{allMonitor.map((m) => (
<Select.Option key={m.id} value={m.id}>
<ColorTag label={m.type} />
{m.name}
</Select.Option>
))}
</Select>
);
}
);
MonitorPicker.displayName = 'MonitorPicker';

View File

@ -24,6 +24,7 @@ import { formatNumber, formatShortTime } from '../../utils/common';
import { useTheme } from '../../hooks/useTheme';
import { WebsiteOnlineCount } from '../WebsiteOnlineCount';
import { useGlobalRangeDate } from '../../hooks/useGlobalRangeDate';
import { MonitorHealthBar } from '../monitor/MonitorHealthBar';
export const WebsiteOverview: React.FC<{
website: WebsiteInfo;
@ -81,11 +82,9 @@ export const WebsiteOverview: React.FC<{
{props.website.name}
</span>
<HealthBar
beats={Array.from({ length: 13 }).map(() => ({
status: 'health',
}))}
/>
{props.website.monitorId && (
<MonitorHealthBar monitorId={props.website.monitorId} />
)}
<div className="ml-4 text-base font-normal">
<WebsiteOnlineCount

View File

@ -157,13 +157,14 @@ export const websiteRouter = router({
updateInfo: workspaceOwnerProcedure
.input(
z.object({
websiteId: z.string().cuid(),
websiteId: z.string().cuid2(),
name: z.string().max(100),
domain: z.union([z.string().max(500).url(), z.string().max(500).ip()]),
monitorId: z.string().cuid2(),
})
)
.mutation(async ({ input }) => {
const { workspaceId, websiteId, name, domain } = input;
const { workspaceId, websiteId, name, domain, monitorId } = input;
const websiteInfo = await prisma.website.update({
where: {
@ -173,6 +174,7 @@ export const websiteRouter = router({
data: {
name,
domain,
monitorId,
},
});