feat: add monitor badge #6
This commit is contained in:
parent
19e7ed516b
commit
3e9760d895
@ -42,6 +42,7 @@
|
|||||||
"colord": "^2.9.3",
|
"colord": "^2.9.3",
|
||||||
"compose-middleware": "^5.0.1",
|
"compose-middleware": "^5.0.1",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
|
"copy-to-clipboard": "^3.3.3",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"croner": "^7.0.1",
|
"croner": "^7.0.1",
|
||||||
"dayjs": "^1.11.9",
|
"dayjs": "^1.11.9",
|
||||||
|
@ -61,6 +61,9 @@ dependencies:
|
|||||||
compression:
|
compression:
|
||||||
specifier: ^1.7.4
|
specifier: ^1.7.4
|
||||||
version: 1.7.4
|
version: 1.7.4
|
||||||
|
copy-to-clipboard:
|
||||||
|
specifier: ^3.3.3
|
||||||
|
version: 3.3.3
|
||||||
cors:
|
cors:
|
||||||
specifier: ^2.8.5
|
specifier: ^2.8.5
|
||||||
version: 2.8.5
|
version: 2.8.5
|
||||||
|
101
src/client/components/monitor/MonitorBadgeView.tsx
Normal file
101
src/client/components/monitor/MonitorBadgeView.tsx
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { Checkbox, Divider, Input, message } from 'antd';
|
||||||
|
import React, { useMemo, useState } from 'react';
|
||||||
|
import { useEvent } from '../../hooks/useEvent';
|
||||||
|
import copy from 'copy-to-clipboard';
|
||||||
|
|
||||||
|
export const MonitorBadgeView: React.FC<{
|
||||||
|
workspaceId: string;
|
||||||
|
monitorId: string;
|
||||||
|
}> = React.memo((props) => {
|
||||||
|
const { workspaceId, monitorId } = props;
|
||||||
|
|
||||||
|
const [showDetail, setShowDetail] = useState(false);
|
||||||
|
|
||||||
|
const url = useMemo(() => {
|
||||||
|
let url = `${window.location.origin}/monitor/${workspaceId}/${monitorId}/badge.svg`;
|
||||||
|
|
||||||
|
if (showDetail) {
|
||||||
|
url += `?showDetail=true`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}, [showDetail]);
|
||||||
|
|
||||||
|
const handleCopy = useEvent((text: string) => {
|
||||||
|
copy(text);
|
||||||
|
message.success('Copy success!');
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<img src={url} />
|
||||||
|
</div>
|
||||||
|
<p>This will show your recent result of your monitor</p>
|
||||||
|
<div>
|
||||||
|
<Checkbox
|
||||||
|
checked={showDetail}
|
||||||
|
onChange={(e) => setShowDetail(e.target.checked)}
|
||||||
|
>
|
||||||
|
Show Detail Number
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<p>Share with...</p>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<Input
|
||||||
|
addonBefore="HTML Embed"
|
||||||
|
value={`<img src="${url}" />`}
|
||||||
|
addonAfter={
|
||||||
|
<div
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => handleCopy(`<img src="${url}" />`)}
|
||||||
|
>
|
||||||
|
Copy
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
addonBefore="Markdown"
|
||||||
|
value={`![](${url})`}
|
||||||
|
addonAfter={
|
||||||
|
<div
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => handleCopy(`![](${url})`)}
|
||||||
|
>
|
||||||
|
Copy
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
addonBefore="BBCode"
|
||||||
|
value={`[img]${url}[/img]`}
|
||||||
|
addonAfter={
|
||||||
|
<div
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => handleCopy(`[img]${url}[/img]`)}
|
||||||
|
>
|
||||||
|
Copy
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
addonBefore="url"
|
||||||
|
value={url}
|
||||||
|
addonAfter={
|
||||||
|
<div className="cursor-pointer" onClick={() => handleCopy(url)}>
|
||||||
|
Copy
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
MonitorBadgeView.displayName = 'MonitorBadgeView';
|
@ -19,7 +19,8 @@ import { MonitorEventList } from './MonitorEventList';
|
|||||||
import { useEvent } from '../../hooks/useEvent';
|
import { useEvent } from '../../hooks/useEvent';
|
||||||
import { MonitorDataMetrics } from './MonitorDataMetrics';
|
import { MonitorDataMetrics } from './MonitorDataMetrics';
|
||||||
import { MonitorDataChart } from './MonitorDataChart';
|
import { MonitorDataChart } from './MonitorDataChart';
|
||||||
import { DeleteOutlined } from '@ant-design/icons';
|
import { DeleteOutlined, MoreOutlined } from '@ant-design/icons';
|
||||||
|
import { MonitorBadgeView } from './MonitorBadgeView';
|
||||||
|
|
||||||
interface MonitorInfoProps {
|
interface MonitorInfoProps {
|
||||||
monitorId: string;
|
monitorId: string;
|
||||||
@ -29,6 +30,7 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
|
|||||||
const { monitorId } = props;
|
const { monitorId } = props;
|
||||||
const [currectResponse, setCurrentResponse] = useState(0);
|
const [currectResponse, setCurrentResponse] = useState(0);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [showBadge, setShowBadge] = useState(false);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: monitorInfo,
|
data: monitorInfo,
|
||||||
@ -209,6 +211,35 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
|
|||||||
>
|
>
|
||||||
<Button danger={true}>Delete</Button>
|
<Button danger={true}>Delete</Button>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
|
|
||||||
|
<Dropdown
|
||||||
|
trigger={['click']}
|
||||||
|
placement="bottomRight"
|
||||||
|
menu={{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
key: 'badge',
|
||||||
|
label: 'Show Badge',
|
||||||
|
onClick: () => setShowBadge(true),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button icon={<MoreOutlined />} />
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
open={showBadge}
|
||||||
|
onCancel={() => setShowBadge(false)}
|
||||||
|
onOk={() => setShowBadge(false)}
|
||||||
|
destroyOnClose={true}
|
||||||
|
centered={true}
|
||||||
|
>
|
||||||
|
<MonitorBadgeView
|
||||||
|
workspaceId={workspaceId}
|
||||||
|
monitorId={monitorId}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
|
@ -25,6 +25,7 @@ import cors from 'cors';
|
|||||||
import { serverStatusRouter } from './router/serverStatus';
|
import { serverStatusRouter } from './router/serverStatus';
|
||||||
import { initCronjob } from './cronjob';
|
import { initCronjob } from './cronjob';
|
||||||
import { logger } from './utils/logger';
|
import { logger } from './utils/logger';
|
||||||
|
import { monitorRouter } from './router/monitor';
|
||||||
|
|
||||||
const port = settings.port;
|
const port = settings.port;
|
||||||
|
|
||||||
@ -57,6 +58,7 @@ app.use(
|
|||||||
|
|
||||||
app.use('/api/website', websiteRouter);
|
app.use('/api/website', websiteRouter);
|
||||||
app.use('/api/workspace', workspaceRouter);
|
app.use('/api/workspace', workspaceRouter);
|
||||||
|
app.use('/monitor', monitorRouter);
|
||||||
app.use('/telemetry', telemetryRouter);
|
app.use('/telemetry', telemetryRouter);
|
||||||
app.use('/serverStatus', serverStatusRouter);
|
app.use('/serverStatus', serverStatusRouter);
|
||||||
|
|
||||||
|
39
src/server/router/monitor.ts
Normal file
39
src/server/router/monitor.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import { param, validate, query } from '../middleware/validate';
|
||||||
|
import { numify } from '../utils/common';
|
||||||
|
import { makeBadge } from 'badge-maker';
|
||||||
|
import { getMonitorPublicInfos, getMonitorRecentData } from '../model/monitor';
|
||||||
|
import { checkEnvTrusty } from '../utils/env';
|
||||||
|
|
||||||
|
export const monitorRouter = Router();
|
||||||
|
|
||||||
|
monitorRouter.get(
|
||||||
|
'/:workspaceId/:monitorId/badge.svg',
|
||||||
|
validate(
|
||||||
|
param('workspaceId').isString(),
|
||||||
|
param('monitorId').isString(),
|
||||||
|
query('showDetail').optional().isString()
|
||||||
|
),
|
||||||
|
async (req, res) => {
|
||||||
|
const { workspaceId, monitorId } = req.params;
|
||||||
|
const showDetail = checkEnvTrusty(String(req.query.showDetail));
|
||||||
|
|
||||||
|
const [info] = await getMonitorPublicInfos([monitorId]);
|
||||||
|
const [{ value }] = await getMonitorRecentData(workspaceId, monitorId, 1);
|
||||||
|
|
||||||
|
const svg =
|
||||||
|
value >= 0
|
||||||
|
? makeBadge({
|
||||||
|
label: info.name,
|
||||||
|
message: showDetail ? numify(value) : 'Health',
|
||||||
|
color: 'green',
|
||||||
|
})
|
||||||
|
: makeBadge({
|
||||||
|
label: info.name,
|
||||||
|
message: 'Error',
|
||||||
|
color: 'red',
|
||||||
|
});
|
||||||
|
|
||||||
|
res.header('Content-Type', 'image/svg+xml').send(svg);
|
||||||
|
}
|
||||||
|
);
|
Loading…
Reference in New Issue
Block a user