@contractspec/example.analytics-dashboard 0.0.0-canary-20260113170453
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +281 -0
- package/dist/dashboard/dashboard.enum.d.ts +18 -0
- package/dist/dashboard/dashboard.enum.d.ts.map +1 -0
- package/dist/dashboard/dashboard.enum.js +43 -0
- package/dist/dashboard/dashboard.enum.js.map +1 -0
- package/dist/dashboard/dashboard.operation.d.ts +537 -0
- package/dist/dashboard/dashboard.operation.d.ts.map +1 -0
- package/dist/dashboard/dashboard.operation.js +213 -0
- package/dist/dashboard/dashboard.operation.js.map +1 -0
- package/dist/dashboard/dashboard.presentation.d.ts +9 -0
- package/dist/dashboard/dashboard.presentation.d.ts.map +1 -0
- package/dist/dashboard/dashboard.presentation.js +90 -0
- package/dist/dashboard/dashboard.presentation.js.map +1 -0
- package/dist/dashboard/dashboard.schema.d.ts +333 -0
- package/dist/dashboard/dashboard.schema.d.ts.map +1 -0
- package/dist/dashboard/dashboard.schema.js +236 -0
- package/dist/dashboard/dashboard.schema.js.map +1 -0
- package/dist/dashboard/dashboard.test-spec.d.ts +10 -0
- package/dist/dashboard/dashboard.test-spec.d.ts.map +1 -0
- package/dist/dashboard/dashboard.test-spec.js +233 -0
- package/dist/dashboard/dashboard.test-spec.js.map +1 -0
- package/dist/dashboard/index.d.ts +4 -0
- package/dist/dashboard/index.js +5 -0
- package/dist/dashboard.feature.d.ts +17 -0
- package/dist/dashboard.feature.d.ts.map +1 -0
- package/dist/dashboard.feature.js +177 -0
- package/dist/dashboard.feature.js.map +1 -0
- package/dist/docs/analytics-dashboard.docblock.d.ts +1 -0
- package/dist/docs/analytics-dashboard.docblock.js +114 -0
- package/dist/docs/analytics-dashboard.docblock.js.map +1 -0
- package/dist/docs/index.d.ts +1 -0
- package/dist/docs/index.js +1 -0
- package/dist/events.d.ts +149 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +128 -0
- package/dist/events.js.map +1 -0
- package/dist/example.d.ts +7 -0
- package/dist/example.d.ts.map +1 -0
- package/dist/example.js +58 -0
- package/dist/example.js.map +1 -0
- package/dist/handlers/analytics.handlers.d.ts +122 -0
- package/dist/handlers/analytics.handlers.d.ts.map +1 -0
- package/dist/handlers/analytics.handlers.js +310 -0
- package/dist/handlers/analytics.handlers.js.map +1 -0
- package/dist/handlers/index.d.ts +2 -0
- package/dist/handlers/index.js +3 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -0
- package/dist/query/index.d.ts +4 -0
- package/dist/query/index.js +5 -0
- package/dist/query/query.enum.d.ts +10 -0
- package/dist/query/query.enum.d.ts.map +1 -0
- package/dist/query/query.enum.js +16 -0
- package/dist/query/query.enum.js.map +1 -0
- package/dist/query/query.operation.d.ts +181 -0
- package/dist/query/query.operation.d.ts.map +1 -0
- package/dist/query/query.operation.js +113 -0
- package/dist/query/query.operation.js.map +1 -0
- package/dist/query/query.presentation.d.ts +8 -0
- package/dist/query/query.presentation.d.ts.map +1 -0
- package/dist/query/query.presentation.js +60 -0
- package/dist/query/query.presentation.js.map +1 -0
- package/dist/query/query.schema.d.ts +143 -0
- package/dist/query/query.schema.d.ts.map +1 -0
- package/dist/query/query.schema.js +157 -0
- package/dist/query/query.schema.js.map +1 -0
- package/dist/query/query.test-spec.d.ts +8 -0
- package/dist/query/query.test-spec.d.ts.map +1 -0
- package/dist/query/query.test-spec.js +124 -0
- package/dist/query/query.test-spec.js.map +1 -0
- package/dist/query-engine/index.d.ts +106 -0
- package/dist/query-engine/index.d.ts.map +1 -0
- package/dist/query-engine/index.js +189 -0
- package/dist/query-engine/index.js.map +1 -0
- package/dist/seeders/index.d.ts +10 -0
- package/dist/seeders/index.d.ts.map +1 -0
- package/dist/seeders/index.js +19 -0
- package/dist/seeders/index.js.map +1 -0
- package/dist/ui/AnalyticsDashboard.d.ts +7 -0
- package/dist/ui/AnalyticsDashboard.d.ts.map +1 -0
- package/dist/ui/AnalyticsDashboard.js +265 -0
- package/dist/ui/AnalyticsDashboard.js.map +1 -0
- package/dist/ui/hooks/index.d.ts +2 -0
- package/dist/ui/hooks/index.js +5 -0
- package/dist/ui/hooks/useAnalyticsData.d.ts +23 -0
- package/dist/ui/hooks/useAnalyticsData.d.ts.map +1 -0
- package/dist/ui/hooks/useAnalyticsData.js +73 -0
- package/dist/ui/hooks/useAnalyticsData.js.map +1 -0
- package/dist/ui/index.d.ts +6 -0
- package/dist/ui/index.js +6 -0
- package/dist/ui/renderers/analytics.markdown.d.ts +28 -0
- package/dist/ui/renderers/analytics.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/analytics.markdown.js +264 -0
- package/dist/ui/renderers/analytics.markdown.js.map +1 -0
- package/dist/ui/renderers/index.d.ts +2 -0
- package/dist/ui/renderers/index.js +3 -0
- package/package.json +101 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useAnalyticsData } from "./hooks/useAnalyticsData.js";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { Button, ErrorState, LoaderBlock, StatCard, StatCardGroup } from "@contractspec/lib.design-system";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
|
|
8
|
+
//#region src/ui/AnalyticsDashboard.tsx
|
|
9
|
+
/**
|
|
10
|
+
* Analytics Dashboard
|
|
11
|
+
*
|
|
12
|
+
* Interactive dashboard for the analytics-dashboard template.
|
|
13
|
+
* Displays dashboards, widgets, and queries.
|
|
14
|
+
*/
|
|
15
|
+
const STATUS_COLORS = {
|
|
16
|
+
PUBLISHED: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
|
|
17
|
+
DRAFT: "bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400",
|
|
18
|
+
ARCHIVED: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400"
|
|
19
|
+
};
|
|
20
|
+
const WIDGET_ICONS = {
|
|
21
|
+
LINE_CHART: "📈",
|
|
22
|
+
BAR_CHART: "📊",
|
|
23
|
+
PIE_CHART: "🥧",
|
|
24
|
+
AREA_CHART: "📉",
|
|
25
|
+
SCATTER_PLOT: "⚬",
|
|
26
|
+
METRIC: "🔢",
|
|
27
|
+
TABLE: "📋",
|
|
28
|
+
HEATMAP: "🗺️",
|
|
29
|
+
FUNNEL: "⏬",
|
|
30
|
+
MAP: "🌍",
|
|
31
|
+
TEXT: "📝",
|
|
32
|
+
EMBED: "🔗"
|
|
33
|
+
};
|
|
34
|
+
const QUERY_TYPE_COLORS = {
|
|
35
|
+
SQL: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400",
|
|
36
|
+
METRIC: "bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400",
|
|
37
|
+
AGGREGATION: "bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-400",
|
|
38
|
+
CUSTOM: "bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400"
|
|
39
|
+
};
|
|
40
|
+
function AnalyticsDashboard() {
|
|
41
|
+
const [activeTab, setActiveTab] = useState("dashboards");
|
|
42
|
+
const { dashboards, queries, selectedDashboard, widgets, loading, error, stats, refetch, selectDashboard } = useAnalyticsData();
|
|
43
|
+
const tabs = [{
|
|
44
|
+
id: "dashboards",
|
|
45
|
+
label: "Dashboards",
|
|
46
|
+
icon: "📊"
|
|
47
|
+
}, {
|
|
48
|
+
id: "queries",
|
|
49
|
+
label: "Queries",
|
|
50
|
+
icon: "🔍"
|
|
51
|
+
}];
|
|
52
|
+
if (loading) return /* @__PURE__ */ jsx(LoaderBlock, { label: "Loading Analytics..." });
|
|
53
|
+
if (error) return /* @__PURE__ */ jsx(ErrorState, {
|
|
54
|
+
title: "Failed to load Analytics",
|
|
55
|
+
description: error.message,
|
|
56
|
+
onRetry: refetch,
|
|
57
|
+
retryLabel: "Retry"
|
|
58
|
+
});
|
|
59
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
60
|
+
className: "space-y-6",
|
|
61
|
+
children: [
|
|
62
|
+
/* @__PURE__ */ jsxs("div", {
|
|
63
|
+
className: "flex items-center justify-between",
|
|
64
|
+
children: [/* @__PURE__ */ jsx("h2", {
|
|
65
|
+
className: "text-2xl font-bold",
|
|
66
|
+
children: "Analytics Dashboard"
|
|
67
|
+
}), /* @__PURE__ */ jsxs(Button, {
|
|
68
|
+
onClick: () => alert("Create dashboard modal"),
|
|
69
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
70
|
+
className: "mr-2",
|
|
71
|
+
children: "+"
|
|
72
|
+
}), " New Dashboard"]
|
|
73
|
+
})]
|
|
74
|
+
}),
|
|
75
|
+
/* @__PURE__ */ jsxs(StatCardGroup, { children: [
|
|
76
|
+
/* @__PURE__ */ jsx(StatCard, {
|
|
77
|
+
label: "Dashboards",
|
|
78
|
+
value: stats.totalDashboards,
|
|
79
|
+
hint: `${stats.publishedDashboards} published`
|
|
80
|
+
}),
|
|
81
|
+
/* @__PURE__ */ jsx(StatCard, {
|
|
82
|
+
label: "Queries",
|
|
83
|
+
value: stats.totalQueries,
|
|
84
|
+
hint: `${stats.sharedQueries} shared`
|
|
85
|
+
}),
|
|
86
|
+
/* @__PURE__ */ jsx(StatCard, {
|
|
87
|
+
label: "Widgets",
|
|
88
|
+
value: widgets.length,
|
|
89
|
+
hint: "on current dashboard"
|
|
90
|
+
})
|
|
91
|
+
] }),
|
|
92
|
+
/* @__PURE__ */ jsx("nav", {
|
|
93
|
+
className: "bg-muted flex gap-1 rounded-lg p-1",
|
|
94
|
+
role: "tablist",
|
|
95
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs(Button, {
|
|
96
|
+
type: "button",
|
|
97
|
+
role: "tab",
|
|
98
|
+
"aria-selected": activeTab === tab.id,
|
|
99
|
+
onClick: () => setActiveTab(tab.id),
|
|
100
|
+
className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
101
|
+
children: [/* @__PURE__ */ jsx("span", { children: tab.icon }), tab.label]
|
|
102
|
+
}, tab.id))
|
|
103
|
+
}),
|
|
104
|
+
/* @__PURE__ */ jsxs("div", {
|
|
105
|
+
className: "min-h-[400px]",
|
|
106
|
+
role: "tabpanel",
|
|
107
|
+
children: [activeTab === "dashboards" && /* @__PURE__ */ jsxs("div", {
|
|
108
|
+
className: "space-y-6",
|
|
109
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
110
|
+
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
111
|
+
children: [dashboards.map((dashboard) => /* @__PURE__ */ jsxs("div", {
|
|
112
|
+
onClick: () => selectDashboard(dashboard),
|
|
113
|
+
className: `border-border bg-card cursor-pointer rounded-lg border p-4 transition-all ${selectedDashboard?.id === dashboard.id ? "ring-primary ring-2" : "hover:bg-muted/50"}`,
|
|
114
|
+
role: "button",
|
|
115
|
+
tabIndex: 0,
|
|
116
|
+
onKeyDown: (e) => {
|
|
117
|
+
if (e.key === "Enter" || e.key === " ") selectDashboard(dashboard);
|
|
118
|
+
},
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ jsxs("div", {
|
|
121
|
+
className: "mb-2 flex items-center justify-between",
|
|
122
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
123
|
+
className: "font-medium",
|
|
124
|
+
children: dashboard.name
|
|
125
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
126
|
+
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[dashboard.status] ?? ""}`,
|
|
127
|
+
children: dashboard.status
|
|
128
|
+
})]
|
|
129
|
+
}),
|
|
130
|
+
/* @__PURE__ */ jsx("p", {
|
|
131
|
+
className: "text-muted-foreground mb-3 text-sm",
|
|
132
|
+
children: dashboard.description
|
|
133
|
+
}),
|
|
134
|
+
/* @__PURE__ */ jsxs("div", {
|
|
135
|
+
className: "text-muted-foreground flex items-center justify-between text-xs",
|
|
136
|
+
children: [/* @__PURE__ */ jsxs("span", { children: ["/", dashboard.slug] }), dashboard.isPublic && /* @__PURE__ */ jsx("span", {
|
|
137
|
+
className: "text-green-600 dark:text-green-400",
|
|
138
|
+
children: "🌐 Public"
|
|
139
|
+
})]
|
|
140
|
+
})
|
|
141
|
+
]
|
|
142
|
+
}, dashboard.id)), dashboards.length === 0 && /* @__PURE__ */ jsx("div", {
|
|
143
|
+
className: "text-muted-foreground col-span-full flex h-64 items-center justify-center",
|
|
144
|
+
children: "No dashboards created yet"
|
|
145
|
+
})]
|
|
146
|
+
}), selectedDashboard && widgets.length > 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("h3", {
|
|
147
|
+
className: "mb-4 text-lg font-semibold",
|
|
148
|
+
children: [
|
|
149
|
+
"Widgets in \"",
|
|
150
|
+
selectedDashboard.name,
|
|
151
|
+
"\""
|
|
152
|
+
]
|
|
153
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
154
|
+
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
155
|
+
children: widgets.map((widget) => /* @__PURE__ */ jsxs("div", {
|
|
156
|
+
className: "border-border bg-card rounded-lg border p-4",
|
|
157
|
+
children: [
|
|
158
|
+
/* @__PURE__ */ jsxs("div", {
|
|
159
|
+
className: "mb-2 flex items-center gap-2",
|
|
160
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
161
|
+
className: "text-xl",
|
|
162
|
+
children: WIDGET_ICONS[widget.type] ?? "📊"
|
|
163
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
164
|
+
className: "font-medium",
|
|
165
|
+
children: widget.name
|
|
166
|
+
})]
|
|
167
|
+
}),
|
|
168
|
+
/* @__PURE__ */ jsx("div", {
|
|
169
|
+
className: "text-muted-foreground text-sm",
|
|
170
|
+
children: widget.type.replace(/_/g, " ")
|
|
171
|
+
}),
|
|
172
|
+
/* @__PURE__ */ jsxs("div", {
|
|
173
|
+
className: "text-muted-foreground mt-2 text-xs",
|
|
174
|
+
children: [
|
|
175
|
+
"Position: (",
|
|
176
|
+
widget.gridX,
|
|
177
|
+
", ",
|
|
178
|
+
widget.gridY,
|
|
179
|
+
") •",
|
|
180
|
+
" ",
|
|
181
|
+
widget.gridWidth,
|
|
182
|
+
"x",
|
|
183
|
+
widget.gridHeight
|
|
184
|
+
]
|
|
185
|
+
})
|
|
186
|
+
]
|
|
187
|
+
}, widget.id))
|
|
188
|
+
})] })]
|
|
189
|
+
}), activeTab === "queries" && /* @__PURE__ */ jsx("div", {
|
|
190
|
+
className: "border-border rounded-lg border",
|
|
191
|
+
children: /* @__PURE__ */ jsxs("table", {
|
|
192
|
+
className: "w-full",
|
|
193
|
+
children: [/* @__PURE__ */ jsx("thead", {
|
|
194
|
+
className: "border-border bg-muted/30 border-b",
|
|
195
|
+
children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
196
|
+
/* @__PURE__ */ jsx("th", {
|
|
197
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
198
|
+
children: "Query"
|
|
199
|
+
}),
|
|
200
|
+
/* @__PURE__ */ jsx("th", {
|
|
201
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
202
|
+
children: "Type"
|
|
203
|
+
}),
|
|
204
|
+
/* @__PURE__ */ jsx("th", {
|
|
205
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
206
|
+
children: "Cache TTL"
|
|
207
|
+
}),
|
|
208
|
+
/* @__PURE__ */ jsx("th", {
|
|
209
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
210
|
+
children: "Shared"
|
|
211
|
+
})
|
|
212
|
+
] })
|
|
213
|
+
}), /* @__PURE__ */ jsxs("tbody", {
|
|
214
|
+
className: "divide-border divide-y",
|
|
215
|
+
children: [queries.map((query) => /* @__PURE__ */ jsxs("tr", {
|
|
216
|
+
className: "hover:bg-muted/50",
|
|
217
|
+
children: [
|
|
218
|
+
/* @__PURE__ */ jsxs("td", {
|
|
219
|
+
className: "px-4 py-3",
|
|
220
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
221
|
+
className: "font-medium",
|
|
222
|
+
children: query.name
|
|
223
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
224
|
+
className: "text-muted-foreground text-sm",
|
|
225
|
+
children: query.description
|
|
226
|
+
})]
|
|
227
|
+
}),
|
|
228
|
+
/* @__PURE__ */ jsx("td", {
|
|
229
|
+
className: "px-4 py-3",
|
|
230
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
231
|
+
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${QUERY_TYPE_COLORS[query.type] ?? ""}`,
|
|
232
|
+
children: query.type
|
|
233
|
+
})
|
|
234
|
+
}),
|
|
235
|
+
/* @__PURE__ */ jsxs("td", {
|
|
236
|
+
className: "text-muted-foreground px-4 py-3 text-sm",
|
|
237
|
+
children: [query.cacheTtlSeconds, "s"]
|
|
238
|
+
}),
|
|
239
|
+
/* @__PURE__ */ jsx("td", {
|
|
240
|
+
className: "px-4 py-3",
|
|
241
|
+
children: query.isShared ? /* @__PURE__ */ jsx("span", {
|
|
242
|
+
className: "text-green-600 dark:text-green-400",
|
|
243
|
+
children: "✓"
|
|
244
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
245
|
+
className: "text-muted-foreground",
|
|
246
|
+
children: "—"
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
]
|
|
250
|
+
}, query.id)), queries.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
|
|
251
|
+
colSpan: 4,
|
|
252
|
+
className: "text-muted-foreground px-4 py-8 text-center",
|
|
253
|
+
children: "No queries saved"
|
|
254
|
+
}) })]
|
|
255
|
+
})]
|
|
256
|
+
})
|
|
257
|
+
})]
|
|
258
|
+
})
|
|
259
|
+
]
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
//#endregion
|
|
264
|
+
export { AnalyticsDashboard };
|
|
265
|
+
//# sourceMappingURL=AnalyticsDashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyticsDashboard.js","names":[],"sources":["../../src/ui/AnalyticsDashboard.tsx"],"sourcesContent":["'use client';\n\n/**\n * Analytics Dashboard\n *\n * Interactive dashboard for the analytics-dashboard template.\n * Displays dashboards, widgets, and queries.\n */\nimport { useState } from 'react';\nimport {\n Button,\n ErrorState,\n LoaderBlock,\n StatCard,\n StatCardGroup,\n} from '@contractspec/lib.design-system';\nimport { useAnalyticsData } from './hooks/useAnalyticsData';\n\ntype Tab = 'dashboards' | 'queries';\n\nconst STATUS_COLORS: Record<string, string> = {\n PUBLISHED:\n 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400',\n DRAFT: 'bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400',\n ARCHIVED:\n 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400',\n};\n\nconst WIDGET_ICONS: Record<string, string> = {\n LINE_CHART: '📈',\n BAR_CHART: '📊',\n PIE_CHART: '🥧',\n AREA_CHART: '📉',\n SCATTER_PLOT: '⚬',\n METRIC: '🔢',\n TABLE: '📋',\n HEATMAP: '🗺️',\n FUNNEL: '⏬',\n MAP: '🌍',\n TEXT: '📝',\n EMBED: '🔗',\n};\n\nconst QUERY_TYPE_COLORS: Record<string, string> = {\n SQL: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',\n METRIC:\n 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400',\n AGGREGATION:\n 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-400',\n CUSTOM: 'bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400',\n};\n\nexport function AnalyticsDashboard() {\n const [activeTab, setActiveTab] = useState<Tab>('dashboards');\n const {\n dashboards,\n queries,\n selectedDashboard,\n widgets,\n loading,\n error,\n stats,\n refetch,\n selectDashboard,\n } = useAnalyticsData();\n\n const tabs: { id: Tab; label: string; icon: string }[] = [\n { id: 'dashboards', label: 'Dashboards', icon: '📊' },\n { id: 'queries', label: 'Queries', icon: '🔍' },\n ];\n\n if (loading) {\n return <LoaderBlock label=\"Loading Analytics...\" />;\n }\n\n if (error) {\n return (\n <ErrorState\n title=\"Failed to load Analytics\"\n description={error.message}\n onRetry={refetch}\n retryLabel=\"Retry\"\n />\n );\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-2xl font-bold\">Analytics Dashboard</h2>\n <Button onClick={() => alert('Create dashboard modal')}>\n <span className=\"mr-2\">+</span> New Dashboard\n </Button>\n </div>\n\n {/* Stats Row */}\n <StatCardGroup>\n <StatCard\n label=\"Dashboards\"\n value={stats.totalDashboards}\n hint={`${stats.publishedDashboards} published`}\n />\n <StatCard\n label=\"Queries\"\n value={stats.totalQueries}\n hint={`${stats.sharedQueries} shared`}\n />\n <StatCard\n label=\"Widgets\"\n value={widgets.length}\n hint=\"on current dashboard\"\n />\n </StatCardGroup>\n\n {/* Navigation Tabs */}\n <nav className=\"bg-muted flex gap-1 rounded-lg p-1\" role=\"tablist\">\n {tabs.map((tab) => (\n <Button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === tab.id}\n onClick={() => setActiveTab(tab.id)}\n className={`flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === tab.id\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n <span>{tab.icon}</span>\n {tab.label}\n </Button>\n ))}\n </nav>\n\n {/* Tab Content */}\n <div className=\"min-h-[400px]\" role=\"tabpanel\">\n {activeTab === 'dashboards' && (\n <div className=\"space-y-6\">\n {/* Dashboard List */}\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {dashboards.map((dashboard) => (\n <div\n key={dashboard.id}\n onClick={() => selectDashboard(dashboard)}\n className={`border-border bg-card cursor-pointer rounded-lg border p-4 transition-all ${\n selectedDashboard?.id === dashboard.id\n ? 'ring-primary ring-2'\n : 'hover:bg-muted/50'\n }`}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ')\n selectDashboard(dashboard);\n }}\n >\n <div className=\"mb-2 flex items-center justify-between\">\n <h3 className=\"font-medium\">{dashboard.name}</h3>\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[dashboard.status] ?? ''}`}\n >\n {dashboard.status}\n </span>\n </div>\n <p className=\"text-muted-foreground mb-3 text-sm\">\n {dashboard.description}\n </p>\n <div className=\"text-muted-foreground flex items-center justify-between text-xs\">\n <span>/{dashboard.slug}</span>\n {dashboard.isPublic && (\n <span className=\"text-green-600 dark:text-green-400\">\n 🌐 Public\n </span>\n )}\n </div>\n </div>\n ))}\n {dashboards.length === 0 && (\n <div className=\"text-muted-foreground col-span-full flex h-64 items-center justify-center\">\n No dashboards created yet\n </div>\n )}\n </div>\n\n {/* Widget Grid for Selected Dashboard */}\n {selectedDashboard && widgets.length > 0 && (\n <div>\n <h3 className=\"mb-4 text-lg font-semibold\">\n Widgets in \"{selectedDashboard.name}\"\n </h3>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {widgets.map((widget) => (\n <div\n key={widget.id}\n className=\"border-border bg-card rounded-lg border p-4\"\n >\n <div className=\"mb-2 flex items-center gap-2\">\n <span className=\"text-xl\">\n {WIDGET_ICONS[widget.type] ?? '📊'}\n </span>\n <span className=\"font-medium\">{widget.name}</span>\n </div>\n <div className=\"text-muted-foreground text-sm\">\n {widget.type.replace(/_/g, ' ')}\n </div>\n <div className=\"text-muted-foreground mt-2 text-xs\">\n Position: ({widget.gridX}, {widget.gridY}) •{' '}\n {widget.gridWidth}x{widget.gridHeight}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n\n {activeTab === 'queries' && (\n <div className=\"border-border rounded-lg border\">\n <table className=\"w-full\">\n <thead className=\"border-border bg-muted/30 border-b\">\n <tr>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Query\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Type\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Cache TTL\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Shared\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-border divide-y\">\n {queries.map((query) => (\n <tr key={query.id} className=\"hover:bg-muted/50\">\n <td className=\"px-4 py-3\">\n <div className=\"font-medium\">{query.name}</div>\n <div className=\"text-muted-foreground text-sm\">\n {query.description}\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${QUERY_TYPE_COLORS[query.type] ?? ''}`}\n >\n {query.type}\n </span>\n </td>\n <td className=\"text-muted-foreground px-4 py-3 text-sm\">\n {query.cacheTtlSeconds}s\n </td>\n <td className=\"px-4 py-3\">\n {query.isShared ? (\n <span className=\"text-green-600 dark:text-green-400\">\n ✓\n </span>\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n )}\n </td>\n </tr>\n ))}\n {queries.length === 0 && (\n <tr>\n <td\n colSpan={4}\n className=\"text-muted-foreground px-4 py-8 text-center\"\n >\n No queries saved\n </td>\n </tr>\n )}\n </tbody>\n </table>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Dashboard, Query, Widget } from "../../handlers/analytics.handlers.js";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/hooks/useAnalyticsData.d.ts
|
|
4
|
+
interface AnalyticsStats {
|
|
5
|
+
totalDashboards: number;
|
|
6
|
+
publishedDashboards: number;
|
|
7
|
+
totalQueries: number;
|
|
8
|
+
sharedQueries: number;
|
|
9
|
+
}
|
|
10
|
+
declare function useAnalyticsData(projectId?: string): {
|
|
11
|
+
dashboards: Dashboard[];
|
|
12
|
+
queries: Query[];
|
|
13
|
+
selectedDashboard: Dashboard | null;
|
|
14
|
+
widgets: Widget[];
|
|
15
|
+
loading: boolean;
|
|
16
|
+
error: Error | null;
|
|
17
|
+
stats: AnalyticsStats;
|
|
18
|
+
refetch: () => Promise<void>;
|
|
19
|
+
selectDashboard: (dashboard: Dashboard) => Promise<void>;
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { AnalyticsStats, useAnalyticsData };
|
|
23
|
+
//# sourceMappingURL=useAnalyticsData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAnalyticsData.d.ts","names":[],"sources":["../../../src/ui/hooks/useAnalyticsData.ts"],"sourcesContent":[],"mappings":";;;UAWiB,cAAA;;EAAA,mBAAc,EAAA,MAAA;EAOf,YAAA,EAAA,MAAgB;;;iBAAhB,gBAAA;;;;;EAgDM,OAAA,EAAA,OAAA;EAAS,KAAA,OAAA,GAAA,IAAA;EAAA,KAAA,gBAAA;;+BAAT,cAAS"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
|
+
import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
|
|
5
|
+
|
|
6
|
+
//#region src/ui/hooks/useAnalyticsData.ts
|
|
7
|
+
function useAnalyticsData(projectId = "local-project") {
|
|
8
|
+
const { handlers } = useTemplateRuntime();
|
|
9
|
+
const analytics = handlers.analytics;
|
|
10
|
+
const [dashboards, setDashboards] = useState([]);
|
|
11
|
+
const [queries, setQueries] = useState([]);
|
|
12
|
+
const [selectedDashboard, setSelectedDashboard] = useState(null);
|
|
13
|
+
const [widgets, setWidgets] = useState([]);
|
|
14
|
+
const [loading, setLoading] = useState(true);
|
|
15
|
+
const [error, setError] = useState(null);
|
|
16
|
+
const fetchData = useCallback(async () => {
|
|
17
|
+
try {
|
|
18
|
+
setLoading(true);
|
|
19
|
+
setError(null);
|
|
20
|
+
const [dashResult, queryResult] = await Promise.all([analytics.listDashboards({
|
|
21
|
+
projectId,
|
|
22
|
+
limit: 100
|
|
23
|
+
}), analytics.listQueries({
|
|
24
|
+
projectId,
|
|
25
|
+
limit: 100
|
|
26
|
+
})]);
|
|
27
|
+
setDashboards(dashResult.dashboards);
|
|
28
|
+
setQueries(queryResult.queries);
|
|
29
|
+
if (dashResult.dashboards.length > 0 && !selectedDashboard) {
|
|
30
|
+
const first = dashResult.dashboards[0];
|
|
31
|
+
if (first) {
|
|
32
|
+
setSelectedDashboard(first);
|
|
33
|
+
setWidgets(await analytics.getWidgets(first.id));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
} catch (err) {
|
|
37
|
+
setError(err instanceof Error ? err : /* @__PURE__ */ new Error("Failed to load analytics"));
|
|
38
|
+
} finally {
|
|
39
|
+
setLoading(false);
|
|
40
|
+
}
|
|
41
|
+
}, [
|
|
42
|
+
analytics,
|
|
43
|
+
projectId,
|
|
44
|
+
selectedDashboard
|
|
45
|
+
]);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
fetchData();
|
|
48
|
+
}, [fetchData]);
|
|
49
|
+
const selectDashboard = useCallback(async (dashboard) => {
|
|
50
|
+
setSelectedDashboard(dashboard);
|
|
51
|
+
setWidgets(await analytics.getWidgets(dashboard.id));
|
|
52
|
+
}, [analytics]);
|
|
53
|
+
return {
|
|
54
|
+
dashboards,
|
|
55
|
+
queries,
|
|
56
|
+
selectedDashboard,
|
|
57
|
+
widgets,
|
|
58
|
+
loading,
|
|
59
|
+
error,
|
|
60
|
+
stats: {
|
|
61
|
+
totalDashboards: dashboards.length,
|
|
62
|
+
publishedDashboards: dashboards.filter((d) => d.status === "PUBLISHED").length,
|
|
63
|
+
totalQueries: queries.length,
|
|
64
|
+
sharedQueries: queries.filter((q) => q.isShared).length
|
|
65
|
+
},
|
|
66
|
+
refetch: fetchData,
|
|
67
|
+
selectDashboard
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { useAnalyticsData };
|
|
73
|
+
//# sourceMappingURL=useAnalyticsData.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAnalyticsData.js","names":[],"sources":["../../../src/ui/hooks/useAnalyticsData.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport type {\n AnalyticsHandlers,\n Dashboard,\n Query,\n Widget,\n} from '../../handlers/analytics.handlers';\nimport { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';\n\nexport interface AnalyticsStats {\n totalDashboards: number;\n publishedDashboards: number;\n totalQueries: number;\n sharedQueries: number;\n}\n\nexport function useAnalyticsData(projectId = 'local-project') {\n const { handlers } = useTemplateRuntime<{ analytics: AnalyticsHandlers }>();\n const analytics = handlers.analytics;\n const [dashboards, setDashboards] = useState<Dashboard[]>([]);\n const [queries, setQueries] = useState<Query[]>([]);\n const [selectedDashboard, setSelectedDashboard] = useState<Dashboard | null>(\n null\n );\n const [widgets, setWidgets] = useState<Widget[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchData = useCallback(async () => {\n try {\n setLoading(true);\n setError(null);\n\n const [dashResult, queryResult] = await Promise.all([\n analytics.listDashboards({ projectId, limit: 100 }),\n analytics.listQueries({ projectId, limit: 100 }),\n ]);\n\n setDashboards(dashResult.dashboards);\n setQueries(queryResult.queries);\n\n // Select first dashboard if available\n if (dashResult.dashboards.length > 0 && !selectedDashboard) {\n const first = dashResult.dashboards[0];\n if (first) {\n setSelectedDashboard(first);\n const dashboardWidgets = await analytics.getWidgets(first.id);\n setWidgets(dashboardWidgets);\n }\n }\n } catch (err) {\n setError(\n err instanceof Error ? err : new Error('Failed to load analytics')\n );\n } finally {\n setLoading(false);\n }\n }, [analytics, projectId, selectedDashboard]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n const selectDashboard = useCallback(\n async (dashboard: Dashboard) => {\n setSelectedDashboard(dashboard);\n const dashboardWidgets = await analytics.getWidgets(dashboard.id);\n setWidgets(dashboardWidgets);\n },\n [analytics]\n );\n\n const stats: AnalyticsStats = {\n totalDashboards: dashboards.length,\n publishedDashboards: dashboards.filter((d) => d.status === 'PUBLISHED')\n .length,\n totalQueries: queries.length,\n sharedQueries: queries.filter((q) => q.isShared).length,\n };\n\n return {\n dashboards,\n queries,\n selectedDashboard,\n widgets,\n loading,\n error,\n stats,\n refetch: fetchData,\n selectDashboard,\n };\n}\n"],"mappings":";;;;;;AAkBA,SAAgB,iBAAiB,YAAY,iBAAiB;CAC5D,MAAM,EAAE,aAAa,oBAAsD;CAC3E,MAAM,YAAY,SAAS;CAC3B,MAAM,CAAC,YAAY,iBAAiB,SAAsB,EAAE,CAAC;CAC7D,MAAM,CAAC,SAAS,cAAc,SAAkB,EAAE,CAAC;CACnD,MAAM,CAAC,mBAAmB,wBAAwB,SAChD,KACD;CACD,MAAM,CAAC,SAAS,cAAc,SAAmB,EAAE,CAAC;CACpD,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CAEtD,MAAM,YAAY,YAAY,YAAY;AACxC,MAAI;AACF,cAAW,KAAK;AAChB,YAAS,KAAK;GAEd,MAAM,CAAC,YAAY,eAAe,MAAM,QAAQ,IAAI,CAClD,UAAU,eAAe;IAAE;IAAW,OAAO;IAAK,CAAC,EACnD,UAAU,YAAY;IAAE;IAAW,OAAO;IAAK,CAAC,CACjD,CAAC;AAEF,iBAAc,WAAW,WAAW;AACpC,cAAW,YAAY,QAAQ;AAG/B,OAAI,WAAW,WAAW,SAAS,KAAK,CAAC,mBAAmB;IAC1D,MAAM,QAAQ,WAAW,WAAW;AACpC,QAAI,OAAO;AACT,0BAAqB,MAAM;AAE3B,gBADyB,MAAM,UAAU,WAAW,MAAM,GAAG,CACjC;;;WAGzB,KAAK;AACZ,YACE,eAAe,QAAQ,sBAAM,IAAI,MAAM,2BAA2B,CACnE;YACO;AACR,cAAW,MAAM;;IAElB;EAAC;EAAW;EAAW;EAAkB,CAAC;AAE7C,iBAAgB;AACd,aAAW;IACV,CAAC,UAAU,CAAC;CAEf,MAAM,kBAAkB,YACtB,OAAO,cAAyB;AAC9B,uBAAqB,UAAU;AAE/B,aADyB,MAAM,UAAU,WAAW,UAAU,GAAG,CACrC;IAE9B,CAAC,UAAU,CACZ;AAUD,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA,OAf4B;GAC5B,iBAAiB,WAAW;GAC5B,qBAAqB,WAAW,QAAQ,MAAM,EAAE,WAAW,YAAY,CACpE;GACH,cAAc,QAAQ;GACtB,eAAe,QAAQ,QAAQ,MAAM,EAAE,SAAS,CAAC;GAClD;EAUC,SAAS;EACT;EACD"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { analyticsDashboardMarkdownRenderer, dashboardListMarkdownRenderer, queryBuilderMarkdownRenderer } from "./renderers/analytics.markdown.js";
|
|
2
|
+
import "./renderers/index.js";
|
|
3
|
+
import { AnalyticsDashboard } from "./AnalyticsDashboard.js";
|
|
4
|
+
import { AnalyticsStats, useAnalyticsData } from "./hooks/useAnalyticsData.js";
|
|
5
|
+
import "./hooks/index.js";
|
|
6
|
+
export { AnalyticsDashboard, AnalyticsStats, analyticsDashboardMarkdownRenderer, dashboardListMarkdownRenderer, queryBuilderMarkdownRenderer, useAnalyticsData };
|
package/dist/ui/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { analyticsDashboardMarkdownRenderer, dashboardListMarkdownRenderer, queryBuilderMarkdownRenderer } from "./renderers/analytics.markdown.js";
|
|
2
|
+
import { useAnalyticsData } from "./hooks/useAnalyticsData.js";
|
|
3
|
+
import { AnalyticsDashboard } from "./AnalyticsDashboard.js";
|
|
4
|
+
import "./hooks/index.js";
|
|
5
|
+
|
|
6
|
+
export { AnalyticsDashboard, analyticsDashboardMarkdownRenderer, dashboardListMarkdownRenderer, queryBuilderMarkdownRenderer, useAnalyticsData };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PresentationRenderer } from "@contractspec/lib.contracts";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/renderers/analytics.markdown.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Markdown renderer for Analytics Dashboard Overview
|
|
7
|
+
*/
|
|
8
|
+
declare const analyticsDashboardMarkdownRenderer: PresentationRenderer<{
|
|
9
|
+
mimeType: string;
|
|
10
|
+
body: string;
|
|
11
|
+
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Markdown renderer for Dashboard List
|
|
14
|
+
*/
|
|
15
|
+
declare const dashboardListMarkdownRenderer: PresentationRenderer<{
|
|
16
|
+
mimeType: string;
|
|
17
|
+
body: string;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Markdown renderer for Query Builder
|
|
21
|
+
*/
|
|
22
|
+
declare const queryBuilderMarkdownRenderer: PresentationRenderer<{
|
|
23
|
+
mimeType: string;
|
|
24
|
+
body: string;
|
|
25
|
+
}>;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { analyticsDashboardMarkdownRenderer, dashboardListMarkdownRenderer, queryBuilderMarkdownRenderer };
|
|
28
|
+
//# sourceMappingURL=analytics.markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.markdown.d.ts","names":[],"sources":["../../../src/ui/renderers/analytics.markdown.ts"],"sourcesContent":[],"mappings":";;;;AAuOA;AAmDA;;cA3Ia,oCAAoC;;;;;;;cAwFpC,+BAA+B;;;;;;;cAmD/B,8BAA8B"}
|