Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6d4605f
feat(analytics): metric view source — Phase 1 walking skeleton
atilafassina Apr 29, 2026
3de86dc
feat(appkit): metric view source — Phase 2 dimensions and time grain
atilafassina Apr 29, 2026
2178476
feat(appkit): metric view source — Phase 3 structured filter spec
atilafassina Apr 29, 2026
600f6b2
feat(appkit): metric view source — Phase 4 OBO lane + cache key compo…
atilafassina Apr 29, 2026
3f0c536
feat(appkit-ui): metric view source — Phase 5 metadata + format utili…
atilafassina Apr 29, 2026
2d12c51
feat(shared): metric view source — Phase 6 CLI metric sync
atilafassina Apr 29, 2026
79eeebf
feat(playground): metric view source — Phase 7 docs + dev-playground …
atilafassina Apr 29, 2026
f269757
fix(appkit-ui): surface server error message in useMetricView dev mode
atilafassina Apr 30, 2026
7bfc8e4
fix(playground): standardize on metric.d.ts (singular) as the type-ge…
atilafassina Apr 30, 2026
7b6cecf
fix(appkit): alias MEASURE() in metric SQL so result rows use plain keys
atilafassina Apr 30, 2026
fca252d
fix(appkit): classify aborted operations as STREAM_ABORTED, not UPSTR…
atilafassina Apr 30, 2026
84534a7
fix(appkit): infer time-grain set from SQL type, not from a non-exist…
atilafassina Apr 30, 2026
eefeadc
fix(appkit): wire metrics.metadata.json into the server-side metric r…
atilafassina Apr 30, 2026
5ed56da
fix(playground): defensive optional-chaining on metadata.<col>.format…
atilafassina Apr 30, 2026
13203ff
feat(appkit): translate UC structured format objects into printf strings
atilafassina Apr 30, 2026
cbadec7
feat(playground): theme-aware Plotly layout in /metrics route
atilafassina Apr 30, 2026
7fb9198
fix(appkit-ui): harden useMetricView and trim client metric metadata
atilafassina May 4, 2026
dca98c4
fix(appkit): server-side hardening for metric views (security + corre…
atilafassina May 4, 2026
ed61b33
fix(playground): regenerate client lockfile against the public registry
atilafassina May 4, 2026
234c251
fix(playground): use waitForRequest instead of page.on for metric ass…
atilafassina May 4, 2026
38bf39a
fix(appkit): server-side scrub of metric route errors
atilafassina May 4, 2026
f91e910
fix(appkit, appkit-ui): cap unbounded inputs and memoize hot-path all…
atilafassina May 4, 2026
32fcd0d
fix(appkit): tighten metric route error scrubbing and 404 disclosure
atilafassina May 4, 2026
1120377
fix(appkit): pre-parse filter depth cap to prevent stack-overflow DoS
atilafassina May 4, 2026
9524ae9
perf(appkit-ui, appkit): drop Blob allocation; memoize collectAllowed…
atilafassina May 4, 2026
66735b3
fix(appkit): close filter pre-check bypass and add per-group breadth cap
atilafassina May 4, 2026
4b6d07f
fix(appkit, appkit-ui): widen fail-closed gate; correct TextEncoder r…
atilafassina May 4, 2026
66a48cb
fix(appkit): support measure-only metric views, tighten dim/filter fa…
atilafassina May 4, 2026
614c212
fix(appkit): close timeGrain cache-bypass, AbortError mismatch, OBO k…
atilafassina May 4, 2026
7d297d9
fix(appkit): close signal.aborted race window; classify cancellations…
atilafassina May 4, 2026
34dc0c5
fix(appkit): trim x-forwarded-user; surface metric.json load failures…
atilafassina May 4, 2026
cc5639a
fix(appkit): wait for DESCRIBE statement completion in metric-registr…
atilafassina May 4, 2026
d8a3bc3
fix(appkit-ui): ignore late SSE events for an already-aborted controller
atilafassina May 4, 2026
a7bd698
chore(playground): refresh metric.d.ts + metrics.metadata.json from l…
atilafassina May 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,970 changes: 2,070 additions & 900 deletions apps/dev-playground/client/package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion apps/dev-playground/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,23 @@
"class-variance-authority": "0.7.1",
"clsx": "2.1.1",
"lucide-react": "0.546.0",
"plotly.js": "^3.5.0",
"react": "19.2.0",
"react-dom": "19.2.0",
"react-plotly.js": "^2.6.0",
"recharts": "3.4.1",
"tailwind-merge": "3.3.1",
"tailwindcss-animate": "1.0.7",
"tw-animate-css": "1.4.0"
},
"devDependencies": {
"@eslint/js": "9.36.0",
"@tailwindcss/postcss": "4.1.17",
"@tanstack/router-cli": "1.133.20",
"@types/node": "24.6.0",
"@types/react": "19.2.2",
"@types/react-dom": "19.2.2",
"@types/react-plotly.js": "^2.6.4",
"@vitejs/plugin-react": "5.0.4",
"autoprefixer": "10.4.21",
"eslint": "9.36.0",
Expand All @@ -43,7 +47,6 @@
"postcss": "8.5.6",
"shiki": "3.15.0",
"tailwindcss": "4.1.17",
"@tailwindcss/postcss": "4.1.17",
"typescript": "5.9.3",
"typescript-eslint": "8.45.0",
"vite": "npm:rolldown-vite@7.1.14"
Expand Down
17 changes: 17 additions & 0 deletions apps/dev-playground/client/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
import {
type MetricsMetadataBundle,
registerMetricsMetadata,
} from "@databricks/appkit-ui/format";
import { createRouter, RouterProvider } from "@tanstack/react-router";
import React from "react";
import ReactDOM from "react-dom/client";
// Build-time-emitted metadata bundle. In a production app this file is
// regenerated by `npx @databricks/appkit metric sync` (or the Vite plugin)
// from `config/queries/metric.json`. Phase 7 ships a hand-authored copy so
// the demo route at `/metrics` can wire format specs into Plotly even when
// the dev workspace does not host the underlying UC metric views.
import metricsMetadata from "../../shared/appkit-types/metrics.metadata.json";
import { routeTree } from "./routeTree.gen";
import "./index.css";

// Register the metric metadata bundle once at startup so `useMetricView()`'s
// `metadata` field is populated for every consumer in the app. The cast is
// load-bearing: TypeScript widens JSON-imported string literals (`"sp"`) to
// `string`, which the bundle's `lane: "sp" | "obo"` discriminant rejects.
// The actual JSON values are hand-checked against the schema.
registerMetricsMetadata(metricsMetadata as unknown as MetricsMetadataBundle);

const router = createRouter({
routeTree,
defaultPreload: "intent",
Expand Down
21 changes: 21 additions & 0 deletions apps/dev-playground/client/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Route as SqlHelpersRouteRouteImport } from './routes/sql-helpers.route'
import { Route as ServingRouteRouteImport } from './routes/serving.route'
import { Route as ReconnectRouteRouteImport } from './routes/reconnect.route'
import { Route as PolicyMatrixRouteRouteImport } from './routes/policy-matrix.route'
import { Route as MetricsRouteRouteImport } from './routes/metrics.route'
import { Route as LakebaseRouteRouteImport } from './routes/lakebase.route'
import { Route as JobsRouteRouteImport } from './routes/jobs.route'
import { Route as GenieRouteRouteImport } from './routes/genie.route'
Expand Down Expand Up @@ -61,6 +62,11 @@ const PolicyMatrixRouteRoute = PolicyMatrixRouteRouteImport.update({
path: '/policy-matrix',
getParentRoute: () => rootRouteImport,
} as any)
const MetricsRouteRoute = MetricsRouteRouteImport.update({
id: '/metrics',
path: '/metrics',
getParentRoute: () => rootRouteImport,
} as any)
const LakebaseRouteRoute = LakebaseRouteRouteImport.update({
id: '/lakebase',
path: '/lakebase',
Expand Down Expand Up @@ -117,6 +123,7 @@ export interface FileRoutesByFullPath {
'/genie': typeof GenieRouteRoute
'/jobs': typeof JobsRouteRoute
'/lakebase': typeof LakebaseRouteRoute
'/metrics': typeof MetricsRouteRoute
'/policy-matrix': typeof PolicyMatrixRouteRoute
'/reconnect': typeof ReconnectRouteRoute
'/serving': typeof ServingRouteRoute
Expand All @@ -135,6 +142,7 @@ export interface FileRoutesByTo {
'/genie': typeof GenieRouteRoute
'/jobs': typeof JobsRouteRoute
'/lakebase': typeof LakebaseRouteRoute
'/metrics': typeof MetricsRouteRoute
'/policy-matrix': typeof PolicyMatrixRouteRoute
'/reconnect': typeof ReconnectRouteRoute
'/serving': typeof ServingRouteRoute
Expand All @@ -154,6 +162,7 @@ export interface FileRoutesById {
'/genie': typeof GenieRouteRoute
'/jobs': typeof JobsRouteRoute
'/lakebase': typeof LakebaseRouteRoute
'/metrics': typeof MetricsRouteRoute
'/policy-matrix': typeof PolicyMatrixRouteRoute
'/reconnect': typeof ReconnectRouteRoute
'/serving': typeof ServingRouteRoute
Expand All @@ -174,6 +183,7 @@ export interface FileRouteTypes {
| '/genie'
| '/jobs'
| '/lakebase'
| '/metrics'
| '/policy-matrix'
| '/reconnect'
| '/serving'
Expand All @@ -192,6 +202,7 @@ export interface FileRouteTypes {
| '/genie'
| '/jobs'
| '/lakebase'
| '/metrics'
| '/policy-matrix'
| '/reconnect'
| '/serving'
Expand All @@ -210,6 +221,7 @@ export interface FileRouteTypes {
| '/genie'
| '/jobs'
| '/lakebase'
| '/metrics'
| '/policy-matrix'
| '/reconnect'
| '/serving'
Expand All @@ -229,6 +241,7 @@ export interface RootRouteChildren {
GenieRouteRoute: typeof GenieRouteRoute
JobsRouteRoute: typeof JobsRouteRoute
LakebaseRouteRoute: typeof LakebaseRouteRoute
MetricsRouteRoute: typeof MetricsRouteRoute
PolicyMatrixRouteRoute: typeof PolicyMatrixRouteRoute
ReconnectRouteRoute: typeof ReconnectRouteRoute
ServingRouteRoute: typeof ServingRouteRoute
Expand Down Expand Up @@ -289,6 +302,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof PolicyMatrixRouteRouteImport
parentRoute: typeof rootRouteImport
}
'/metrics': {
id: '/metrics'
path: '/metrics'
fullPath: '/metrics'
preLoaderRoute: typeof MetricsRouteRouteImport
parentRoute: typeof rootRouteImport
}
'/lakebase': {
id: '/lakebase'
path: '/lakebase'
Expand Down Expand Up @@ -365,6 +385,7 @@ const rootRouteChildren: RootRouteChildren = {
GenieRouteRoute: GenieRouteRoute,
JobsRouteRoute: JobsRouteRoute,
LakebaseRouteRoute: LakebaseRouteRoute,
MetricsRouteRoute: MetricsRouteRoute,
PolicyMatrixRouteRoute: PolicyMatrixRouteRoute,
ReconnectRouteRoute: ReconnectRouteRoute,
ServingRouteRoute: ServingRouteRoute,
Expand Down
8 changes: 8 additions & 0 deletions apps/dev-playground/client/src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ function RootComponent() {
Analytics
</Button>
</Link>
<Link to="/metrics" className="no-underline">
<Button
variant="ghost"
className="text-foreground hover:text-secondary-foreground"
>
Metrics
</Button>
</Link>
<Link to="/arrow-analytics" className="no-underline">
<Button
variant="ghost"
Expand Down
18 changes: 18 additions & 0 deletions apps/dev-playground/client/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,24 @@ function IndexRoute() {
</div>
</Card>

<Card className="p-6 hover:shadow-lg transition-shadow cursor-pointer">
<div className="flex flex-col h-full">
<h3 className="text-2xl font-semibold text-foreground mb-3">
Metric Views
</h3>
<p className="text-muted-foreground mb-6 flex-grow">
Consume UC Metric Views with type-safe measures, dimensions,
filter spec, and metadata-driven Plotly formatting.
</p>
<Button
onClick={() => navigate({ to: "/metrics" })}
className="w-full"
>
Explore Metric Views
</Button>
</div>
</Card>

<Card className="p-6 hover:shadow-lg transition-shadow cursor-pointer">
<div className="flex flex-col h-full">
<h3 className="text-2xl font-semibold text-foreground mb-3">
Expand Down
Loading
Loading