Skip to content

Commit 5e58475

Browse files
committed
fix: loading states
1 parent 156a80e commit 5e58475

File tree

5 files changed

+481
-4
lines changed

5 files changed

+481
-4
lines changed

apps/api/src/query/builders/devices.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,4 +402,131 @@ export const DevicesBuilders: Record<string, SimpleQueryConfig> = {
402402
timeField: 'time',
403403
customizable: true,
404404
},
405+
406+
viewport_vs_resolution: {
407+
meta: {
408+
title: 'Viewport vs Screen Resolution',
409+
description:
410+
'Comparison between actual screen resolution and browser viewport size, showing how users browse your site.',
411+
category: 'Technology',
412+
tags: ['viewport', 'resolution', 'browser', 'responsive'],
413+
output_fields: [
414+
{
415+
name: 'screen_resolution',
416+
type: 'string',
417+
label: 'Screen Resolution',
418+
description: 'Physical screen resolution',
419+
},
420+
{
421+
name: 'viewport_size',
422+
type: 'string',
423+
label: 'Viewport Size',
424+
description: 'Browser viewport dimensions',
425+
},
426+
{
427+
name: 'visitors',
428+
type: 'number',
429+
label: 'Visitors',
430+
description: 'Unique visitors with this combination',
431+
},
432+
{
433+
name: 'device_type',
434+
type: 'string',
435+
label: 'Device Type',
436+
description: 'Device category',
437+
},
438+
{
439+
name: 'usage_pattern',
440+
type: 'string',
441+
label: 'Usage Pattern',
442+
description: 'Browsing behavior pattern',
443+
},
444+
],
445+
default_visualization: 'table',
446+
supports_granularity: ['hour', 'day'],
447+
version: '1.0',
448+
},
449+
table: Analytics.events,
450+
fields: [
451+
'screen_resolution',
452+
'viewport_size',
453+
'COUNT(DISTINCT anonymous_id) as visitors',
454+
'COUNT(*) as pageviews',
455+
'any(device_type) as device_type',
456+
'CASE ' +
457+
'WHEN screen_resolution = viewport_size THEN "Full Screen" ' +
458+
'WHEN screen_resolution != viewport_size THEN "Windowed" ' +
459+
'ELSE "Unknown" ' +
460+
'END as usage_pattern',
461+
],
462+
where: [
463+
"event_name = 'screen_view'",
464+
"screen_resolution != ''",
465+
"viewport_size != ''",
466+
'screen_resolution IS NOT NULL',
467+
'viewport_size IS NOT NULL',
468+
],
469+
groupBy: ['screen_resolution', 'viewport_size', 'device_type'],
470+
orderBy: 'visitors DESC',
471+
limit: 200,
472+
timeField: 'time',
473+
allowedFilters: ['device_type', 'browser_name', 'os_name', 'country'],
474+
customizable: true,
475+
},
476+
477+
viewport_patterns: {
478+
meta: {
479+
title: 'Viewport Usage Patterns',
480+
description:
481+
'Analysis of how users browse - full screen vs windowed, and common viewport sizes.',
482+
category: 'Technology',
483+
tags: ['viewport', 'browsing patterns', 'user behavior'],
484+
output_fields: [
485+
{
486+
name: 'usage_pattern',
487+
type: 'string',
488+
label: 'Usage Pattern',
489+
description: 'How users browse (full screen vs windowed)',
490+
},
491+
{
492+
name: 'visitors',
493+
type: 'number',
494+
label: 'Visitors',
495+
description: 'Unique visitors using this pattern',
496+
},
497+
{
498+
name: 'percentage',
499+
type: 'number',
500+
label: 'Share',
501+
description: 'Percentage of total visitors',
502+
unit: '%',
503+
},
504+
],
505+
default_visualization: 'pie',
506+
supports_granularity: ['hour', 'day'],
507+
version: '1.0',
508+
},
509+
table: Analytics.events,
510+
fields: [
511+
'CASE ' +
512+
'WHEN screen_resolution = viewport_size THEN "Full Screen Browsing" ' +
513+
'WHEN screen_resolution != viewport_size THEN "Windowed Browsing" ' +
514+
'ELSE "Unknown Pattern" ' +
515+
'END as usage_pattern',
516+
'COUNT(DISTINCT anonymous_id) as visitors',
517+
'COUNT(DISTINCT session_id) as sessions',
518+
'ROUND((COUNT(DISTINCT anonymous_id) / SUM(COUNT(DISTINCT anonymous_id)) OVER()) * 100, 2) as percentage',
519+
],
520+
where: [
521+
"event_name = 'screen_view'",
522+
"screen_resolution != ''",
523+
"viewport_size != ''",
524+
'screen_resolution IS NOT NULL',
525+
'viewport_size IS NOT NULL',
526+
],
527+
groupBy: ['usage_pattern'],
528+
orderBy: 'visitors DESC',
529+
timeField: 'time',
530+
customizable: true,
531+
},
405532
};
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import { Analytics } from '../../types/tables';
2+
import type { SimpleQueryConfig } from '../types';
3+
4+
export const EngagementBuilders: Record<string, SimpleQueryConfig> = {
5+
scroll_depth_summary: {
6+
meta: {
7+
title: 'Scroll Depth Summary',
8+
description:
9+
'Average scroll depth metrics showing how far users scroll on pages.',
10+
category: 'Engagement',
11+
tags: ['scroll', 'engagement', 'user behavior'],
12+
output_fields: [
13+
{
14+
name: 'avg_scroll_depth',
15+
type: 'number',
16+
label: 'Average Scroll Depth',
17+
description: 'Average percentage of page scrolled',
18+
unit: '%',
19+
},
20+
{
21+
name: 'total_sessions',
22+
type: 'number',
23+
label: 'Total Sessions',
24+
description: 'Total sessions with scroll data',
25+
},
26+
],
27+
default_visualization: 'metric',
28+
supports_granularity: ['hour', 'day'],
29+
version: '1.0',
30+
},
31+
table: Analytics.events,
32+
fields: [
33+
'ROUND(AVG(CASE WHEN scroll_depth > 0 THEN scroll_depth * 100 ELSE NULL END), 1) as avg_scroll_depth',
34+
'COUNT(DISTINCT session_id) as total_sessions',
35+
'COUNT(DISTINCT anonymous_id) as visitors',
36+
],
37+
where: ["event_name = 'screen_view'", 'scroll_depth > 0'],
38+
timeField: 'time',
39+
customizable: true,
40+
},
41+
42+
scroll_depth_distribution: {
43+
meta: {
44+
title: 'Scroll Depth Distribution',
45+
description:
46+
'Breakdown of users by how far they scroll on pages, grouped into ranges.',
47+
category: 'Engagement',
48+
tags: ['scroll', 'distribution', 'engagement'],
49+
output_fields: [
50+
{
51+
name: 'depth_range',
52+
type: 'string',
53+
label: 'Scroll Range',
54+
description: 'Percentage range of page scrolled',
55+
},
56+
{
57+
name: 'visitors',
58+
type: 'number',
59+
label: 'Visitors',
60+
description: 'Unique visitors in this range',
61+
},
62+
{
63+
name: 'sessions',
64+
type: 'number',
65+
label: 'Sessions',
66+
description: 'Sessions in this range',
67+
},
68+
{
69+
name: 'percentage',
70+
type: 'number',
71+
label: 'Share',
72+
description: 'Percentage of total sessions',
73+
unit: '%',
74+
},
75+
],
76+
default_visualization: 'bar',
77+
supports_granularity: ['hour', 'day'],
78+
version: '1.0',
79+
},
80+
table: Analytics.events,
81+
fields: [
82+
'CASE ' +
83+
'WHEN scroll_depth < 0.25 THEN "0-25%" ' +
84+
'WHEN scroll_depth < 0.5 THEN "25-50%" ' +
85+
'WHEN scroll_depth < 0.75 THEN "50-75%" ' +
86+
'WHEN scroll_depth < 1.0 THEN "75-100%" ' +
87+
'ELSE "100%" ' +
88+
'END as depth_range',
89+
'COUNT(DISTINCT anonymous_id) as visitors',
90+
'COUNT(DISTINCT session_id) as sessions',
91+
'ROUND((COUNT(DISTINCT session_id) / SUM(COUNT(DISTINCT session_id)) OVER()) * 100, 2) as percentage',
92+
],
93+
where: ["event_name = 'screen_view'", 'scroll_depth > 0'],
94+
groupBy: ['depth_range'],
95+
orderBy:
96+
'CASE depth_range WHEN "0-25%" THEN 1 WHEN "25-50%" THEN 2 WHEN "50-75%" THEN 3 WHEN "75-100%" THEN 4 ELSE 5 END',
97+
timeField: 'time',
98+
customizable: true,
99+
},
100+
101+
page_scroll_performance: {
102+
meta: {
103+
title: 'Page Scroll Performance',
104+
description:
105+
'Average scroll depth by page, showing which pages engage users most effectively.',
106+
category: 'Engagement',
107+
tags: ['pages', 'scroll', 'performance'],
108+
output_fields: [
109+
{
110+
name: 'name',
111+
type: 'string',
112+
label: 'Page Path',
113+
description: 'The page URL path',
114+
},
115+
{
116+
name: 'avg_scroll_depth',
117+
type: 'number',
118+
label: 'Avg Scroll Depth',
119+
description: 'Average scroll depth percentage',
120+
unit: '%',
121+
},
122+
{
123+
name: 'visitors',
124+
type: 'number',
125+
label: 'Visitors',
126+
description: 'Unique visitors to this page',
127+
},
128+
{
129+
name: 'sessions',
130+
type: 'number',
131+
label: 'Sessions',
132+
description: 'Sessions on this page',
133+
},
134+
],
135+
default_visualization: 'table',
136+
supports_granularity: ['hour', 'day'],
137+
version: '1.0',
138+
},
139+
table: Analytics.events,
140+
fields: [
141+
"trimRight(path(path), '/') as name",
142+
'ROUND(AVG(CASE WHEN scroll_depth > 0 THEN scroll_depth * 100 ELSE NULL END), 1) as avg_scroll_depth',
143+
'COUNT(DISTINCT anonymous_id) as visitors',
144+
'COUNT(DISTINCT session_id) as sessions',
145+
'COUNT(*) as pageviews',
146+
],
147+
where: ["event_name = 'screen_view'", "path != ''", 'scroll_depth > 0'],
148+
groupBy: ["trimRight(path(path), '/')"],
149+
orderBy: 'avg_scroll_depth DESC',
150+
limit: 100,
151+
timeField: 'time',
152+
allowedFilters: [
153+
'path',
154+
'country',
155+
'device_type',
156+
'browser_name',
157+
'os_name',
158+
'referrer',
159+
],
160+
customizable: true,
161+
},
162+
163+
interaction_summary: {
164+
meta: {
165+
title: 'Interaction Summary',
166+
description:
167+
'Summary of user interactions including click, scroll, and keyboard events.',
168+
category: 'Engagement',
169+
tags: ['interactions', 'engagement', 'user behavior'],
170+
output_fields: [
171+
{
172+
name: 'avg_interactions',
173+
type: 'number',
174+
label: 'Average Interactions',
175+
description: 'Average number of interactions per session',
176+
},
177+
{
178+
name: 'interactive_sessions',
179+
type: 'number',
180+
label: 'Interactive Sessions',
181+
description: 'Sessions with at least one interaction',
182+
},
183+
{
184+
name: 'interaction_rate',
185+
type: 'number',
186+
label: 'Interaction Rate',
187+
description: 'Percentage of sessions with interactions',
188+
unit: '%',
189+
},
190+
],
191+
default_visualization: 'metric',
192+
supports_granularity: ['hour', 'day'],
193+
version: '1.0',
194+
},
195+
table: Analytics.events,
196+
fields: [
197+
'ROUND(AVG(CASE WHEN interaction_count >= 0 THEN interaction_count ELSE NULL END), 1) as avg_interactions',
198+
'COUNT(DISTINCT CASE WHEN interaction_count > 0 THEN session_id ELSE NULL END) as interactive_sessions',
199+
'ROUND((COUNT(DISTINCT CASE WHEN interaction_count > 0 THEN session_id ELSE NULL END) / COUNT(DISTINCT session_id)) * 100, 1) as interaction_rate',
200+
'COUNT(DISTINCT session_id) as total_sessions',
201+
],
202+
where: ["event_name = 'screen_view'", 'interaction_count >= 0'],
203+
timeField: 'time',
204+
customizable: true,
205+
},
206+
};

apps/api/src/query/builders/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { CustomEventsBuilders } from './custom-events';
22
import { DevicesBuilders } from './devices';
3+
import { EngagementBuilders } from './engagement';
34
import { ErrorsBuilders } from './errors';
45
import { GeoBuilders } from './geo';
56
import { LinksBuilders } from './links';
@@ -22,6 +23,7 @@ export const QueryBuilders = {
2223
...CustomEventsBuilders,
2324
...ProfilesBuilders,
2425
...LinksBuilders,
26+
...EngagementBuilders,
2527
};
2628

2729
export type QueryType = keyof typeof QueryBuilders;

0 commit comments

Comments
 (0)