From 91331bda7ec0e130da124ec3ad9b71f13660b9e1 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Thu, 13 Mar 2025 09:11:46 -0700 Subject: [PATCH] fix: Record correct diagram type, send playground toggle event immediately. --- src/lib/components/View.svelte | 11 ++-- src/lib/util/stats.test.ts | 19 ------- src/lib/util/stats.ts | 92 +++++++++++++--------------------- 3 files changed, 42 insertions(+), 80 deletions(-) delete mode 100644 src/lib/util/stats.test.ts diff --git a/src/lib/components/View.svelte b/src/lib/components/View.svelte index 6b3d108a..0e1c860b 100644 --- a/src/lib/components/View.svelte +++ b/src/lib/components/View.svelte @@ -67,6 +67,7 @@ return; } error = false; + let diagramType: string | undefined; try { if (container && state && (state.updateDiagram || state.autoSync)) { if (!state.autoSync) { @@ -95,12 +96,16 @@ rough = state.rough; const scroll = view?.parentElement?.scrollTop; delete container.dataset.processed; - const { svg, bindFunctions } = await renderDiagram( + const { + svg, + bindFunctions, + diagramType: detectedDiagramType + } = await renderDiagram( Object.assign({}, JSON.parse(state.mermaid)) as MermaidConfig, code, 'graph-div' ); - + diagramType = detectedDiagramType; if (svg.length > 0) { handlePanZoom(state); container.innerHTML = svg; @@ -145,7 +150,7 @@ error = true; } const renderTime = Date.now() - startTime; - saveStatistics({ code, renderTime, isRough: state.rough }); + saveStatistics({ code, renderTime, isRough: state.rough, diagramType }); recordRenderTime(renderTime, () => { $inputStateStore.updateDiagram = true; }); diff --git a/src/lib/util/stats.test.ts b/src/lib/util/stats.test.ts deleted file mode 100644 index 518a55b1..00000000 --- a/src/lib/util/stats.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { detectType } from './stats'; -describe('diagram detection', () => { - it('should detect diagrams correctly', () => { - expect( - detectType(`%%{{ - graph`) - ).toBe('graph'); - expect(detectType(`gitGraph`)).toBe('gitGraph'); - expect( - detectType(`%%{{ - - - flowChart - graph`) - ).toBe('flowChart'); - expect(detectType(`loki -> thor`)).toBe(undefined); - }); -}); diff --git a/src/lib/util/stats.ts b/src/lib/util/stats.ts index 7a360ace..1e7aa67a 100644 --- a/src/lib/util/stats.ts +++ b/src/lib/util/stats.ts @@ -1,6 +1,7 @@ import { browser } from '$app/environment'; import type PlausibleInstance from 'plausible-tracker'; import { env } from './env'; + export let plausible: ReturnType | undefined; export const initAnalytics = async (): Promise => { @@ -20,29 +21,6 @@ export const initAnalytics = async (): Promise => { } }; -export const detectType = (text: string): string | undefined => { - const possibleDiagramTypes = [ - 'classDiagram', - 'erDiagram', - 'flowChart', - 'gantt', - 'gitGraph', - 'graph', - 'journey', - 'pie', - 'stateDiagram', - 'quadrantChart', - 'mindmap' - ]; - const firstLine = text - .replaceAll(/^\s*%%.*\n/g, '\n') - .trimStart() - .split(' ')[0] - .toLowerCase(); - const detectedDiagram = possibleDiagramTypes.find((d) => firstLine.includes(d.toLowerCase())); - return detectedDiagram; -}; - export const countLines = (code: string): number => { return (code.match(/\n/g)?.length ?? 0) + 1; }; @@ -50,50 +28,47 @@ export const countLines = (code: string): number => { export const saveStatistics = ({ code, renderTime, - isRough + isRough, + diagramType }: { code: string; renderTime: number; isRough: boolean; + diagramType?: string; }): void => { - const graphType = detectType(code); - if (!graphType) { + if (!diagramType) { return; } const length = countLines(code); const lengthBucket = getBucket(length); const renderTimeMsBucket = getBucket(renderTime); - logEvent('render', { graphType, length, lengthBucket, renderTimeMsBucket, isRough }); + logEvent('render', { diagramType, lengthBucket, renderTimeMsBucket, isRough }); }; const getBucket = (length: number): string => { - return length < 10 - ? '0-10' - : length < 25 - ? '10-25' - : length < 50 - ? '25-50' - : length < 100 - ? '50-100' - : length < 200 - ? '100-200' - : length < 500 - ? '200-500' - : length < 700 - ? '500-700' - : length < 1000 - ? '700-1000' - : length < 1500 - ? '1000-1500' - : length < 2500 - ? '1500-2500' - : length < 4500 - ? '2500-4500' - : length < 7000 - ? '4500-7000' - : length < 10_000 - ? '7000-10000' - : '10000+'; + const buckets = [ + [10, '0-10'], + [25, '10-25'], + [50, '25-50'], + [100, '50-100'], + [200, '100-200'], + [500, '200-500'], + [700, '500-700'], + [1000, '700-1000'], + [1500, '1000-1500'], + [2500, '1500-2500'], + [4500, '2500-4500'], + [7000, '4500-7000'], + [10_000, '7000-10000'] + ] as const; + + for (const [threshold, label] of buckets) { + if (length < threshold) { + return label; + } + } + + return '10000+'; }; const minutesToMilliSeconds = (minutes: number): number => { @@ -104,7 +79,7 @@ const defaultDelay = minutesToMilliSeconds(1); const delaysPerEvent = { render: minutesToMilliSeconds(5), panZoom: minutesToMilliSeconds(10), - playgroundToggle: defaultDelay, + playgroundToggle: 0, copyClipboard: defaultDelay, download: defaultDelay, copyMarkdown: defaultDelay, @@ -116,7 +91,7 @@ const delaysPerEvent = { themeChange: defaultDelay, bannerClick: defaultDelay, version: defaultDelay -}; +} as const; export type AnalyticsEvent = keyof typeof delaysPerEvent; const timeouts: Map = new Map(); // manual debounce to reduce the number of events sent to analytics @@ -128,7 +103,8 @@ export const logEvent = ( return; } const key = data ? JSON.stringify({ name, data }) : name; - if (timeouts.has(key)) { + const delay = delaysPerEvent[name]; + if (timeouts.has(key) && delay > 0) { clearTimeout(timeouts.get(key)); } else { plausible.trackEvent( @@ -139,6 +115,6 @@ export const logEvent = ( } timeouts.set( key, - window.setTimeout(() => timeouts.delete(key), delaysPerEvent[name]) + window.setTimeout(() => timeouts.delete(key), delay) ); };