Skip to content

Commit

Permalink
feat: add monitor badge #6
Browse files Browse the repository at this point in the history
  • Loading branch information
moonrailgun committed Jan 6, 2024
1 parent 19e7ed5 commit 3e9760d
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 1 deletion.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"colord": "^2.9.3",
"compose-middleware": "^5.0.1",
"compression": "^1.7.4",
"copy-to-clipboard": "^3.3.3",
"cors": "^2.8.5",
"croner": "^7.0.1",
"dayjs": "^1.11.9",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 101 additions & 0 deletions src/client/components/monitor/MonitorBadgeView.tsx
Original file line number Diff line number Diff line change
@@ -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';
33 changes: 32 additions & 1 deletion src/client/components/monitor/MonitorInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import { MonitorEventList } from './MonitorEventList';
import { useEvent } from '../../hooks/useEvent';
import { MonitorDataMetrics } from './MonitorDataMetrics';
import { MonitorDataChart } from './MonitorDataChart';
import { DeleteOutlined } from '@ant-design/icons';
import { DeleteOutlined, MoreOutlined } from '@ant-design/icons';
import { MonitorBadgeView } from './MonitorBadgeView';

interface MonitorInfoProps {
monitorId: string;
Expand All @@ -29,6 +30,7 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
const { monitorId } = props;
const [currectResponse, setCurrentResponse] = useState(0);
const navigate = useNavigate();
const [showBadge, setShowBadge] = useState(false);

const {
data: monitorInfo,
Expand Down Expand Up @@ -209,6 +211,35 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
>
<Button danger={true}>Delete</Button>
</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>

<Card>
Expand Down
2 changes: 2 additions & 0 deletions src/server/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import cors from 'cors';
import { serverStatusRouter } from './router/serverStatus';
import { initCronjob } from './cronjob';
import { logger } from './utils/logger';
import { monitorRouter } from './router/monitor';

const port = settings.port;

Expand Down Expand Up @@ -57,6 +58,7 @@ app.use(

app.use('/api/website', websiteRouter);
app.use('/api/workspace', workspaceRouter);
app.use('/monitor', monitorRouter);
app.use('/telemetry', telemetryRouter);
app.use('/serverStatus', serverStatusRouter);

Expand Down
39 changes: 39 additions & 0 deletions src/server/router/monitor.ts
Original file line number Diff line number Diff line change
@@ -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);
}
);

0 comments on commit 3e9760d

Please sign in to comment.