feat: add usage button for telemetry

This commit is contained in:
moonrailgun 2024-03-03 18:51:10 +08:00
parent 18027170b8
commit daef9ff084
4 changed files with 81 additions and 13 deletions

View File

@ -33,6 +33,7 @@ It's good to specialize in one thing, if we are experts in related abilities we
- [ ] utm track - [ ] utm track
- [ ] waitlist - [ ] waitlist
- [ ] survey - [ ] survey
- [ ] lighthouse report
## Preview ## Preview

View File

@ -18,7 +18,6 @@ export const PageHeader: React.FC<{
)} )}
</div> </div>
<div className="text-2xl flex-1">{props.title}</div>
{props.action} {props.action}
</div> </div>
); );

View File

@ -1,11 +1,12 @@
import { Trans, t } from '@i18next-toolkit/react'; import { Trans, t } from '@i18next-toolkit/react';
import { Button, Form, Input, Modal, Table } from 'antd'; import { Button, Collapse, Form, Input, Modal, Table, Typography } from 'antd';
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import { AppRouterOutput, trpc } from '../../api/trpc'; import { AppRouterOutput, trpc } from '../../api/trpc';
import { useCurrentWorkspaceId } from '../../store/user'; import { useCurrentWorkspaceId } from '../../store/user';
import { type ColumnsType } from 'antd/es/table/interface'; import { type ColumnsType } from 'antd/es/table/interface';
import { import {
BarChartOutlined, BarChartOutlined,
CodeOutlined,
EditOutlined, EditOutlined,
PlusOutlined, PlusOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
@ -18,10 +19,11 @@ type TelemetryInfo = AppRouterOutput['telemetry']['all'][number];
export const TelemetryList: React.FC = React.memo(() => { export const TelemetryList: React.FC = React.memo(() => {
const workspaceId = useCurrentWorkspaceId(); const workspaceId = useCurrentWorkspaceId();
const [isModalOpen, setIsModalOpen] = useState(false); const [isEditModalOpen, setIsEditModalOpen] = useState(false);
const [form] = Form.useForm<{ id?: string; name: string }>(); const [form] = Form.useForm<{ id?: string; name: string }>();
const upsertTelemetryMutation = trpc.telemetry.upsert.useMutation(); const upsertTelemetryMutation = trpc.telemetry.upsert.useMutation();
const utils = trpc.useUtils(); const utils = trpc.useUtils();
const [modal, contextHolder] = Modal.useModal();
const handleAddTelemetry = useEvent(async () => { const handleAddTelemetry = useEvent(async () => {
await form.validateFields(); await form.validateFields();
@ -35,13 +37,67 @@ export const TelemetryList: React.FC = React.memo(() => {
utils.telemetry.all.refetch(); utils.telemetry.all.refetch();
setIsModalOpen(false); setIsEditModalOpen(false);
form.resetFields(); form.resetFields();
}); });
const handleShowUsage = useEvent((info: TelemetryInfo) => {
const blankGif = `${window.location.origin}/telemetry/${workspaceId}/${info.id}.gif`;
const countBadgeUrl = `${window.location.origin}/telemetry/${workspaceId}/${info.id}/badge.svg`;
modal.info({
maskClosable: true,
title: 'How to Use Telemetry',
content: (
<div>
<p>Here is some way to use telemetry:</p>
<h2>Insert to article:</h2>
<p>
if your article support raw html, you can direct insert it{' '}
<Typography.Text code={true} copyable={{ text: blankGif }}>
{blankGif}
</Typography.Text>
</p>
<Collapse
ghost
items={[
{
label: 'Advanced',
children: (
<div>
<p>
Some website will not allow send `referer` field. so its
maybe can not track source. so you can mark it by
yourself. for example:
</p>
<p>
<Typography.Text code={true}>
{blankGif}?url=https://xxxxxxxx
</Typography.Text>
</p>
</div>
),
},
]}
/>
<h2>Count your website visitor:</h2>
<p>
if your article support raw html, you can direct insert it{' '}
<Typography.Text code={true} copyable={{ text: blankGif }}>
{countBadgeUrl}
</Typography.Text>
</p>
<p>
Like this: <img src={countBadgeUrl} />
</p>
</div>
),
});
});
const handleEditTelemetry = useEvent(async (info: TelemetryInfo) => { const handleEditTelemetry = useEvent(async (info: TelemetryInfo) => {
setIsModalOpen(true); setIsEditModalOpen(true);
form.setFieldsValue({ form.setFieldsValue({
id: info.id, id: info.id,
name: info.name, name: info.name,
@ -87,7 +143,7 @@ export const TelemetryList: React.FC = React.memo(() => {
type="primary" type="primary"
icon={<PlusOutlined />} icon={<PlusOutlined />}
size="large" size="large"
onClick={() => setIsModalOpen(true)} onClick={() => setIsEditModalOpen(true)}
> >
{t('Add Telemetry')} {t('Add Telemetry')}
</Button> </Button>
@ -95,16 +151,19 @@ export const TelemetryList: React.FC = React.memo(() => {
} }
/> />
<TelemetryListTable onEdit={handleEditTelemetry} /> <TelemetryListTable
onShowUsage={handleShowUsage}
onEdit={handleEditTelemetry}
/>
<Modal <Modal
title={t('Add Telemetry')} title={t('Add Telemetry')}
open={isModalOpen} open={isEditModalOpen}
okButtonProps={{ okButtonProps={{
loading: upsertTelemetryMutation.isLoading, loading: upsertTelemetryMutation.isLoading,
}} }}
onOk={() => handleAddTelemetry()} onOk={() => handleAddTelemetry()}
onCancel={() => setIsModalOpen(false)} onCancel={() => setIsEditModalOpen(false)}
> >
<Form layout="vertical" form={form}> <Form layout="vertical" form={form}>
<Form.Item name="id" hidden={true} /> <Form.Item name="id" hidden={true} />
@ -118,6 +177,8 @@ export const TelemetryList: React.FC = React.memo(() => {
</Form.Item> </Form.Item>
</Form> </Form>
</Modal> </Modal>
{contextHolder}
</div> </div>
); );
}); });
@ -125,6 +186,7 @@ TelemetryList.displayName = 'TelemetryList';
const TelemetryListTable: React.FC<{ const TelemetryListTable: React.FC<{
onEdit: (info: TelemetryInfo) => void; onEdit: (info: TelemetryInfo) => void;
onShowUsage: (info: TelemetryInfo) => void;
}> = React.memo((props) => { }> = React.memo((props) => {
const workspaceId = useCurrentWorkspaceId(); const workspaceId = useCurrentWorkspaceId();
const { data = [], isLoading } = trpc.telemetry.all.useQuery({ const { data = [], isLoading } = trpc.telemetry.all.useQuery({
@ -155,6 +217,12 @@ const TelemetryListTable: React.FC<{
render: (_, record) => { render: (_, record) => {
return ( return (
<div className="flex gap-2 justify-end"> <div className="flex gap-2 justify-end">
<Button
icon={<CodeOutlined />}
onClick={() => props.onShowUsage(record)}
>
{t('Usage')}
</Button>
<Button <Button
icon={<EditOutlined />} icon={<EditOutlined />}
onClick={() => props.onEdit(record)} onClick={() => props.onEdit(record)}

View File

@ -19,13 +19,13 @@ export async function recordTelemetryEvent(req: Request) {
} }
const eventName = name ? String(name) : undefined; const eventName = name ? String(name) : undefined;
const session = await findSession(req, url); const workspaceId = req.params.workspaceId;
if (!session) { if (!workspaceId) {
return; return;
} }
const workspaceId = req.params.workspaceId; const session = await findSession(req, url);
if (!workspaceId) { if (!session) {
return; return;
} }