diff --git a/src/client/App.tsx b/src/client/App.tsx
index a42aec5..7d4844c 100644
--- a/src/client/App.tsx
+++ b/src/client/App.tsx
@@ -9,7 +9,7 @@ import { Register } from './pages/Register';
import { QueryClientProvider } from '@tanstack/react-query';
import { queryClient } from './api/cache';
import { TokenLoginContainer } from './components/TokenLoginContainer';
-import React, { Suspense, useRef } from 'react';
+import React, { useRef } from 'react';
import { trpc, trpcClient } from './api/trpc';
import { MonitorPage } from './pages/Monitor';
import { WebsitePage } from './pages/Website';
@@ -19,7 +19,7 @@ import { ConfigProvider, theme } from 'antd';
import clsx from 'clsx';
import { useSettingsStore } from './store/settings';
import { StatusPage } from './pages/Status';
-import { Loading } from './components/Loading';
+import { TelemetryPage } from './pages/Telemetry';
export const AppRoutes: React.FC = React.memo(() => {
const { info } = useUserStore();
@@ -35,6 +35,7 @@ export const AppRoutes: React.FC = React.memo(() => {
} />
} />
} />
+ } />
} />
) : (
diff --git a/src/client/components/telemetry/TelemetryList.tsx b/src/client/components/telemetry/TelemetryList.tsx
new file mode 100644
index 0000000..5aae552
--- /dev/null
+++ b/src/client/components/telemetry/TelemetryList.tsx
@@ -0,0 +1,146 @@
+import { t } from '@i18next-toolkit/react';
+import { Button, Form, Input, Modal, Table } from 'antd';
+import React, { useMemo, useState } from 'react';
+import { AppRouterOutput, trpc } from '../../api/trpc';
+import { useCurrentWorkspaceId } from '../../store/user';
+import { type ColumnsType } from 'antd/es/table/interface';
+import {
+ BarChartOutlined,
+ EditOutlined,
+ PlusOutlined,
+} from '@ant-design/icons';
+import { useNavigate } from 'react-router';
+import { PageHeader } from '../PageHeader';
+import { useEvent } from '../../hooks/useEvent';
+
+type TelemetryInfo = AppRouterOutput['telemetry']['all'][number];
+
+export const TelemetryList: React.FC = React.memo(() => {
+ const workspaceId = useCurrentWorkspaceId();
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [form] = Form.useForm<{ id?: string; name: string }>();
+ const upsertTelemetryMutation = trpc.telemetry.upsert.useMutation();
+ const utils = trpc.useUtils();
+
+ const handleAddTelemetry = useEvent(async () => {
+ await form.validateFields();
+ const values = form.getFieldsValue();
+
+ await upsertTelemetryMutation.mutateAsync({
+ telemetryId: values.id,
+ workspaceId,
+ name: values.name,
+ });
+
+ utils.telemetry.all.refetch();
+
+ setIsModalOpen(false);
+
+ form.resetFields();
+ });
+
+ const handleEditTelemetry = useEvent(async (info: TelemetryInfo) => {
+ setIsModalOpen(true);
+ form.setFieldsValue({
+ id: info.id,
+ name: info.name,
+ });
+ });
+
+ return (
+
+
+ }
+ size="large"
+ onClick={() => setIsModalOpen(true)}
+ >
+ {t('Add Telemetry')}
+
+
+ }
+ />
+
+
+
+ handleAddTelemetry()}
+ onCancel={() => setIsModalOpen(false)}
+ >
+
+
+
+
+
+
+
+ );
+});
+TelemetryList.displayName = 'TelemetryList';
+
+const TelemetryListTable: React.FC<{
+ onEdit: (info: TelemetryInfo) => void;
+}> = React.memo((props) => {
+ const workspaceId = useCurrentWorkspaceId();
+ const { data = [], isLoading } = trpc.telemetry.all.useQuery({
+ workspaceId,
+ });
+ const navigate = useNavigate();
+
+ const columns = useMemo((): ColumnsType => {
+ return [
+ {
+ dataIndex: 'name',
+ title: t('Name'),
+ },
+ {
+ key: 'action',
+ render: (_, record) => {
+ return (
+
+ }
+ onClick={() => props.onEdit(record)}
+ >
+ {t('Edit')}
+
+ }
+ onClick={() => {
+ navigate(`/telemetry/${record.id}`);
+ }}
+ >
+ {t('View')}
+
+
+ );
+ },
+ },
+ ] as ColumnsType;
+ }, []);
+
+ return (
+
+ );
+});
+TelemetryListTable.displayName = 'TelemetryListTable';
diff --git a/src/client/pages/Layout.tsx b/src/client/pages/Layout.tsx
index 3a627c2..22c2c93 100644
--- a/src/client/pages/Layout.tsx
+++ b/src/client/pages/Layout.tsx
@@ -12,6 +12,7 @@ import { useIsMobile } from '../hooks/useIsMobile';
import { RiMenuUnfoldLine } from 'react-icons/ri';
import { useTranslation } from '@i18next-toolkit/react';
import { LanguageSelector } from '../components/LanguageSelector';
+import { useGlobalConfig } from '../hooks/useConfig';
export const Layout: React.FC = React.memo(() => {
const [params] = useSearchParams();
@@ -34,6 +35,7 @@ export const Layout: React.FC = React.memo(() => {
const showHeader = !params.has('hideHeader');
const navigate = useNavigate();
const { t } = useTranslation();
+ const { alphaMode } = useGlobalConfig();
const accountEl = (
{
label={t('Servers')}
onClick={() => setOpenDraw(false)}
/>
+ {alphaMode && (
+ setOpenDraw(false)}
+ />
+ )}
+
{
+
diff --git a/src/client/pages/Telemetry/index.tsx b/src/client/pages/Telemetry/index.tsx
new file mode 100644
index 0000000..76b7c71
--- /dev/null
+++ b/src/client/pages/Telemetry/index.tsx
@@ -0,0 +1,7 @@
+import React from 'react';
+import { TelemetryList } from '../../components/telemetry/TelemetryList';
+
+export const TelemetryPage: React.FC = React.memo(() => {
+ return ;
+});
+TelemetryPage.displayName = 'TelemetryPage';
diff --git a/src/server/prisma/migrations/20240217104338_add_named_telemetry_list/migration.sql b/src/server/prisma/migrations/20240217104338_add_named_telemetry_list/migration.sql
new file mode 100644
index 0000000..7d4644a
--- /dev/null
+++ b/src/server/prisma/migrations/20240217104338_add_named_telemetry_list/migration.sql
@@ -0,0 +1,35 @@
+-- AlterTable
+ALTER TABLE "TelemetryEvent" ADD COLUMN "telemetryId" VARCHAR(30);
+
+-- AlterTable
+ALTER TABLE "TelemetrySession" ADD COLUMN "telemetryId" VARCHAR(30);
+
+-- CreateTable
+CREATE TABLE "Telemetry" (
+ "id" VARCHAR(30) NOT NULL,
+ "workspaceId" VARCHAR(30) NOT NULL,
+ "name" VARCHAR(100) NOT NULL,
+ "createdAt" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMPTZ(6) NOT NULL,
+ "deletedAt" TIMESTAMPTZ(6),
+
+ CONSTRAINT "Telemetry_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Telemetry_id_key" ON "Telemetry"("id");
+
+-- CreateIndex
+CREATE INDEX "Telemetry_workspaceId_idx" ON "Telemetry"("workspaceId");
+
+-- CreateIndex
+CREATE INDEX "Telemetry_createdAt_idx" ON "Telemetry"("createdAt");
+
+-- AddForeignKey
+ALTER TABLE "Telemetry" ADD CONSTRAINT "Telemetry_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "TelemetrySession" ADD CONSTRAINT "TelemetrySession_telemetryId_fkey" FOREIGN KEY ("telemetryId") REFERENCES "Telemetry"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "TelemetryEvent" ADD CONSTRAINT "TelemetryEvent_telemetryId_fkey" FOREIGN KEY ("telemetryId") REFERENCES "Telemetry"("id") ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/src/server/prisma/schema.prisma b/src/server/prisma/schema.prisma
index ef2352c..f6a338b 100644
--- a/src/server/prisma/schema.prisma
+++ b/src/server/prisma/schema.prisma
@@ -49,6 +49,7 @@ model Workspace {
notifications Notification[]
monitors Monitor[]
monitorStatusPages MonitorStatusPage[]
+ telemetryList Telemetry[]
// for user currentWorkspace
selectedUsers User[] // user list who select this workspace, not use in most of case
@@ -201,9 +202,27 @@ model WebsiteSessionData {
@@index([sessionId])
}
+model Telemetry {
+ id String @id @unique @default(cuid()) @db.VarChar(30)
+ workspaceId String @db.VarChar(30)
+ name String @db.VarChar(100)
+ 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)
+
+ sessions TelemetrySession[]
+ events TelemetryEvent[]
+
+ @@index([workspaceId])
+ @@index([createdAt])
+}
+
model TelemetrySession {
id String @id @unique @db.Uuid
workspaceId String @db.VarChar(30)
+ telemetryId String? @db.VarChar(30) // if null, means Default
hostname String? @db.VarChar(100)
browser String? @db.VarChar(20)
os String? @db.VarChar(20)
@@ -217,6 +236,7 @@ model TelemetrySession {
accuracyRadius Int?
createdAt DateTime @default(now()) @db.Timestamptz(6)
+ telemetry Telemetry? @relation(fields: [telemetryId], references: [id], onUpdate: Cascade, onDelete: Cascade)
telemetryEvent TelemetryEvent[]
@@index([createdAt])
@@ -225,8 +245,9 @@ model TelemetrySession {
model TelemetryEvent {
id String @id() @default(cuid()) @db.VarChar(30)
- sessionId String @db.Uuid
workspaceId String @db.VarChar(30)
+ telemetryId String? @db.VarChar(30) // if null, means Default
+ sessionId String @db.Uuid
eventName String? @db.VarChar(100)
urlOrigin String @db.VarChar(500)
urlPath String @db.VarChar(500)
@@ -236,7 +257,8 @@ model TelemetryEvent {
payload Json? @db.Json // Other payload info get from query params, should be a object
createdAt DateTime @default(now()) @db.Timestamptz(6)
- session TelemetrySession @relation(fields: [sessionId], references: [id], onUpdate: Cascade, onDelete: Cascade)
+ telemetry Telemetry? @relation(fields: [telemetryId], references: [id], onUpdate: Cascade, onDelete: Cascade)
+ session TelemetrySession @relation(fields: [sessionId], references: [id], onUpdate: Cascade, onDelete: Cascade)
@@index([createdAt])
@@index([sessionId])
diff --git a/src/server/prisma/zod/index.ts b/src/server/prisma/zod/index.ts
index e9c5a6f..6a65c69 100644
--- a/src/server/prisma/zod/index.ts
+++ b/src/server/prisma/zod/index.ts
@@ -6,6 +6,7 @@ export * from "./websitesession"
export * from "./websiteevent"
export * from "./websiteeventdata"
export * from "./websitesessiondata"
+export * from "./telemetry"
export * from "./telemetrysession"
export * from "./telemetryevent"
export * from "./notification"
diff --git a/src/server/prisma/zod/telemetry.ts b/src/server/prisma/zod/telemetry.ts
new file mode 100644
index 0000000..42d179d
--- /dev/null
+++ b/src/server/prisma/zod/telemetry.ts
@@ -0,0 +1,29 @@
+import * as z from "zod"
+import * as imports from "./schemas"
+import { CompleteWorkspace, RelatedWorkspaceModelSchema, CompleteTelemetrySession, RelatedTelemetrySessionModelSchema, CompleteTelemetryEvent, RelatedTelemetryEventModelSchema } from "./index"
+
+export const TelemetryModelSchema = z.object({
+ id: z.string(),
+ workspaceId: z.string(),
+ name: z.string(),
+ createdAt: z.date(),
+ updatedAt: z.date(),
+ deletedAt: z.date().nullish(),
+})
+
+export interface CompleteTelemetry extends z.infer {
+ workspace: CompleteWorkspace
+ sessions: CompleteTelemetrySession[]
+ events: CompleteTelemetryEvent[]
+}
+
+/**
+ * RelatedTelemetryModelSchema contains all relations on your model in addition to the scalars
+ *
+ * NOTE: Lazy required in case of potential circular dependencies within schema
+ */
+export const RelatedTelemetryModelSchema: z.ZodSchema = z.lazy(() => TelemetryModelSchema.extend({
+ workspace: RelatedWorkspaceModelSchema,
+ sessions: RelatedTelemetrySessionModelSchema.array(),
+ events: RelatedTelemetryEventModelSchema.array(),
+}))
diff --git a/src/server/prisma/zod/telemetryevent.ts b/src/server/prisma/zod/telemetryevent.ts
index 4aeb4f0..0ff0839 100644
--- a/src/server/prisma/zod/telemetryevent.ts
+++ b/src/server/prisma/zod/telemetryevent.ts
@@ -1,6 +1,6 @@
import * as z from "zod"
import * as imports from "./schemas"
-import { CompleteTelemetrySession, RelatedTelemetrySessionModelSchema } from "./index"
+import { CompleteTelemetry, RelatedTelemetryModelSchema, CompleteTelemetrySession, RelatedTelemetrySessionModelSchema } from "./index"
// Helper schema for JSON fields
type Literal = boolean | number | string
@@ -10,8 +10,9 @@ const jsonSchema: z.ZodSchema = z.lazy(() => z.union([literalSchema, z.arr
export const TelemetryEventModelSchema = z.object({
id: z.string(),
- sessionId: z.string(),
workspaceId: z.string(),
+ telemetryId: z.string().nullish(),
+ sessionId: z.string(),
eventName: z.string().nullish(),
urlOrigin: z.string(),
urlPath: z.string(),
@@ -23,6 +24,7 @@ export const TelemetryEventModelSchema = z.object({
})
export interface CompleteTelemetryEvent extends z.infer {
+ telemetry?: CompleteTelemetry | null
session: CompleteTelemetrySession
}
@@ -32,5 +34,6 @@ export interface CompleteTelemetryEvent extends z.infer = z.lazy(() => TelemetryEventModelSchema.extend({
+ telemetry: RelatedTelemetryModelSchema.nullish(),
session: RelatedTelemetrySessionModelSchema,
}))
diff --git a/src/server/prisma/zod/telemetrysession.ts b/src/server/prisma/zod/telemetrysession.ts
index f6ef3d0..f05edf9 100644
--- a/src/server/prisma/zod/telemetrysession.ts
+++ b/src/server/prisma/zod/telemetrysession.ts
@@ -1,10 +1,11 @@
import * as z from "zod"
import * as imports from "./schemas"
-import { CompleteTelemetryEvent, RelatedTelemetryEventModelSchema } from "./index"
+import { CompleteTelemetry, RelatedTelemetryModelSchema, CompleteTelemetryEvent, RelatedTelemetryEventModelSchema } from "./index"
export const TelemetrySessionModelSchema = z.object({
id: z.string(),
workspaceId: z.string(),
+ telemetryId: z.string().nullish(),
hostname: z.string().nullish(),
browser: z.string().nullish(),
os: z.string().nullish(),
@@ -20,6 +21,7 @@ export const TelemetrySessionModelSchema = z.object({
})
export interface CompleteTelemetrySession extends z.infer {
+ telemetry?: CompleteTelemetry | null
telemetryEvent: CompleteTelemetryEvent[]
}
@@ -29,5 +31,6 @@ export interface CompleteTelemetrySession extends z.infer = z.lazy(() => TelemetrySessionModelSchema.extend({
+ telemetry: RelatedTelemetryModelSchema.nullish(),
telemetryEvent: RelatedTelemetryEventModelSchema.array(),
}))
diff --git a/src/server/prisma/zod/workspace.ts b/src/server/prisma/zod/workspace.ts
index 73662fe..2e842f1 100644
--- a/src/server/prisma/zod/workspace.ts
+++ b/src/server/prisma/zod/workspace.ts
@@ -1,6 +1,6 @@
import * as z from "zod"
import * as imports from "./schemas"
-import { CompleteWorkspacesOnUsers, RelatedWorkspacesOnUsersModelSchema, CompleteWebsite, RelatedWebsiteModelSchema, CompleteNotification, RelatedNotificationModelSchema, CompleteMonitor, RelatedMonitorModelSchema, CompleteMonitorStatusPage, RelatedMonitorStatusPageModelSchema, CompleteUser, RelatedUserModelSchema, CompleteWorkspaceDailyUsage, RelatedWorkspaceDailyUsageModelSchema, CompleteWorkspaceAuditLog, RelatedWorkspaceAuditLogModelSchema } from "./index"
+import { CompleteWorkspacesOnUsers, RelatedWorkspacesOnUsersModelSchema, CompleteWebsite, RelatedWebsiteModelSchema, CompleteNotification, RelatedNotificationModelSchema, CompleteMonitor, RelatedMonitorModelSchema, CompleteMonitorStatusPage, RelatedMonitorStatusPageModelSchema, CompleteTelemetry, RelatedTelemetryModelSchema, CompleteUser, RelatedUserModelSchema, CompleteWorkspaceDailyUsage, RelatedWorkspaceDailyUsageModelSchema, CompleteWorkspaceAuditLog, RelatedWorkspaceAuditLogModelSchema } from "./index"
// Helper schema for JSON fields
type Literal = boolean | number | string
@@ -30,6 +30,7 @@ export interface CompleteWorkspace extends z.infer
notifications: CompleteNotification[]
monitors: CompleteMonitor[]
monitorStatusPages: CompleteMonitorStatusPage[]
+ telemetryList: CompleteTelemetry[]
selectedUsers: CompleteUser[]
workspaceDailyUsage: CompleteWorkspaceDailyUsage[]
workspaceAuditLog: CompleteWorkspaceAuditLog[]
@@ -46,6 +47,7 @@ export const RelatedWorkspaceModelSchema: z.ZodSchema = z.laz
notifications: RelatedNotificationModelSchema.array(),
monitors: RelatedMonitorModelSchema.array(),
monitorStatusPages: RelatedMonitorStatusPageModelSchema.array(),
+ telemetryList: RelatedTelemetryModelSchema.array(),
selectedUsers: RelatedUserModelSchema.array(),
workspaceDailyUsage: RelatedWorkspaceDailyUsageModelSchema.array(),
workspaceAuditLog: RelatedWorkspaceAuditLogModelSchema.array(),
diff --git a/src/server/trpc/routers/auditLog.ts b/src/server/trpc/routers/auditLog.ts
index de6efcd..a3a9315 100644
--- a/src/server/trpc/routers/auditLog.ts
+++ b/src/server/trpc/routers/auditLog.ts
@@ -1,20 +1,20 @@
import { z } from 'zod';
-import { router, workspaceProcedure } from '../trpc';
+import { OpenApiMetaInfo, router, workspaceProcedure } from '../trpc';
import { OPENAPI_TAG } from '../../utils/const';
import { WorkspaceAuditLogModelSchema } from '../../prisma/zod';
import { prisma } from '../../model/_client';
import { fetchDataByCursor } from '../../utils/prisma';
+import { OpenApiMeta } from 'trpc-openapi';
export const auditLogRouter = router({
fetchByCursor: workspaceProcedure
- .meta({
- openapi: {
+ .meta(
+ buildAuditLogOpenapi({
method: 'GET',
path: '/fetchByCursor',
- tags: [OPENAPI_TAG.AUDIT_LOG],
description: 'Fetch workspace audit log',
- },
- })
+ })
+ )
.input(
z.object({
limit: z.number().min(1).max(100).default(50),
@@ -47,3 +47,14 @@ export const auditLogRouter = router({
};
}),
});
+
+function buildAuditLogOpenapi(meta: OpenApiMetaInfo): OpenApiMeta {
+ return {
+ openapi: {
+ tags: [OPENAPI_TAG.AUDIT_LOG],
+ protect: true,
+ ...meta,
+ path: `/audit${meta.path}`,
+ },
+ };
+}
diff --git a/src/server/trpc/routers/billing.ts b/src/server/trpc/routers/billing.ts
index 07e35f0..d07f7a9 100644
--- a/src/server/trpc/routers/billing.ts
+++ b/src/server/trpc/routers/billing.ts
@@ -1,18 +1,18 @@
import { z } from 'zod';
-import { router, workspaceProcedure } from '../trpc';
+import { OpenApiMetaInfo, router, workspaceProcedure } from '../trpc';
import { OPENAPI_TAG } from '../../utils/const';
import { prisma } from '../../model/_client';
+import { OpenApiMeta } from 'trpc-openapi';
export const billingRouter = router({
usage: workspaceProcedure
- .meta({
- openapi: {
+ .meta(
+ buildBillingOpenapi({
method: 'GET',
path: '/usage',
- tags: [OPENAPI_TAG.BILLING],
description: 'get workspace usage',
- },
- })
+ })
+ )
.input(
z.object({
startAt: z.number(),
@@ -51,3 +51,14 @@ export const billingRouter = router({
};
}),
});
+
+function buildBillingOpenapi(meta: OpenApiMetaInfo): OpenApiMeta {
+ return {
+ openapi: {
+ tags: [OPENAPI_TAG.BILLING],
+ protect: true,
+ ...meta,
+ path: `/billing${meta.path}`,
+ },
+ };
+}
diff --git a/src/server/trpc/routers/index.ts b/src/server/trpc/routers/index.ts
index 8f5da64..93b753d 100644
--- a/src/server/trpc/routers/index.ts
+++ b/src/server/trpc/routers/index.ts
@@ -8,6 +8,7 @@ import { globalRouter } from './global';
import { serverStatusRouter } from './serverStatus';
import { auditLogRouter } from './auditLog';
import { billingRouter } from './billing';
+import { telemetryRouter } from './telemetry';
export const appRouter = router({
global: globalRouter,
@@ -16,6 +17,7 @@ export const appRouter = router({
website: websiteRouter,
notification: notificationRouter,
monitor: monitorRouter,
+ telemetry: telemetryRouter,
serverStatus: serverStatusRouter,
auditLog: auditLogRouter,
billing: billingRouter,
diff --git a/src/server/trpc/routers/telemetry.ts b/src/server/trpc/routers/telemetry.ts
new file mode 100644
index 0000000..df66c08
--- /dev/null
+++ b/src/server/trpc/routers/telemetry.ts
@@ -0,0 +1,83 @@
+import { z } from 'zod';
+import {
+ OpenApiMetaInfo,
+ router,
+ workspaceOwnerProcedure,
+ workspaceProcedure,
+} from '../trpc';
+import { OPENAPI_TAG } from '../../utils/const';
+import { prisma } from '../../model/_client';
+import { TelemetryModelSchema } from '../../prisma/zod';
+import { OpenApiMeta } from 'trpc-openapi';
+
+export const telemetryRouter = router({
+ all: workspaceProcedure
+ .meta(
+ buildTelemetryOpenapi({
+ method: 'GET',
+ path: '/all',
+ })
+ )
+ .output(z.array(TelemetryModelSchema))
+ .query(async ({ input }) => {
+ const { workspaceId } = input;
+
+ const res = await prisma.telemetry.findMany({
+ where: {
+ workspaceId,
+ },
+ orderBy: {
+ updatedAt: 'desc',
+ },
+ });
+
+ return res;
+ }),
+ upsert: workspaceOwnerProcedure
+ .meta(
+ buildTelemetryOpenapi({
+ method: 'POST',
+ path: '/upsert',
+ })
+ )
+ .input(
+ z.object({
+ telemetryId: z.string().optional(),
+ name: z.string(),
+ })
+ )
+ .output(TelemetryModelSchema)
+ .mutation(async ({ input }) => {
+ const { workspaceId, telemetryId, name } = input;
+
+ if (telemetryId) {
+ return prisma.telemetry.update({
+ where: {
+ id: telemetryId,
+ workspaceId,
+ },
+ data: {
+ name,
+ },
+ });
+ } else {
+ return prisma.telemetry.create({
+ data: {
+ workspaceId,
+ name,
+ },
+ });
+ }
+ }),
+});
+
+function buildTelemetryOpenapi(meta: OpenApiMetaInfo): OpenApiMeta {
+ return {
+ openapi: {
+ tags: [OPENAPI_TAG.TELEMETRY],
+ protect: true,
+ ...meta,
+ path: `/workspace/{workspaceId}${meta.path}`,
+ },
+ };
+}
diff --git a/src/server/utils/const.ts b/src/server/utils/const.ts
index 8b72749..92274f7 100644
--- a/src/server/utils/const.ts
+++ b/src/server/utils/const.ts
@@ -109,4 +109,5 @@ export enum OPENAPI_TAG {
MONITOR = 'Monitor',
AUDIT_LOG = 'AuditLog',
BILLING = 'Billing',
+ TELEMETRY = 'Telemetry',
}