diff --git a/.dockerignore b/.dockerignore index 75491515..b57dee0d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,4 +7,6 @@ node_modules npm-debug.log README.md .next -.git \ No newline at end of file +.git +tmp +converage \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0a535e05..3ae0537b 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,3 @@ { - "recommendations": [ - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", - "yoavbls.pretty-ts-errors" - ] + "recommendations": ["yoavbls.pretty-ts-errors"] } diff --git a/.vscode/settings.json b/.vscode/settings.json index d9aacae8..63692fe5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,21 +1,34 @@ { - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" + "prettier.enable": false, + "eslint.enable": false, + "files.associations": { + "*.css": "tailwindcss" + }, + "editor.codeActionsOnSave": { + "source.organizeImports.biome": "explicit" + }, + "[prisma]": { + "editor.defaultFormatter": "Prisma.prisma" + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[json]": { + "editor.defaultFormatter": "biomejs.biome" }, - "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, - "eslint.workingDirectories": [ - { "pattern": "apps/*/" }, - { "pattern": "packages/*/" }, - { "pattern": "tooling/*/" } + "tailwindCSS.experimental.configFile": "./packages/ui/tailwind.config.ts", + "tailwindCSS.experimental.classRegex": [ + ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], + ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] ], "typescript.enablePromptUseWorkspaceTsdk": true, "typescript.tsdk": "node_modules/typescript/lib", "typescript.preferences.autoImportFileExcludePatterns": [ "next/router.d.ts", "next/dist/client/router.d.ts" - ], - "[sql]": { - "editor.defaultFormatter": "adpyke.vscode-sql-formatter" - } + ] } diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile index 6e964915..57c31995 100644 --- a/apps/api/Dockerfile +++ b/apps/api/Dockerfile @@ -38,9 +38,6 @@ COPY packages/constants/package.json packages/constants/ COPY packages/validation/package.json packages/validation/ COPY packages/sdks/sdk/package.json packages/sdks/sdk/ -# Patches -COPY patches patches - # BUILD FROM base AS build diff --git a/apps/api/package.json b/apps/api/package.json index 14c042b2..923b1ffb 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -6,8 +6,6 @@ "testing": "API_PORT=3333 pnpm dev", "start": "node dist/index.js", "build": "rm -rf dist && tsup", - "lint": "eslint .", - "format": "prettier --check \"**/*.{mjs,ts,md,json}\"", "typecheck": "tsc --noEmit" }, "dependencies": { @@ -40,8 +38,6 @@ "zod": "^3.22.4" }, "devDependencies": { - "@openpanel/eslint-config": "workspace:*", - "@openpanel/prettier-config": "workspace:*", "@openpanel/sdk": "workspace:*", "@openpanel/tsconfig": "workspace:*", "@types/jsonwebtoken": "^9.0.6", @@ -51,16 +47,7 @@ "@types/ua-parser-js": "^0.7.39", "@types/uuid": "^9.0.8", "@types/ws": "^8.5.10", - "eslint": "^8.48.0", - "prettier": "^3.0.3", "tsup": "^7.2.0", "typescript": "^5.2.2" - }, - "eslintConfig": { - "root": true, - "extends": [ - "@openpanel/eslint-config/base" - ] - }, - "prettier": "@openpanel/prettier-config" -} \ No newline at end of file + } +} diff --git a/apps/api/scripts/get-referrers.ts b/apps/api/scripts/get-referrers.ts index e0934a00..e32e24ae 100644 --- a/apps/api/scripts/get-referrers.ts +++ b/apps/api/scripts/get-referrers.ts @@ -1,5 +1,5 @@ -import fs from 'fs'; -import path from 'path'; +import fs from 'node:fs'; +import path from 'node:path'; function transform(data: any) { const obj: Record = {}; @@ -22,7 +22,7 @@ async function main() { // Get document, or throw exception on error try { const data = await fetch( - 'https://s3-eu-west-1.amazonaws.com/snowplow-hosted-assets/third-party/referer-parser/referers-latest.json' + 'https://s3-eu-west-1.amazonaws.com/snowplow-hosted-assets/third-party/referer-parser/referers-latest.json', ).then((res) => res.json()); fs.writeFileSync( @@ -34,11 +34,11 @@ async function main() { `// The orginal referers.yml is based on Piwik's SearchEngines.php and Socials.php, copyright 2012 Matthieu Aubry and available under the GNU General Public License v3.`, '', `const referrers: Record = ${JSON.stringify( - transform(data) + transform(data), )} as const;`, 'export default referrers;', ].join('\n'), - 'utf-8' + 'utf-8', ); } catch (e) { console.log(e); diff --git a/apps/api/scripts/migrate-origins.ts b/apps/api/scripts/migrate-origins.ts index 0c8698bd..a88f5950 100644 --- a/apps/api/scripts/migrate-origins.ts +++ b/apps/api/scripts/migrate-origins.ts @@ -1,8 +1,8 @@ -import { ch, chQuery, TABLE_NAMES } from '@openpanel/db'; +import { TABLE_NAMES, ch, chQuery } from '@openpanel/db'; async function main() { const projects = await chQuery( - `SELECT distinct project_id FROM ${TABLE_NAMES.events} ORDER BY project_id` + `SELECT distinct project_id FROM ${TABLE_NAMES.events} ORDER BY project_id`, ); const withOrigin = []; @@ -10,10 +10,10 @@ async function main() { try { const [eventWithOrigin, eventWithoutOrigin] = await Promise.all([ await chQuery( - `SELECT * FROM ${TABLE_NAMES.events} WHERE origin != '' AND project_id = '${project.project_id}' ORDER BY created_at DESC LIMIT 1` + `SELECT * FROM ${TABLE_NAMES.events} WHERE origin != '' AND project_id = '${project.project_id}' ORDER BY created_at DESC LIMIT 1`, ), await chQuery( - `SELECT * FROM ${TABLE_NAMES.events} WHERE origin = '' AND project_id = '${project.project_id}' AND path != '' ORDER BY created_at DESC LIMIT 1` + `SELECT * FROM ${TABLE_NAMES.events} WHERE origin = '' AND project_id = '${project.project_id}' AND path != '' ORDER BY created_at DESC LIMIT 1`, ), ]); @@ -22,7 +22,7 @@ async function main() { console.log(`- Origin: ${eventWithOrigin[0].origin}`); withOrigin.push(project.project_id); const events = await chQuery( - `SELECT count(*) as count FROM ${TABLE_NAMES.events} WHERE project_id = '${project.project_id}' AND path != '' AND origin = ''` + `SELECT count(*) as count FROM ${TABLE_NAMES.events} WHERE project_id = '${project.project_id}' AND path != '' AND origin = ''`, ); console.log(`๐Ÿค ๐Ÿค ๐Ÿค ๐Ÿค  Will update ${events[0]?.count} events`); await ch.command({ @@ -35,20 +35,20 @@ async function main() { if (!eventWithOrigin[0] && eventWithoutOrigin[0]) { console.log( - `๐Ÿ˜ง Project ${project.project_id} has no events with origin (last event ${eventWithoutOrigin[0].created_at})` + `๐Ÿ˜ง Project ${project.project_id} has no events with origin (last event ${eventWithoutOrigin[0].created_at})`, ); console.log('- NO ORIGIN'); } if (!eventWithOrigin[0] && !eventWithoutOrigin[0]) { console.log( - `๐Ÿ”ฅ WARNING: Project ${project.project_id} has no events at all?!?!?!` + `๐Ÿ”ฅ WARNING: Project ${project.project_id} has no events at all?!?!?!`, ); } if (eventWithOrigin[0] && !eventWithoutOrigin[0]) { console.log( - `โœ… Project ${project.project_id} has all events with origin!!!` + `โœ… Project ${project.project_id} has all events with origin!!!`, ); } console.log(''); diff --git a/apps/api/src/controllers/event.controller.ts b/apps/api/src/controllers/event.controller.ts index 24e9ef11..9cd85151 100644 --- a/apps/api/src/controllers/event.controller.ts +++ b/apps/api/src/controllers/event.controller.ts @@ -1,7 +1,7 @@ import { getClientIp, parseIp } from '@/utils/parseIp'; import type { FastifyReply, FastifyRequest } from 'fastify'; -import { generateDeviceId } from '@openpanel/common'; +import { generateDeviceId } from '@openpanel/common/server'; import { getSalts } from '@openpanel/db'; import { eventsQueue } from '@openpanel/queue'; import { getRedisCache } from '@openpanel/redis'; @@ -13,7 +13,7 @@ export async function postEvent( request: FastifyRequest<{ Body: PostEventPayload; }>, - reply: FastifyReply + reply: FastifyReply, ) { const ip = getClientIp(request)!; const ua = request.headers['user-agent']!; @@ -44,7 +44,7 @@ export async function postEvent( 'locked', 'EX', 10, - 'NX' + 'NX', ); eventsQueue.add('event', { diff --git a/apps/api/src/controllers/export.controller.ts b/apps/api/src/controllers/export.controller.ts index 4d297829..63cd631e 100644 --- a/apps/api/src/controllers/export.controller.ts +++ b/apps/api/src/controllers/export.controller.ts @@ -19,7 +19,7 @@ async function getProjectId( projectId?: string; }; }>, - reply: FastifyReply + reply: FastifyReply, ) { let projectId = request.query.projectId || request.query.project_id; @@ -77,7 +77,7 @@ const eventsScheme = z.object({ includes: z .preprocess( (arg) => (typeof arg === 'string' ? [arg] : arg), - z.array(z.string()) + z.array(z.string()), ) .optional(), }); @@ -86,7 +86,7 @@ export async function events( request: FastifyRequest<{ Querystring: z.infer; }>, - reply: FastifyReply + reply: FastifyReply, ) { const query = eventsScheme.safeParse(request.query); @@ -118,7 +118,7 @@ export async function events( meta: false, ...query.data.includes?.reduce( (acc, key) => ({ ...acc, [key]: true }), - {} + {}, ), }, }; @@ -154,7 +154,7 @@ export async function charts( request: FastifyRequest<{ Querystring: Record; }>, - reply: FastifyReply + reply: FastifyReply, ) { const query = chartSchemeFull.safeParse(parseQueryString(request.query)); diff --git a/apps/api/src/controllers/import.controller.ts b/apps/api/src/controllers/import.controller.ts index 5584ec6e..355db752 100644 --- a/apps/api/src/controllers/import.controller.ts +++ b/apps/api/src/controllers/import.controller.ts @@ -2,13 +2,13 @@ import type { FastifyReply, FastifyRequest } from 'fastify'; import { toDots } from '@openpanel/common'; import type { IClickhouseEvent } from '@openpanel/db'; -import { ch, formatClickhouseDate, TABLE_NAMES } from '@openpanel/db'; +import { TABLE_NAMES, ch, formatClickhouseDate } from '@openpanel/db'; export async function importEvents( request: FastifyRequest<{ Body: IClickhouseEvent[]; }>, - reply: FastifyReply + reply: FastifyReply, ) { const importedAt = formatClickhouseDate(new Date()); const values: IClickhouseEvent[] = request.body.map((event) => { diff --git a/apps/api/src/controllers/live.controller.ts b/apps/api/src/controllers/live.controller.ts index 9a08cc01..9bc1645b 100644 --- a/apps/api/src/controllers/live.controller.ts +++ b/apps/api/src/controllers/live.controller.ts @@ -6,11 +6,11 @@ import type * as WebSocket from 'ws'; import { getSuperJson } from '@openpanel/common'; import type { IServiceEvent } from '@openpanel/db'; import { + TABLE_NAMES, getEvents, getLiveVisitors, getProfileById, getProfileByIdCached, - TABLE_NAMES, transformMinimalEvent, } from '@openpanel/db'; import { getRedisCache, getRedisPub, getRedisSub } from '@openpanel/redis'; @@ -26,10 +26,10 @@ export async function testVisitors( projectId: string; }; }>, - reply: FastifyReply + reply: FastifyReply, ) { const events = await getEvents( - `SELECT * FROM ${TABLE_NAMES.events} LIMIT 500` + `SELECT * FROM ${TABLE_NAMES.events} LIMIT 500`, ); const event = events[Math.floor(Math.random() * events.length)]; if (!event) { @@ -41,7 +41,7 @@ export async function testVisitors( `live:event:${event.projectId}:${Math.random() * 1000}`, '', 'EX', - 10 + 10, ); reply.status(202).send(event); } @@ -52,10 +52,10 @@ export async function testEvents( projectId: string; }; }>, - reply: FastifyReply + reply: FastifyReply, ) { const events = await getEvents( - `SELECT * FROM ${TABLE_NAMES.events} LIMIT 500` + `SELECT * FROM ${TABLE_NAMES.events} LIMIT 500`, ); const event = events[Math.floor(Math.random() * events.length)]; if (!event) { @@ -73,7 +73,7 @@ export function wsVisitors( Params: { projectId: string; }; - }> + }>, ) { const { params } = req; @@ -122,7 +122,7 @@ export async function wsProjectEvents( token?: string; type?: string; }; - }> + }>, ) { const { params, query } = req; const { token } = query; @@ -147,7 +147,7 @@ export async function wsProjectEvents( if (event?.projectId === params.projectId) { const profile = await getProfileByIdCached( event.profileId, - event.projectId + event.projectId, ); connection.socket.send( superjson.stringify( @@ -156,8 +156,8 @@ export async function wsProjectEvents( ...event, profile, } - : transformMinimalEvent(event) - ) + : transformMinimalEvent(event), + ), ); } }; diff --git a/apps/api/src/controllers/misc.controller.ts b/apps/api/src/controllers/misc.controller.ts index cac31559..dbe7c479 100644 --- a/apps/api/src/controllers/misc.controller.ts +++ b/apps/api/src/controllers/misc.controller.ts @@ -4,8 +4,8 @@ import type { FastifyReply, FastifyRequest } from 'fastify'; import icoToPng from 'ico-to-png'; import sharp from 'sharp'; -import { createHash } from '@openpanel/common'; -import { ch, formatClickhouseDate, TABLE_NAMES } from '@openpanel/db'; +import { createHash } from '@openpanel/common/server'; +import { TABLE_NAMES, ch, formatClickhouseDate } from '@openpanel/db'; import { getRedisCache } from '@openpanel/redis'; interface GetFaviconParams { @@ -38,7 +38,7 @@ async function getImageBuffer(url: string) { .png() .toBuffer(); } catch (error) { - logger.error(`Failed to get image from url`, { + logger.error('Failed to get image from url', { error, url, }); @@ -51,7 +51,7 @@ export async function getFavicon( request: FastifyRequest<{ Querystring: GetFaviconParams; }>, - reply: FastifyReply + reply: FastifyReply, ) { function sendBuffer(buffer: Buffer, cacheKey?: string) { if (cacheKey) { @@ -95,7 +95,7 @@ export async function getFavicon( } const buffer = await getImageBuffer( - 'https://www.iconsdb.com/icons/download/orange/warning-128.png' + 'https://www.iconsdb.com/icons/download/orange/warning-128.png', ); if (buffer && buffer.byteLength > 0) { return sendBuffer(buffer, hostname); @@ -106,7 +106,7 @@ export async function getFavicon( export async function clearFavicons( request: FastifyRequest, - reply: FastifyReply + reply: FastifyReply, ) { const keys = await getRedisCache().keys('favicon:*'); for (const key of keys) { @@ -122,7 +122,7 @@ export async function ping( count: number; }; }>, - reply: FastifyReply + reply: FastifyReply, ) { try { await ch.insert({ @@ -137,7 +137,7 @@ export async function ping( format: 'JSONEachRow', }); reply.status(200).send({ - message: `Success`, + message: 'Success', count: request.body.count, domain: request.body.domain, }); diff --git a/apps/api/src/controllers/profile.controller.ts b/apps/api/src/controllers/profile.controller.ts index dd7eadcb..d1f5628d 100644 --- a/apps/api/src/controllers/profile.controller.ts +++ b/apps/api/src/controllers/profile.controller.ts @@ -13,7 +13,7 @@ export async function updateProfile( request: FastifyRequest<{ Body: UpdateProfilePayload; }>, - reply: FastifyReply + reply: FastifyReply, ) { const { profileId, properties, ...rest } = request.body; const projectId = request.projectId; @@ -41,7 +41,7 @@ export async function incrementProfileProperty( request: FastifyRequest<{ Body: IncrementProfilePayload; }>, - reply: FastifyReply + reply: FastifyReply, ) { const { profileId, property, value } = request.body; const projectId = request.projectId; @@ -51,19 +51,19 @@ export async function incrementProfileProperty( return reply.status(404).send('Not found'); } - const parsed = parseInt( + const parsed = Number.parseInt( pathOr('0', property.split('.'), profile.properties), - 10 + 10, ); - if (isNaN(parsed)) { + if (Number.isNaN(parsed)) { return reply.status(400).send('Not number'); } profile.properties = assocPath( property.split('.'), parsed + value, - profile.properties + profile.properties, ); await upsertProfile({ @@ -80,7 +80,7 @@ export async function decrementProfileProperty( request: FastifyRequest<{ Body: IncrementProfilePayload; }>, - reply: FastifyReply + reply: FastifyReply, ) { const { profileId, property, value } = request.body; const projectId = request.projectId; @@ -90,19 +90,19 @@ export async function decrementProfileProperty( return reply.status(404).send('Not found'); } - const parsed = parseInt( + const parsed = Number.parseInt( pathOr('0', property.split('.'), profile.properties), - 10 + 10, ); - if (isNaN(parsed)) { + if (Number.isNaN(parsed)) { return reply.status(400).send('Not number'); } profile.properties = assocPath( property.split('.'), parsed - value, - profile.properties + profile.properties, ); await upsertProfile({ diff --git a/apps/api/src/controllers/track.controller.ts b/apps/api/src/controllers/track.controller.ts index e9d55c1d..32b651bd 100644 --- a/apps/api/src/controllers/track.controller.ts +++ b/apps/api/src/controllers/track.controller.ts @@ -2,9 +2,9 @@ import type { GeoLocation } from '@/utils/parseIp'; import { getClientIp, parseIp } from '@/utils/parseIp'; import { parseUserAgent } from '@/utils/parseUserAgent'; import type { FastifyReply, FastifyRequest } from 'fastify'; -import { assocPath, path, pathOr, pick } from 'ramda'; +import { path, assocPath, pathOr, pick } from 'ramda'; -import { generateDeviceId } from '@openpanel/common'; +import { generateDeviceId } from '@openpanel/common/server'; import { createProfileAlias, getProfileById, @@ -31,21 +31,21 @@ export function getStringHeaders(headers: FastifyRequest['headers']) { 'openpanel-sdk-version', 'openpanel-client-id', ], - headers - ) + headers, + ), ).reduce( (acc, [key, value]) => ({ ...acc, [key]: value ? String(value) : undefined, }), - {} + {}, ); } function getIdentity(body: TrackHandlerPayload): IdentifyPayload | undefined { const identity = path( ['properties', '__identify'], - body.payload + body.payload, ); return ( @@ -62,7 +62,7 @@ export async function handler( request: FastifyRequest<{ Body: TrackHandlerPayload; }>, - reply: FastifyReply + reply: FastifyReply, ) { const ip = path(['properties', '__ip'], request.body.payload) || @@ -129,7 +129,7 @@ export async function handler( projectId, geo, ua, - }) + }), ); } @@ -196,7 +196,7 @@ async function track({ 'locked', 'EX', 10, - 'NX' + 'NX', ); eventsQueue.add('event', { @@ -269,19 +269,19 @@ async function increment({ throw new Error('Not found'); } - const parsed = parseInt( + const parsed = Number.parseInt( pathOr('0', property.split('.'), profile.properties), - 10 + 10, ); - if (isNaN(parsed)) { + if (Number.isNaN(parsed)) { throw new Error('Not number'); } profile.properties = assocPath( property.split('.'), parsed + (value || 1), - profile.properties + profile.properties, ); await upsertProfile({ @@ -305,19 +305,19 @@ async function decrement({ throw new Error('Not found'); } - const parsed = parseInt( + const parsed = Number.parseInt( pathOr('0', property.split('.'), profile.properties), - 10 + 10, ); - if (isNaN(parsed)) { + if (Number.isNaN(parsed)) { throw new Error('Not number'); } profile.properties = assocPath( property.split('.'), parsed - (value || 1), - profile.properties + profile.properties, ); await upsertProfile({ diff --git a/apps/api/src/controllers/webhook.controller.ts b/apps/api/src/controllers/webhook.controller.ts index 2326e30b..2eea1338 100644 --- a/apps/api/src/controllers/webhook.controller.ts +++ b/apps/api/src/controllers/webhook.controller.ts @@ -33,7 +33,7 @@ export async function clerkWebhook( request: FastifyRequest<{ Body: WebhookEvent; }>, - reply: FastifyReply + reply: FastifyReply, ) { const payload = request.body; const verified = verify(payload, request.headers); @@ -49,7 +49,7 @@ export async function clerkWebhook( if (!email) { return Response.json( { message: 'No email address found' }, - { status: 400 } + { status: 400 }, ); } diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 6d9b3144..e3ce868c 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -1,4 +1,4 @@ -import zlib from 'zlib'; +import zlib from 'node:zlib'; import { clerkPlugin } from '@clerk/fastify'; import compress from '@fastify/compress'; import cookie from '@fastify/cookie'; @@ -11,7 +11,7 @@ import metricsPlugin from 'fastify-metrics'; import { path } from 'ramda'; import { generateId, round } from '@openpanel/common'; -import { chQuery, db, TABLE_NAMES } from '@openpanel/db'; +import { TABLE_NAMES, chQuery, db } from '@openpanel/db'; import type { IServiceClient } from '@openpanel/db'; import { eventsQueue } from '@openpanel/queue'; import { getRedisCache, getRedisPub } from '@openpanel/redis'; @@ -48,7 +48,7 @@ async function withTimings(promise: Promise) { } } -const port = parseInt(process.env.API_PORT || '3000', 10); +const port = Number.parseInt(process.env.API_PORT || '3000', 10); const startServer = async () => { logger.info('Starting server'); @@ -65,7 +65,7 @@ const startServer = async () => { }); const getTrpcInput = ( - request: FastifyRequest + request: FastifyRequest, ): Record | undefined => { const input = path(['query', 'input'], request); try { @@ -125,14 +125,14 @@ const startServer = async () => { fastify.addContentTypeParser( 'application/json', { parseAs: 'buffer' }, - function (req, body, done) { + (req, body, done) => { const isGzipped = req.headers['content-encoding'] === 'gzip'; if (isGzipped) { zlib.gunzip(body, (err, decompressedBody) => { console.log( 'decompressedBody', - decompressedBody.toString().slice(0, 100) + decompressedBody.toString().slice(0, 100), ); if (err) { done(err); @@ -153,7 +153,7 @@ const startServer = async () => { done(new Error('Invalid JSON')); } } - } + }, ); await fastify.register(metricsPlugin, { endpoint: '/metrics' }); @@ -211,7 +211,7 @@ const startServer = async () => { const dbRes = await withTimings(db.project.findFirst()); const queueRes = await withTimings(eventsQueue.getCompleted()); const chRes = await withTimings( - chQuery(`SELECT * FROM ${TABLE_NAMES.events} LIMIT 1`) + chQuery(`SELECT * FROM ${TABLE_NAMES.events} LIMIT 1`), ); const status = redisRes && dbRes && queueRes && chRes ? 200 : 500; diff --git a/apps/api/src/routes/event.router.ts b/apps/api/src/routes/event.router.ts index eda616b2..914ae504 100644 --- a/apps/api/src/routes/event.router.ts +++ b/apps/api/src/routes/event.router.ts @@ -14,7 +14,7 @@ const eventRouter: FastifyPluginCallback = (fastify, opts, done) => { req: FastifyRequest<{ Body: PostEventPayload; }>, - reply + reply, ) => { try { const client = await validateSdkRequest(req.headers).catch((error) => { @@ -51,7 +51,7 @@ const eventRouter: FastifyPluginCallback = (fastify, opts, done) => { reply.status(401).send(); return; } - } + }, ); fastify.route({ diff --git a/apps/api/src/routes/export.router.ts b/apps/api/src/routes/export.router.ts index f1f61d72..edc7882c 100644 --- a/apps/api/src/routes/export.router.ts +++ b/apps/api/src/routes/export.router.ts @@ -15,11 +15,14 @@ const eventRouter: FastifyPluginCallback = (fastify, opts, done) => { error: 'Unauthorized', message: 'Client ID seems to be malformed', }); - } else if (e instanceof Error) { + } + + if (e instanceof Error) { return reply .status(401) .send({ error: 'Unauthorized', message: e.message }); } + return reply .status(401) .send({ error: 'Unauthorized', message: 'Unexpected error' }); diff --git a/apps/api/src/routes/import.router.ts b/apps/api/src/routes/import.router.ts index e993a591..0dab535b 100644 --- a/apps/api/src/routes/import.router.ts +++ b/apps/api/src/routes/import.router.ts @@ -15,11 +15,14 @@ const importRouter: FastifyPluginCallback = (fastify, opts, done) => { error: 'Unauthorized', message: 'Client ID seems to be malformed', }); - } else if (e instanceof Error) { + } + + if (e instanceof Error) { return reply .status(401) .send({ error: 'Unauthorized', message: e.message }); } + return reply .status(401) .send({ error: 'Unauthorized', message: 'Unexpected error' }); diff --git a/apps/api/src/routes/live.router.ts b/apps/api/src/routes/live.router.ts index b836af43..ba71b301 100644 --- a/apps/api/src/routes/live.router.ts +++ b/apps/api/src/routes/live.router.ts @@ -20,12 +20,12 @@ const liveRouter: FastifyPluginCallback = (fastify, opts, done) => { fastify.get( '/visitors/:projectId', { websocket: true }, - controller.wsVisitors + controller.wsVisitors, ); fastify.get( '/events/:projectId', { websocket: true }, - controller.wsProjectEvents + controller.wsProjectEvents, ); done(); }); diff --git a/apps/api/src/routes/track.router.ts b/apps/api/src/routes/track.router.ts index b5b43e9c..c8ce3fe1 100644 --- a/apps/api/src/routes/track.router.ts +++ b/apps/api/src/routes/track.router.ts @@ -14,7 +14,7 @@ const trackRouter: FastifyPluginCallback = (fastify, opts, done) => { req: FastifyRequest<{ Body: TrackHandlerPayload; }>, - reply + reply, ) => { try { const client = await validateSdkRequest(req.headers).catch((error) => { @@ -55,7 +55,7 @@ const trackRouter: FastifyPluginCallback = (fastify, opts, done) => { reply.status(401).send(); return; } - } + }, ); fastify.route({ diff --git a/apps/api/src/utils/auth.ts b/apps/api/src/utils/auth.ts index aaabd663..7f5c3b90 100644 --- a/apps/api/src/utils/auth.ts +++ b/apps/api/src/utils/auth.ts @@ -1,7 +1,7 @@ import type { RawRequestDefaultExpression } from 'fastify'; import jwt from 'jsonwebtoken'; -import { verifyPassword } from '@openpanel/common'; +import { verifyPassword } from '@openpanel/common/server'; import type { Client, IServiceClient } from '@openpanel/db'; import { ClientType, db } from '@openpanel/db'; @@ -24,7 +24,7 @@ export class SdkAuthError extends Error { clientId?: string; clientSecret?: string; origin?: string; - } + }, ) { super(message); this.name = 'SdkAuthError'; @@ -33,7 +33,7 @@ export class SdkAuthError extends Error { } export async function validateSdkRequest( - headers: RawRequestDefaultExpression['headers'] + headers: RawRequestDefaultExpression['headers'], ): Promise { const clientIdNew = headers['openpanel-client-id'] as string; const clientIdOld = headers['mixan-client-id'] as string; @@ -48,7 +48,7 @@ export async function validateSdkRequest( clientId, clientSecret: typeof clientSecret === 'string' - ? clientSecret.slice(0, 5) + '...' + clientSecret.slice(-5) + ? `${clientSecret.slice(0, 5)}...${clientSecret.slice(-5)}` : 'none', origin, }); @@ -99,7 +99,7 @@ export async function validateSdkRequest( } export async function validateExportRequest( - headers: RawRequestDefaultExpression['headers'] + headers: RawRequestDefaultExpression['headers'], ): Promise { const clientId = headers['openpanel-client-id'] as string; const clientSecret = (headers['openpanel-client-secret'] as string) || ''; @@ -129,7 +129,7 @@ export async function validateExportRequest( } export async function validateImportRequest( - headers: RawRequestDefaultExpression['headers'] + headers: RawRequestDefaultExpression['headers'], ): Promise { const clientId = headers['openpanel-client-id'] as string; const clientSecret = (headers['openpanel-client-secret'] as string) || ''; @@ -165,7 +165,7 @@ export function validateClerkJwt(token?: string) { try { const decoded = jwt.verify( token, - process.env.CLERK_PUBLIC_PEM_KEY!.replace(/\\n/g, '\n') + process.env.CLERK_PUBLIC_PEM_KEY!.replace(/\\n/g, '\n'), ); if (typeof decoded === 'object') { diff --git a/apps/api/src/utils/parse-zod-query-string.ts b/apps/api/src/utils/parse-zod-query-string.ts index f9b097ce..c72683d3 100644 --- a/apps/api/src/utils/parse-zod-query-string.ts +++ b/apps/api/src/utils/parse-zod-query-string.ts @@ -4,8 +4,11 @@ export const parseQueryString = (obj: Record): any => { return Object.fromEntries( Object.entries(obj).map(([k, v]) => { if (typeof v === 'object') return [k, parseQueryString(v)]; - if (/^-?[0-9]+(\.[0-9]+)?$/i.test(v) && !isNaN(parseFloat(v))) - return [k, parseFloat(v)]; + if ( + /^-?[0-9]+(\.[0-9]+)?$/i.test(v) && + !Number.isNaN(Number.parseFloat(v)) + ) + return [k, Number.parseFloat(v)]; if (v === 'true') return [k, true]; if (v === 'false') return [k, false]; if (typeof v === 'string') { @@ -15,6 +18,6 @@ export const parseQueryString = (obj: Record): any => { return [k, v]; } return [k, null]; - }) + }), ); }; diff --git a/apps/api/src/utils/parseUrlMeta.ts b/apps/api/src/utils/parseUrlMeta.ts index 670c3cbc..cda031a0 100644 --- a/apps/api/src/utils/parseUrlMeta.ts +++ b/apps/api/src/utils/parseUrlMeta.ts @@ -9,7 +9,7 @@ function findBestFavicon(favicons: UrlMetaData['favicons']) { (favicon) => favicon.rel === 'shortcut icon' || favicon.rel === 'icon' || - favicon.rel === 'apple-touch-icon' + favicon.rel === 'apple-touch-icon', ); if (match) { diff --git a/apps/api/src/utils/parseUserAgent.ts b/apps/api/src/utils/parseUserAgent.ts index af469ee7..b7e8666d 100644 --- a/apps/api/src/utils/parseUserAgent.ts +++ b/apps/api/src/utils/parseUserAgent.ts @@ -71,7 +71,7 @@ const userAgentServerList = [ function isServer(userAgent: string) { const match = userAgentServerList.some((server) => - userAgent.toLowerCase().includes(server.toLowerCase()) + userAgent.toLowerCase().includes(server.toLowerCase()), ); if (match) { return true; @@ -83,15 +83,15 @@ function isServer(userAgent: string) { export function getDevice(ua: string) { const mobile1 = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test( - ua + ua, ); const mobile2 = /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test( - ua.slice(0, 4) + ua.slice(0, 4), ); const tablet = /tablet|ipad|android(?!.*mobile)|xoom|sch-i800|kindle|silk|playbook/i.test( - ua + ua, ); if (mobile1 || mobile2) { diff --git a/apps/dashboard/.gitignore b/apps/dashboard/.gitignore index 2971a0bd..04424e48 100644 --- a/apps/dashboard/.gitignore +++ b/apps/dashboard/.gitignore @@ -26,9 +26,6 @@ next-env.d.ts # debug npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* # local env files # do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables diff --git a/apps/dashboard/Dockerfile b/apps/dashboard/Dockerfile index 089a7480..db079e54 100644 --- a/apps/dashboard/Dockerfile +++ b/apps/dashboard/Dockerfile @@ -37,7 +37,6 @@ COPY packages/common/package.json packages/common/package.json COPY packages/constants/package.json packages/constants/package.json COPY packages/validation/package.json packages/validation/package.json COPY packages/sdks/sdk/package.json packages/sdks/sdk/package.json -COPY patches patches # BUILD FROM base AS build diff --git a/apps/dashboard/next.config.mjs b/apps/dashboard/next.config.mjs index a3b94d9a..7f83a9da 100644 --- a/apps/dashboard/next.config.mjs +++ b/apps/dashboard/next.config.mjs @@ -30,7 +30,11 @@ const config = { typescript: { ignoreBuildErrors: true }, experimental: { // Avoid "Critical dependency: the request of a dependency is an expression" - serverComponentsExternalPackages: ['bullmq', 'ioredis'], + serverComponentsExternalPackages: [ + 'bullmq', + 'ioredis', + '@hyperdx/node-opentelemetry', + ], instrumentationHook: !!process.env.ENABLE_INSTRUMENTATION_HOOK, }, /** diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index d2bf9f7e..3c37d3b0 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -7,8 +7,6 @@ "testing": "pnpm dev", "build": "pnpm with-env next build", "start": "next start", - "lint": "eslint .", - "format": "prettier --check \"**/*.{tsx,mjs,ts,md,json}\"", "typecheck": "tsc --noEmit", "with-env": "dotenv -e ../../.env -c --" }, @@ -76,7 +74,7 @@ "lucide-react": "^0.331.0", "mathjs": "^12.3.2", "mitt": "^3.0.1", - "next": "~14.2.1", + "next": "14.2.1", "next-auth": "^4.24.5", "next-themes": "^0.2.1", "nextjs-toploader": "^1.6.11", @@ -112,8 +110,6 @@ "zod": "^3.22.4" }, "devDependencies": { - "@openpanel/eslint-config": "workspace:*", - "@openpanel/prettier-config": "workspace:*", "@openpanel/trpc": "workspace:*", "@openpanel/tsconfig": "workspace:*", "@types/bcrypt": "^5.0.2", @@ -127,26 +123,9 @@ "@types/react-simple-maps": "^3.0.4", "@types/react-syntax-highlighter": "^15.5.11", "@types/sqlstring": "^2.3.2", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", "autoprefixer": "^10.4.17", - "eslint": "^8.56.0", "postcss": "^8.4.35", - "prettier": "^3.2.5", - "prettier-plugin-tailwindcss": "^0.5.11", "tailwindcss": "^3.4.1", "typescript": "^5.3.3" - }, - "ct3aMetadata": { - "initVersion": "7.21.0" - }, - "eslintConfig": { - "root": true, - "extends": [ - "@openpanel/eslint-config/base", - "@openpanel/eslint-config/react", - "@openpanel/eslint-config/nextjs" - ] - }, - "prettier": "@openpanel/prettier-config" -} \ No newline at end of file + } +} diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/dashboards/[dashboardId]/list-reports.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/dashboards/[dashboardId]/list-reports.tsx index ab2b40e7..63404d52 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/dashboards/[dashboardId]/list-reports.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/dashboards/[dashboardId]/list-reports.tsx @@ -30,7 +30,7 @@ import { getDefaultIntervalByRange, timeWindows, } from '@openpanel/constants'; -import type { getReportsByDashboardId, IServiceDashboard } from '@openpanel/db'; +import type { IServiceDashboard, getReportsByDashboardId } from '@openpanel/db'; import { OverviewReportRange } from '../../overview-sticky-header'; @@ -64,7 +64,7 @@ export function ListReports({ reports, dashboard }: ListReportsProps) { params.projectId }/reports?${new URLSearchParams({ dashboardId: params.dashboardId, - }).toString()}` + }).toString()}`, ); }} > @@ -163,7 +163,7 @@ export function ListReports({ reports, dashboard }: ListReportsProps) { params.projectId }/reports?${new URLSearchParams({ dashboardId: params.dashboardId, - }).toString()}` + }).toString()}`, ) } className="mt-14" diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/dashboards/list-dashboards/list-dashboards.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/dashboards/list-dashboards/list-dashboards.tsx index c9d04503..3bf9dbd4 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/dashboards/list-dashboards/list-dashboards.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/dashboards/list-dashboards/list-dashboards.tsx @@ -79,7 +79,7 @@ export function ListDashboards({ dashboards }: ListDashboardsProps) { {dashboards.map((item) => { const visibleReports = item.reports.slice( 0, - item.reports.length > 6 ? 5 : 6 + item.reports.length > 6 ? 5 : 6, ); return ( @@ -97,7 +97,7 @@ export function ListDashboards({ dashboards }: ListDashboardsProps) {
{visibleReports.map((report) => { @@ -145,6 +145,7 @@ export function ListDashboards({ dashboards }: ListDashboardsProps) {
diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-charts.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-charts.tsx index 214b4a8f..3a36b814 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-charts.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-charts.tsx @@ -1,8 +1,8 @@ 'use client'; -import { memo } from 'react'; import { ReportChart } from '@/components/report-chart'; import { Widget, WidgetBody, WidgetHead } from '@/components/widget'; +import { memo } from 'react'; import type { IChartProps } from '@openpanel/validation'; diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-events.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-events.tsx index e65e78e3..587430ec 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-events.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-events.tsx @@ -24,7 +24,7 @@ const Events = ({ projectId, profileId }: Props) => { const [eventNames] = useEventQueryNamesFilter(); const [cursor, setCursor] = useQueryState( 'cursor', - parseAsInteger.withDefault(0) + parseAsInteger.withDefault(0), ); const query = api.event.events.useQuery( { @@ -37,7 +37,7 @@ const Events = ({ projectId, profileId }: Props) => { }, { keepPreviousData: true, - } + }, ); return ( diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-metrics/profile-metrics.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-metrics/profile-metrics.tsx index ebe07673..293326bb 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-metrics/profile-metrics.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/profile-metrics/profile-metrics.tsx @@ -35,7 +35,7 @@ function Info({ title, value }: { title: string; value: string }) { const ProfileMetrics = ({ data, profile }: Props) => { const [tab, setTab] = useQueryState( 'tab', - parseAsStringEnum(['profile', 'properties']).withDefault('profile') + parseAsStringEnum(['profile', 'properties']).withDefault('profile'), ); const number = useNumber(); return ( @@ -44,24 +44,26 @@ const ProfileMetrics = ({ data, profile }: Props) => {
- + Profiles Power users diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/power-users.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/power-users.tsx index de026da1..e4da65eb 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/power-users.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/power-users.tsx @@ -12,7 +12,7 @@ type Props = { const Events = ({ projectId }: Props) => { const [cursor, setCursor] = useQueryState( 'cursor', - parseAsInteger.withDefault(0) + parseAsInteger.withDefault(0), ); const query = api.profile.powerUsers.useQuery( { @@ -23,7 +23,7 @@ const Events = ({ projectId }: Props) => { }, { keepPreviousData: true, - } + }, ); return ( diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profile-last-seen/index.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profile-last-seen/index.tsx index 9fe959a2..2f74747f 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profile-last-seen/index.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profile-last-seen/index.tsx @@ -7,7 +7,7 @@ import { Widget, WidgetBody, WidgetHead } from '@/components/widget'; import { cn } from '@/utils/cn'; import { escape } from 'sqlstring'; -import { chQuery, TABLE_NAMES } from '@openpanel/db'; +import { TABLE_NAMES, chQuery } from '@openpanel/db'; interface Props { projectId: string; @@ -21,7 +21,7 @@ export default async function ProfileLastSeenServer({ projectId }: Props) { // Days since last event from users // group by days const res = await chQuery( - `SELECT age('days',created_at, now()) as days, count(distinct profile_id) as count FROM ${TABLE_NAMES.events} where project_id = ${escape(projectId)} group by days order by days ASC LIMIT 51` + `SELECT age('days',created_at, now()) as days, count(distinct profile_id) as count FROM ${TABLE_NAMES.events} where project_id = ${escape(projectId)} group by days order by days ASC LIMIT 51`, ); const maxValue = Math.max(...res.map((x) => x.count)); @@ -29,7 +29,7 @@ export default async function ProfileLastSeenServer({ projectId }: Props) { const calculateRatio = (currentValue: number) => Math.max( 0.1, - Math.min(1, (currentValue - minValue) / (maxValue - minValue)) + Math.min(1, (currentValue - minValue) / (maxValue - minValue)), ); const renderItem = (item: Row) => ( @@ -41,7 +41,7 @@ export default async function ProfileLastSeenServer({ projectId }: Props) { style={{ opacity: calculateRatio(item.count), }} - >
+ /> {item.count} profiles last seen{' '} diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profiles.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profiles.tsx index a50da9c6..e751ae26 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profiles.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profiles.tsx @@ -15,7 +15,7 @@ type Props = { const Events = ({ projectId }: Props) => { const [cursor, setCursor] = useQueryState( 'cursor', - parseAsInteger.withDefault(0) + parseAsInteger.withDefault(0), ); const [search, setSearch] = useQueryState('search', { defaultValue: '', @@ -31,7 +31,7 @@ const Events = ({ projectId }: Props) => { }, { keepPreviousData: true, - } + }, ); return ( diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/coordinates.ts b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/coordinates.ts index 24efd136..7e430cae 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/coordinates.ts +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/coordinates.ts @@ -5,7 +5,7 @@ export type Coordinate = { export function haversineDistance( coord1: Coordinate, - coord2: Coordinate + coord2: Coordinate, ): number { const R = 6371; // Earth's radius in kilometers const lat1Rad = coord1.lat * (Math.PI / 180); @@ -25,7 +25,7 @@ export function haversineDistance( } export function findFarthestPoints( - coordinates: Coordinate[] + coordinates: Coordinate[], ): [Coordinate, Coordinate] { if (coordinates.length < 2) { throw new Error('At least two coordinates are required'); @@ -80,12 +80,12 @@ function cross(o: Coordinate, a: Coordinate, b: Coordinate): number { // convex hull export function getOuterMarkers(coordinates: Coordinate[]): Coordinate[] { - coordinates = coordinates.sort(sortCoordinates); + const sorted = coordinates.sort(sortCoordinates); - if (coordinates.length <= 3) return coordinates; + if (sorted.length <= 3) return sorted; const lower: Coordinate[] = []; - for (const coord of coordinates) { + for (const coord of sorted) { while ( lower.length >= 2 && cross(lower[lower.length - 2]!, lower[lower.length - 1]!, coord) <= 0 @@ -99,15 +99,11 @@ export function getOuterMarkers(coordinates: Coordinate[]): Coordinate[] { for (let i = coordinates.length - 1; i >= 0; i--) { while ( upper.length >= 2 && - cross( - upper[upper.length - 2]!, - upper[upper.length - 1]!, - coordinates[i]! - ) <= 0 + cross(upper[upper.length - 2]!, upper[upper.length - 1]!, sorted[i]!) <= 0 ) { upper.pop(); } - upper.push(coordinates[i]!); + upper.push(sorted[i]!); } upper.pop(); @@ -148,22 +144,22 @@ export function calculateCentroid(polygon: Coordinate[]): Coordinate { } export function calculateGeographicMidpoint( - coordinate: Coordinate[] + coordinate: Coordinate[], ): Coordinate { - let minLat = Infinity, - maxLat = -Infinity, - minLong = Infinity, - maxLong = -Infinity; + let minLat = Number.POSITIVE_INFINITY; + let maxLat = Number.NEGATIVE_INFINITY; + let minLong = Number.POSITIVE_INFINITY; + let maxLong = Number.NEGATIVE_INFINITY; - coordinate.forEach(({ lat, long }) => { + for (const { lat, long } of coordinate) { if (lat < minLat) minLat = lat; if (lat > maxLat) maxLat = lat; if (long < minLong) minLong = long; if (long > maxLong) maxLong = long; - }); + } // Handling the wrap around the international date line - let midLong; + let midLong: number; if (maxLong > minLong) { midLong = (maxLong + minLong) / 2; } else { @@ -211,7 +207,7 @@ export function clusterCoordinates(coordinates: Coordinate[], radius = 25) { long: center.long + cur.long / cluster.members.length, }; }, - { lat: 0, long: 0 } + { lat: 0, long: 0 }, ); clusters.push(cluster); diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/index.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/index.tsx index a0f183fa..59700e8a 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/index.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/index.tsx @@ -1,7 +1,7 @@ import { subMinutes } from 'date-fns'; import { escape } from 'sqlstring'; -import { chQuery, formatClickhouseDate, TABLE_NAMES } from '@openpanel/db'; +import { TABLE_NAMES, chQuery, formatClickhouseDate } from '@openpanel/db'; import type { Coordinate } from './coordinates'; import Map from './map'; @@ -11,7 +11,7 @@ type Props = { }; const RealtimeMap = async ({ projectId }: Props) => { const res = await chQuery( - `SELECT DISTINCT city, longitude as long, latitude as lat FROM ${TABLE_NAMES.events} WHERE project_id = ${escape(projectId)} AND created_at >= '${formatClickhouseDate(subMinutes(new Date(), 30))}' ORDER BY created_at DESC` + `SELECT DISTINCT city, longitude as long, latitude as lat FROM ${TABLE_NAMES.events} WHERE project_id = ${escape(projectId)} AND created_at >= '${formatClickhouseDate(subMinutes(new Date(), 30))}' ORDER BY created_at DESC`, ); return ; diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/map.helpers.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/map.helpers.tsx index fb688db3..0ce40bbf 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/map.helpers.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/map.helpers.tsx @@ -49,7 +49,7 @@ export const getBoundingBox = (coordinates: Coordinate[]) => { export const determineZoom = ( bbox: ReturnType, - aspectRatio = 1.0 + aspectRatio = 1.0, ): number => { const latDiff = bbox.maxLat - bbox.minLat; const longDiff = bbox.maxLong - bbox.minLong; diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/map.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/map.tsx index da382e56..5ba1a15b 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/map.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/map.tsx @@ -1,11 +1,11 @@ 'use client'; -import { Fragment, useEffect, useRef, useState } from 'react'; import { useFullscreen } from '@/components/fullscreen-toggle'; import { Tooltiper } from '@/components/ui/tooltip'; import { cn } from '@/utils/cn'; import { bind } from 'bind-event-listener'; import { useTheme } from 'next-themes'; +import { Fragment, useEffect, useRef, useState } from 'react'; import { ComposableMap, Geographies, @@ -22,8 +22,8 @@ import { } from './coordinates'; import { CustomZoomableGroup, - determineZoom, GEO_MAP_URL, + determineZoom, getBoundingBox, useAnimatedState, } from './map.helpers'; @@ -37,7 +37,7 @@ const Map = ({ markers }: Props) => { const showCenterMarker = false; const ref = useRef(null); const [size, setSize] = useState<{ width: number; height: number } | null>( - null + null, ); // const { markers, toggle } = useActiveMarkers(_m); @@ -50,7 +50,7 @@ const Map = ({ markers }: Props) => { const [zoom] = useAnimatedState( markers.length === 1 ? 20 - : determineZoom(boundingBox, size ? size?.height / size?.width : 1) + : determineZoom(boundingBox, size ? size?.height / size?.width : 1), ); const [long] = useAnimatedState(center.long); @@ -99,7 +99,7 @@ const Map = ({ markers }: Props) => {
@@ -142,7 +142,7 @@ const Map = ({ markers }: Props) => { )} {clusterCoordinates(markers).map((marker) => { const size = adjustSizeBasedOnZoom( - calculateMarkerSize(marker.count) + calculateMarkerSize(marker.count), ); const coordinates: [number, number] = [ marker.center.long, diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/markers.ts b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/markers.ts index 453d6392..9513dd0d 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/markers.ts +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/map/markers.ts @@ -11,7 +11,7 @@ const useActiveMarkers = (initialMarkers: Coordinate[]) => { // Cut the array in half randomly to simulate changes in active markers const selected = shuffled.slice( 0, - Math.floor(Math.random() * shuffled.length) + 1 + Math.floor(Math.random() * shuffled.length) + 1, ); setActiveMarkers(selected); }, [activeMarkers]); diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/page.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/page.tsx index a20995f1..c190ad00 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/page.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/page.tsx @@ -1,10 +1,10 @@ -import { Suspense } from 'react'; import { Fullscreen, FullscreenClose, FullscreenOpen, } from '@/components/fullscreen-toggle'; import { ReportChart } from '@/components/report-chart'; +import { Suspense } from 'react'; import RealtimeMap from './map'; import RealtimeLiveEventsServer from './realtime-live-events'; diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-events/index.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-events/index.tsx index 9dce9fdb..6fc9523f 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-events/index.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-events/index.tsx @@ -1,6 +1,6 @@ import { escape } from 'sqlstring'; -import { getEvents, TABLE_NAMES } from '@openpanel/db'; +import { TABLE_NAMES, getEvents } from '@openpanel/db'; import LiveEvents from './live-events'; @@ -13,7 +13,7 @@ const RealtimeLiveEventsServer = async ({ projectId, limit = 30 }: Props) => { `SELECT * FROM ${TABLE_NAMES.events} WHERE created_at > now() - INTERVAL 2 HOUR AND project_id = ${escape(projectId)} ORDER BY created_at DESC LIMIT ${limit}`, { profile: true, - } + }, ); return ; }; diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-events/live-events.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-events/live-events.tsx index b570748c..75cc06e6 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-events/live-events.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-events/live-events.tsx @@ -1,9 +1,9 @@ 'use client'; -import { useState } from 'react'; import { EventListItem } from '@/components/events/event-list-item'; import useWS from '@/hooks/useWS'; import { AnimatePresence, motion } from 'framer-motion'; +import { useState } from 'react'; import type { IServiceEvent, IServiceEventMinimal } from '@openpanel/db'; @@ -19,7 +19,7 @@ const RealtimeLiveEvents = ({ events, projectId, limit }: Props) => { `/live/events/${projectId}`, (event) => { setState((p) => [event, ...p].slice(0, limit)); - } + }, ); return ( diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-histogram.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-histogram.tsx index a910673a..17e64b2e 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-histogram.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/realtime/realtime-live-histogram.tsx @@ -71,18 +71,16 @@ export function RealtimeLiveHistogram({ const liveCount = countRes.data?.series[0]?.metrics?.sum ?? 0; if (res.isInitialLoading || countRes.isInitialLoading || liveCount === 0) { - // prettier-ignore const staticArray = [ - 10, 25, 30, 45, 20, 5, 55, 18, 40, 12, - 50, 35, 8, 22, 38, 42, 15, 28, 52, 5, - 48, 14, 32, 58, 7, 19, 33, 56, 24, 5 + 10, 25, 30, 45, 20, 5, 55, 18, 40, 12, 50, 35, 8, 22, 38, 42, 15, 28, 52, + 5, 48, 14, 32, 58, 7, 19, 33, 56, 24, 5, ]; return ( {staticArray.map((percent, i) => (
@@ -104,7 +102,7 @@ export function RealtimeLiveHistogram({
{ maxWait: 15000, delay: 15000, }, - } + }, ); return null; diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/reports/report-editor.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/reports/report-editor.tsx index 85ce1574..27adfbc9 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/reports/report-editor.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/reports/report-editor.tsx @@ -1,6 +1,5 @@ 'use client'; -import { useEffect } from 'react'; import { StickyBelowHeader } from '@/app/(app)/[organizationSlug]/[projectId]/layout-sticky-below-header'; import { ReportChart } from '@/components/report-chart'; import { ReportChartType } from '@/components/report/ReportChartType'; @@ -25,6 +24,7 @@ import { useDispatch, useSelector } from '@/redux'; import { bind } from 'bind-event-listener'; import { endOfDay, startOfDay } from 'date-fns'; import { GanttChartSquareIcon } from 'lucide-react'; +import { useEffect } from 'react'; import type { IServiceReport } from '@openpanel/db'; diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/retention/last-active-users/chart.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/retention/last-active-users/chart.tsx index 5af24f1d..1b961649 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/retention/last-active-users/chart.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/retention/last-active-users/chart.tsx @@ -55,12 +55,12 @@ const Chart = ({ data }: Props) => { offset="0%" stopColor={getChartColor(0)} stopOpacity={0.8} - > + /> + /> @@ -70,7 +70,7 @@ const Chart = ({ data }: Props) => { dataKey="users" stroke={getChartColor(0)} strokeWidth={2} - fill={`url(#bg)`} + fill={'url(#bg)'} isAnimationActive={false} /> { offset="0%" stopColor={getChartColor(0)} stopOpacity={0.8} - > + /> + /> + /> + /> + /> + /> @@ -111,21 +111,21 @@ const Chart = ({ data }: Props) => { dataKey="dau" stroke={getChartColor(0)} strokeWidth={2} - fill={`url(#dau)`} + fill={'url(#dau)'} isAnimationActive={false} /> diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/retention/users-retention-series/chart.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/retention/users-retention-series/chart.tsx index fe5fae6f..7e0905f2 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/retention/users-retention-series/chart.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/retention/users-retention-series/chart.tsx @@ -70,12 +70,12 @@ const Chart = ({ data }: Props) => { offset="0%" stopColor={getChartColor(0)} stopOpacity={0.8} - > + /> + /> @@ -85,7 +85,7 @@ const Chart = ({ data }: Props) => { dataKey="retention" stroke={getChartColor(0)} strokeWidth={2} - fill={`url(#bg)`} + fill={'url(#bg)'} isAnimationActive={false} /> {
+ />
{value}
); @@ -39,7 +39,7 @@ const WeeklyCohortsServer = async ({ projectId }: Props) => { row.period_7, row.period_8, row.period_9, - ]) + ]), ); const calculateRatio = (currentValue: number) => @@ -47,7 +47,7 @@ const WeeklyCohortsServer = async ({ projectId }: Props) => { ? 0 : Math.max( 0.1, - Math.min(1, (currentValue - minValue) / (maxValue - minValue)) + Math.min(1, (currentValue - minValue) / (maxValue - minValue)), ); return ( diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/invites/create-invite.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/invites/create-invite.tsx index 2c9c5f21..2ed0428f 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/invites/create-invite.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/invites/create-invite.tsx @@ -6,7 +6,6 @@ import { ComboboxAdvanced } from '@/components/ui/combobox-advanced'; import { Label } from '@/components/ui/label'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { - closeSheet, Sheet, SheetContent, SheetDescription, @@ -14,6 +13,7 @@ import { SheetHeader, SheetTitle, SheetTrigger, + closeSheet, } from '@/components/ui/sheet'; import { useAppParams } from '@/hooks/useAppParams'; import { api } from '@/trpc/client'; diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/page.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/page.tsx index c8a5a90a..187d99f7 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/page.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/organization/page.tsx @@ -52,7 +52,7 @@ export default async function Page({ } const member = organization.members.find( - (member) => member.userId === session.userId + (member) => member.userId === session.userId, ); const hasAccess = member?.role === 'org:admin'; @@ -69,13 +69,13 @@ export default async function Page({ return ( - + Organization - + Members - + Invites diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/profile/logout.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/profile/logout.tsx index fc3f5391..71578074 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/profile/logout.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/profile/logout.tsx @@ -10,9 +10,7 @@ export function Logout() { Sad part -

- Sometimes you need to go. See you next time -

+

Sometimes you need to go. See you next time

diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/projects/list-projects.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/projects/list-projects.tsx index 97460007..9a1c882a 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/projects/list-projects.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/settings/projects/list-projects.tsx @@ -44,7 +44,7 @@ export default function ListProjects({ projects, clients }: ListProjectsProps) { {projects.map((project) => { const pClients = clients.filter( - (client) => client.projectId === project.id + (client) => client.projectId === project.id, ); return (
-
+
@@ -91,6 +91,7 @@ export default function ListProjects({ projects, clients }: ListProjectsProps) { ); })}
)} {events.slice(-5).map((event, index) => ( -
+
{' '} {event.name}{' '} @@ -108,6 +108,7 @@ const VerifyListener = ({ client, events: _events, onVerified }: Props) => {
You can{' '}
); - } + }, ); CheckboxItem.displayName = 'CheckboxItem'; diff --git a/apps/dashboard/src/components/forms/copy-input.tsx b/apps/dashboard/src/components/forms/copy-input.tsx index c9c7239f..b70850f8 100644 --- a/apps/dashboard/src/components/forms/copy-input.tsx +++ b/apps/dashboard/src/components/forms/copy-input.tsx @@ -13,6 +13,7 @@ type Props = { const CopyInput = ({ label, value, className }: Props) => { return ( diff --git a/apps/dashboard/src/components/overview/overview-top-bots.tsx b/apps/dashboard/src/components/overview/overview-top-bots.tsx index 54340636..c90002a3 100644 --- a/apps/dashboard/src/components/overview/overview-top-bots.tsx +++ b/apps/dashboard/src/components/overview/overview-top-bots.tsx @@ -1,5 +1,5 @@ -import { useState } from 'react'; import { api } from '@/trpc/client'; +import { useState } from 'react'; import { Pagination } from '../pagination'; import { Tooltiper } from '../ui/tooltip'; @@ -23,7 +23,7 @@ const OverviewTopBots = ({ projectId }: Props) => { { projectId, cursor }, { keepPreviousData: true, - } + }, ); const data = res.data?.data ?? []; const count = res.data?.count ?? 0; diff --git a/apps/dashboard/src/components/overview/overview-top-devices.tsx b/apps/dashboard/src/components/overview/overview-top-devices.tsx index 6dfc63e9..d05eef7a 100644 --- a/apps/dashboard/src/components/overview/overview-top-devices.tsx +++ b/apps/dashboard/src/components/overview/overview-top-devices.tsx @@ -1,8 +1,8 @@ 'use client'; -import { useState } from 'react'; import { useEventQueryFilters } from '@/hooks/useEventQueryFilters'; import { cn } from '@/utils/cn'; +import { useState } from 'react'; import { NOT_SET_VALUE } from '@openpanel/constants'; import type { IChartType } from '@openpanel/validation'; @@ -295,6 +295,7 @@ export default function OverviewTopDevices({ {widgets.map((w) => (
-
+
, ); } diff --git a/apps/dashboard/src/components/report-chart/histogram/chart.tsx b/apps/dashboard/src/components/report-chart/histogram/chart.tsx index a023ff23..5349b4c6 100644 --- a/apps/dashboard/src/components/report-chart/histogram/chart.tsx +++ b/apps/dashboard/src/components/report-chart/histogram/chart.tsx @@ -1,10 +1,10 @@ -import React from 'react'; import { useRechartDataModel } from '@/hooks/useRechartDataModel'; import { useVisibleSeries } from '@/hooks/useVisibleSeries'; import type { IChartData } from '@/trpc/client'; import { cn } from '@/utils/cn'; import { getChartColor, theme } from '@/utils/theme'; import { useTheme } from 'next-themes'; +import React from 'react'; import { Bar, BarChart, diff --git a/apps/dashboard/src/components/report-chart/index.tsx b/apps/dashboard/src/components/report-chart/index.tsx index 92dad234..c1c57630 100644 --- a/apps/dashboard/src/components/report-chart/index.tsx +++ b/apps/dashboard/src/components/report-chart/index.tsx @@ -1,7 +1,7 @@ 'use client'; -import React, { useEffect, useRef } from 'react'; import { mergeDeepRight } from 'ramda'; +import React, { useEffect, useRef } from 'react'; import { useInViewport } from 'react-in-viewport'; import { ReportAreaChart } from './area'; diff --git a/apps/dashboard/src/components/report-chart/line/chart.tsx b/apps/dashboard/src/components/report-chart/line/chart.tsx index a86d55fd..55550d83 100644 --- a/apps/dashboard/src/components/report-chart/line/chart.tsx +++ b/apps/dashboard/src/components/report-chart/line/chart.tsx @@ -1,6 +1,5 @@ 'use client'; -import React, { useCallback } from 'react'; import { useRechartDataModel } from '@/hooks/useRechartDataModel'; import { useVisibleSeries } from '@/hooks/useVisibleSeries'; import { api } from '@/trpc/client'; @@ -9,6 +8,7 @@ import { cn } from '@/utils/cn'; import { getChartColor } from '@/utils/theme'; import { isSameDay, isSameHour, isSameMonth } from 'date-fns'; import { last } from 'ramda'; +import React, { useCallback } from 'react'; import { Area, CartesianGrid, @@ -57,7 +57,7 @@ export function Chart({ data }: Props) { }, { staleTime: 1000 * 60 * 10, - } + }, ); const { series, setVisibleSeries } = useVisibleSeries(data); const rechartData = useRechartDataModel(series); @@ -73,7 +73,7 @@ export function Chart({ data }: Props) { id: string, col1: string, col2: string, - percentChange: number + percentChange: number, ) => ( @@ -177,29 +177,25 @@ export function Chart({ data }: Props) { x2="0" y2="1" > - + + /> )} {gradientTwoColors( `hideAllButLastInterval_${serie.id}`, 'rgba(0,0,0,0)', color, - lastIntervalPercent + lastIntervalPercent, )} {gradientTwoColors( `hideJustLastInterval_${serie.id}`, color, 'rgba(0,0,0,0)', - lastIntervalPercent + lastIntervalPercent, )} {series.map((serie) => { diff --git a/apps/dashboard/src/components/report-chart/metric/index.tsx b/apps/dashboard/src/components/report-chart/metric/index.tsx index fbcb8ff3..7c82b8a3 100644 --- a/apps/dashboard/src/components/report-chart/metric/index.tsx +++ b/apps/dashboard/src/components/report-chart/metric/index.tsx @@ -29,10 +29,10 @@ export function ReportMetricChart() { export function Loading() { return (
-
+
-
-
+
+
); diff --git a/apps/dashboard/src/components/report-chart/metric/metric-card.tsx b/apps/dashboard/src/components/report-chart/metric/metric-card.tsx index db9bd5a4..5a29ed20 100644 --- a/apps/dashboard/src/components/report-chart/metric/metric-card.tsx +++ b/apps/dashboard/src/components/report-chart/metric/metric-card.tsx @@ -9,8 +9,8 @@ import { Area, AreaChart } from 'recharts'; import type { IChartMetric } from '@openpanel/validation'; import { - getDiffIndicator, PreviousDiffIndicator, + getDiffIndicator, } from '../common/previous-diff-indicator'; import { SerieName } from '../common/serie-name'; import { useReportChartContext } from '../context'; @@ -54,7 +54,7 @@ export function MetricCard({ previous?.state, '#6ee7b7', // green '#fda4af', // red - '#93c5fd' // blue + '#93c5fd', // blue ); return ( @@ -64,7 +64,7 @@ export function MetricCard({ >
diff --git a/apps/dashboard/src/components/report/ReportLineType.tsx b/apps/dashboard/src/components/report/ReportLineType.tsx index 2e2e29b2..3f9e21e0 100644 --- a/apps/dashboard/src/components/report/ReportLineType.tsx +++ b/apps/dashboard/src/components/report/ReportLineType.tsx @@ -15,7 +15,7 @@ export function ReportLineType({ className }: ReportLineTypeProps) { const chartType = useSelector((state) => state.report.chartType); const type = useSelector((state) => state.report.lineType); - if (chartType != 'linear' && chartType != 'area') { + if (chartType !== 'linear' && chartType !== 'area') { return null; } diff --git a/apps/dashboard/src/components/report/ReportSaveButton.tsx b/apps/dashboard/src/components/report/ReportSaveButton.tsx index aa5f0f11..f00fa372 100644 --- a/apps/dashboard/src/components/report/ReportSaveButton.tsx +++ b/apps/dashboard/src/components/report/ReportSaveButton.tsx @@ -44,20 +44,19 @@ export function ReportSaveButton({ className }: ReportSaveButtonProps) { Update ); - } else { - return ( - - ); } + return ( + + ); } diff --git a/apps/dashboard/src/components/report/edit-report-name.tsx b/apps/dashboard/src/components/report/edit-report-name.tsx index 10c923a6..8cf39e00 100644 --- a/apps/dashboard/src/components/report/edit-report-name.tsx +++ b/apps/dashboard/src/components/report/edit-report-name.tsx @@ -1,7 +1,7 @@ 'use client'; -import { useState } from 'react'; import { PencilIcon } from 'lucide-react'; +import { useState } from 'react'; type Props = { name?: string; @@ -23,7 +23,7 @@ const EditReportName = ({ name }: Props) => { window.dispatchEvent( new CustomEvent('report-name-change', { detail: newName === '' ? name : newName, - }) + }), ); setIsEditing(false); @@ -33,8 +33,6 @@ const EditReportName = ({ name }: Props) => { return (
{ @@ -53,6 +51,7 @@ const EditReportName = ({ name }: Props) => { return ( diff --git a/apps/dashboard/src/components/settings-toggle.tsx b/apps/dashboard/src/components/settings-toggle.tsx index 2a49c56d..75f0e7d4 100644 --- a/apps/dashboard/src/components/settings-toggle.tsx +++ b/apps/dashboard/src/components/settings-toggle.tsx @@ -1,6 +1,5 @@ 'use client'; -import * as React from 'react'; import { Button } from '@/components/ui/button'; import { DropdownMenu, @@ -16,6 +15,7 @@ import { } from '@/components/ui/dropdown-menu'; import { CheckIcon, MoreHorizontalIcon, PlusIcon } from 'lucide-react'; import { useTheme } from 'next-themes'; +import * as React from 'react'; import { ProjectLink } from './links'; diff --git a/apps/dashboard/src/components/settings/invites/columns.tsx b/apps/dashboard/src/components/settings/invites/columns.tsx index 10fb374c..c5c54c4c 100644 --- a/apps/dashboard/src/components/settings/invites/columns.tsx +++ b/apps/dashboard/src/components/settings/invites/columns.tsx @@ -17,7 +17,7 @@ import { toast } from 'sonner'; import type { IServiceInvite, IServiceProject } from '@openpanel/db'; export function useColumns( - projects: IServiceProject[] + projects: IServiceProject[], ): ColumnDef[] { return [ { diff --git a/apps/dashboard/src/components/settings/invites/index.tsx b/apps/dashboard/src/components/settings/invites/index.tsx index d7d35cf5..e9cf7ebb 100644 --- a/apps/dashboard/src/components/settings/invites/index.tsx +++ b/apps/dashboard/src/components/settings/invites/index.tsx @@ -21,11 +21,11 @@ export const InvitesTable = ({ projects, data }: Props) => { if (!data) { return (
-
-
-
-
-
+
+
+
+
+
); } diff --git a/apps/dashboard/src/components/settings/members/columns.tsx b/apps/dashboard/src/components/settings/members/columns.tsx index 23ff9cac..93ed5b03 100644 --- a/apps/dashboard/src/components/settings/members/columns.tsx +++ b/apps/dashboard/src/components/settings/members/columns.tsx @@ -1,4 +1,3 @@ -import { useState } from 'react'; import { TooltipComplete } from '@/components/tooltip-complete'; import { Button } from '@/components/ui/button'; import { ComboboxAdvanced } from '@/components/ui/combobox-advanced'; @@ -12,6 +11,7 @@ import { api } from '@/trpc/client'; import type { ColumnDef, Row } from '@tanstack/react-table'; import { MoreHorizontalIcon } from 'lucide-react'; import { useRouter } from 'next/navigation'; +import { useState } from 'react'; import { toast } from 'sonner'; import type { IServiceMember, IServiceProject } from '@openpanel/db'; @@ -77,7 +77,7 @@ function AccessCell({ projects: IServiceProject[]; }) { const [access, setAccess] = useState( - row.original.access.map((item) => item.projectId) + row.original.access.map((item) => item.projectId), ); const mutation = api.organization.updateMemberAccess.useMutation(); @@ -106,13 +106,13 @@ function ActionsCell({ row }: { row: Row }) { const revoke = api.organization.removeMember.useMutation({ onSuccess() { toast.success( - `${row.original.user?.firstName} has been removed from the organization` + `${row.original.user?.firstName} has been removed from the organization`, ); router.refresh(); }, onError() { toast.error( - `Failed to remove ${row.original.user?.firstName} from the organization` + `Failed to remove ${row.original.user?.firstName} from the organization`, ); }, }); diff --git a/apps/dashboard/src/components/settings/members/index.tsx b/apps/dashboard/src/components/settings/members/index.tsx index b08e7463..41aed16d 100644 --- a/apps/dashboard/src/components/settings/members/index.tsx +++ b/apps/dashboard/src/components/settings/members/index.tsx @@ -21,11 +21,11 @@ export const MembersTable = ({ projects, data }: Props) => { if (!data) { return (
-
-
-
-
-
+
+
+
+
+
); } diff --git a/apps/dashboard/src/components/stats.tsx b/apps/dashboard/src/components/stats.tsx index ce455320..ed3850d0 100644 --- a/apps/dashboard/src/components/stats.tsx +++ b/apps/dashboard/src/components/stats.tsx @@ -12,7 +12,7 @@ export function Stats({
diff --git a/apps/dashboard/src/components/syntax.tsx b/apps/dashboard/src/components/syntax.tsx index 441c97b1..d243199b 100644 --- a/apps/dashboard/src/components/syntax.tsx +++ b/apps/dashboard/src/components/syntax.tsx @@ -16,6 +16,7 @@ export default function Syntax({ code }: SyntaxProps) { return (