Compare commits
3 commits
22f50d64f9
...
8927f2ab8a
| Author | SHA1 | Date | |
|---|---|---|---|
| 8927f2ab8a | |||
|
|
9311b81102 | ||
|
|
7a6ad8ab0e |
36 changed files with 197 additions and 57 deletions
|
|
@ -5,13 +5,16 @@ reusable React component library.
|
||||||
|
|
||||||
This project is not a Homepage customization and does not depend on Homepage
|
This project is not a Homepage customization and does not depend on Homepage
|
||||||
runtime, frontend code, or configuration. The dashboard will be model-driven:
|
runtime, frontend code, or configuration. The dashboard will be model-driven:
|
||||||
the reusable UI package stays content-free, while environment-specific data
|
the reusable UI package stays content-free, the reusable dashboard model
|
||||||
lives in validated dashboard model state inside the web app.
|
package owns schema and validation, and environment-specific data lives in
|
||||||
|
validated dashboard model state inside the web app.
|
||||||
|
|
||||||
## Workspace Layout
|
## Workspace Layout
|
||||||
|
|
||||||
- `apps/web`: Vite React website, Bun API server, model fixtures, Drizzle
|
- `apps/web`: Vite React website, Bun API server, model fixtures, Drizzle
|
||||||
persistence, Playwright e2e checks, and container build.
|
persistence, Playwright e2e checks, and container build.
|
||||||
|
- `packages/dashboard-model`: reusable dashboard schema, validation, and
|
||||||
|
generic model fixtures shared by apps and tooling.
|
||||||
- `packages/ui`: reusable dashboard React components, design tokens,
|
- `packages/ui`: reusable dashboard React components, design tokens,
|
||||||
shadcn/radix primitives, generic fixtures, and Storybook.
|
shadcn/radix primitives, generic fixtures, and Storybook.
|
||||||
- `docs/superpowers`: migration specs and execution plans used for this repo.
|
- `docs/superpowers`: migration specs and execution plans used for this repo.
|
||||||
|
|
@ -65,7 +68,7 @@ with an explicit migration error.
|
||||||
## Seed Data
|
## Seed Data
|
||||||
|
|
||||||
The initial Dimension Lab dashboard lives in
|
The initial Dimension Lab dashboard lives in
|
||||||
`apps/web/src/lib/model/fixtures/dimensionlab.ts` as validated model data. It
|
`apps/web/src/lib/dashboard-seed/dimensionlab.ts` as validated model data. It
|
||||||
includes the first-screen telemetry, service groups, status strip, weather
|
includes the first-screen telemetry, service groups, status strip, weather
|
||||||
module, Iconify icon identifiers, links, and datasource references. Values that
|
module, Iconify icon identifiers, links, and datasource references. Values that
|
||||||
are not live yet are labeled as fallback values in the data so later datasource
|
are not live yet are labeled as fallback values in the data so later datasource
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ WORKDIR /repo
|
||||||
ENV PATH=/repo/apps/web/node_modules/.bin:/repo/packages/ui/node_modules/.bin:/repo/node_modules/.bin:$PATH
|
ENV PATH=/repo/apps/web/node_modules/.bin:/repo/packages/ui/node_modules/.bin:/repo/node_modules/.bin:$PATH
|
||||||
COPY package.json bun.lock turbo.json tsconfig.base.json ./
|
COPY package.json bun.lock turbo.json tsconfig.base.json ./
|
||||||
COPY apps/web/package.json apps/web/package.json
|
COPY apps/web/package.json apps/web/package.json
|
||||||
|
COPY packages/dashboard-model/package.json packages/dashboard-model/package.json
|
||||||
COPY packages/ui/package.json packages/ui/package.json
|
COPY packages/ui/package.json packages/ui/package.json
|
||||||
RUN bun install --frozen-lockfile
|
RUN bun install --frozen-lockfile
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
"db:check": "drizzle-kit check"
|
"db:check": "drizzle-kit check"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@dimensionlab/dashboard-model": "workspace:*",
|
||||||
"@dimensionlab/ui": "workspace:*",
|
"@dimensionlab/ui": "workspace:*",
|
||||||
"@sinclair/typebox": "^0.34.49",
|
"@sinclair/typebox": "^0.34.49",
|
||||||
"ajv": "^8.20.0",
|
"ajv": "^8.20.0",
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import type {
|
||||||
DatasourceReference,
|
DatasourceReference,
|
||||||
ServiceEntry,
|
ServiceEntry,
|
||||||
TelemetryCard,
|
TelemetryCard,
|
||||||
} from "../schema";
|
} from "@dimensionlab/dashboard-model";
|
||||||
|
|
||||||
describe("Dimension Lab dashboard seed", () => {
|
describe("Dimension Lab dashboard seed", () => {
|
||||||
test("defines the primary first-screen sections as model data", () => {
|
test("defines the primary first-screen sections as model data", () => {
|
||||||
|
|
@ -7,7 +7,7 @@ import {
|
||||||
type ServiceGroup,
|
type ServiceGroup,
|
||||||
type Severity,
|
type Severity,
|
||||||
type TelemetryCard,
|
type TelemetryCard,
|
||||||
} from "../schema";
|
} from "@dimensionlab/dashboard-model";
|
||||||
|
|
||||||
type NumericValueKind = "percent" | "bytes" | "temperature" | "latency" | "number";
|
type NumericValueKind = "percent" | "bytes" | "temperature" | "latency" | "number";
|
||||||
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
export { dimensionLabDashboardFixture } from "./dimensionlab";
|
|
||||||
export { genericDashboardFixture } from "./generic";
|
|
||||||
|
|
@ -74,5 +74,7 @@ function findFiles(path: string, extension: string): string[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
function withoutInternalPackageScope(source: string): string {
|
function withoutInternalPackageScope(source: string): string {
|
||||||
return source.replaceAll("@dimensionlab/ui", "@internal/ui");
|
return source
|
||||||
|
.replaceAll("@dimensionlab/dashboard-model", "@internal/dashboard-model")
|
||||||
|
.replaceAll("@dimensionlab/ui", "@internal/ui");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ import { mkdtemp } from "node:fs/promises";
|
||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { afterEach, describe, expect, test } from "vitest";
|
import { afterEach, describe, expect, test } from "vitest";
|
||||||
import type { DashboardDocument } from "$lib/model";
|
import type { DashboardDocument } from "@dimensionlab/dashboard-model";
|
||||||
import { genericDashboardFixture } from "$lib/model/fixtures/generic";
|
import { genericDashboardFixture } from "@dimensionlab/dashboard-model/fixtures";
|
||||||
import { createDashboardStore, type DashboardStore } from "$lib/server/db/dashboard-store";
|
import { createDashboardStore, type DashboardStore } from "$lib/server/db/dashboard-store";
|
||||||
import {
|
import {
|
||||||
AgentConfigAuthorizationError,
|
AgentConfigAuthorizationError,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import {
|
||||||
type ServiceGroup,
|
type ServiceGroup,
|
||||||
type StatusItem,
|
type StatusItem,
|
||||||
type TelemetryCard,
|
type TelemetryCard,
|
||||||
} from "$lib/model";
|
} from "@dimensionlab/dashboard-model";
|
||||||
import {
|
import {
|
||||||
createDashboardStore,
|
createDashboardStore,
|
||||||
DashboardRevisionNotFoundError,
|
DashboardRevisionNotFoundError,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ import { mkdtemp } from "node:fs/promises";
|
||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { afterEach, describe, expect, test } from "vitest";
|
import { afterEach, describe, expect, test } from "vitest";
|
||||||
import { dimensionLabDashboardFixture } from "$lib/model/fixtures/dimensionlab";
|
import { dimensionLabDashboardFixture } from "$lib/dashboard-seed/dimensionlab";
|
||||||
import { genericDashboardFixture } from "$lib/model/fixtures/generic";
|
import { genericDashboardFixture } from "@dimensionlab/dashboard-model/fixtures";
|
||||||
import { createDashboardStore, type DashboardStore } from "./db/dashboard-store";
|
import { createDashboardStore, type DashboardStore } from "./db/dashboard-store";
|
||||||
import { loadDashboardRuntime } from "./dashboard";
|
import { loadDashboardRuntime } from "./dashboard";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { dimensionLabDashboardFixture } from "$lib/model/fixtures/dimensionlab";
|
import { dimensionLabDashboardFixture } from "$lib/dashboard-seed/dimensionlab";
|
||||||
import type { DashboardDocument } from "$lib/model";
|
import type { DashboardDocument } from "@dimensionlab/dashboard-model";
|
||||||
import {
|
import {
|
||||||
createDashboardStore,
|
createDashboardStore,
|
||||||
DashboardPersistenceValidationError,
|
DashboardPersistenceValidationError,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { describe, expect, test, vi } from "vitest";
|
||||||
import {
|
import {
|
||||||
DASHBOARD_SCHEMA_VERSION,
|
DASHBOARD_SCHEMA_VERSION,
|
||||||
type DashboardDocument,
|
type DashboardDocument,
|
||||||
} from "$lib/model";
|
} from "@dimensionlab/dashboard-model";
|
||||||
import { resolveDashboardDatasources } from ".";
|
import { resolveDashboardDatasources } from ".";
|
||||||
|
|
||||||
describe("dashboard datasource resolution", () => {
|
describe("dashboard datasource resolution", () => {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import type {
|
||||||
StatusItem,
|
StatusItem,
|
||||||
StatusStrip,
|
StatusStrip,
|
||||||
TelemetryCard,
|
TelemetryCard,
|
||||||
} from "$lib/model";
|
} from "@dimensionlab/dashboard-model";
|
||||||
|
|
||||||
export interface DatasourceResolutionOptions {
|
export interface DatasourceResolutionOptions {
|
||||||
fetch?: DatasourceFetch;
|
fetch?: DatasourceFetch;
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ import { mkdtemp } from "node:fs/promises";
|
||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { afterEach, describe, expect, test, vi } from "vitest";
|
import { afterEach, describe, expect, test, vi } from "vitest";
|
||||||
import { genericDashboardFixture } from "$lib/model/fixtures/generic";
|
import { genericDashboardFixture } from "@dimensionlab/dashboard-model/fixtures";
|
||||||
import type { DashboardDocument } from "$lib/model";
|
import type { DashboardDocument } from "@dimensionlab/dashboard-model";
|
||||||
import {
|
import {
|
||||||
DashboardPersistenceValidationError,
|
DashboardPersistenceValidationError,
|
||||||
createDashboardStore,
|
createDashboardStore,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { desc, eq } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
type DashboardDocument,
|
type DashboardDocument,
|
||||||
type DashboardValidationFailure,
|
type DashboardValidationFailure,
|
||||||
} from "$lib/model";
|
} from "@dimensionlab/dashboard-model";
|
||||||
import {
|
import {
|
||||||
type DashboardDatabaseConnection,
|
type DashboardDatabaseConnection,
|
||||||
openDashboardDatabase,
|
openDashboardDatabase,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, expect, test } from "vitest";
|
import { describe, expect, test } from "vitest";
|
||||||
import { DASHBOARD_SCHEMA_VERSION } from "$lib/model";
|
import { DASHBOARD_SCHEMA_VERSION } from "@dimensionlab/dashboard-model";
|
||||||
import { genericDashboardFixture } from "$lib/model/fixtures/generic";
|
import { genericDashboardFixture } from "@dimensionlab/dashboard-model/fixtures";
|
||||||
import {
|
import {
|
||||||
UnsupportedDashboardModelVersionError,
|
UnsupportedDashboardModelVersionError,
|
||||||
migrateDashboardDocumentForPersistence,
|
migrateDashboardDocumentForPersistence,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import {
|
||||||
validateDashboardDocument,
|
validateDashboardDocument,
|
||||||
type DashboardDocument,
|
type DashboardDocument,
|
||||||
type DashboardValidationFailure,
|
type DashboardValidationFailure,
|
||||||
} from "$lib/model";
|
} from "@dimensionlab/dashboard-model";
|
||||||
|
|
||||||
export interface DashboardModelMigrationSuccess {
|
export interface DashboardModelMigrationSuccess {
|
||||||
valid: true;
|
valid: true;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { DashboardDocument } from "$lib/model";
|
import type { DashboardDocument } from "@dimensionlab/dashboard-model";
|
||||||
import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||||
|
|
||||||
export const dashboardDocuments = sqliteTable("dashboard_documents", {
|
export const dashboardDocuments = sqliteTable("dashboard_documents", {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { readFileSync } from "node:fs";
|
import { readFileSync } from "node:fs";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { describe, expect, test } from "vitest";
|
import { describe, expect, test } from "vitest";
|
||||||
import { type DashboardDocument } from "$lib/model";
|
import { type DashboardDocument } from "@dimensionlab/dashboard-model";
|
||||||
import { dimensionLabDashboardFixture } from "$lib/model/fixtures/dimensionlab";
|
import { dimensionLabDashboardFixture } from "$lib/dashboard-seed/dimensionlab";
|
||||||
import { genericDashboardFixture } from "$lib/model/fixtures/generic";
|
import { genericDashboardFixture } from "@dimensionlab/dashboard-model/fixtures";
|
||||||
import { dashboardDocumentToUiDashboard } from "./model-renderer";
|
import { dashboardDocumentToUiDashboard } from "./model-renderer";
|
||||||
|
|
||||||
const appRoot = process.cwd().endsWith(`${join("apps", "web")}`)
|
const appRoot = process.cwd().endsWith(`${join("apps", "web")}`)
|
||||||
|
|
@ -93,6 +93,7 @@ describe("dashboard model renderer", () => {
|
||||||
"utf8",
|
"utf8",
|
||||||
)
|
)
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
|
.replaceAll("@dimensionlab/dashboard-model", "@internal/dashboard-model")
|
||||||
.replaceAll("@dimensionlab/ui", "@internal/ui");
|
.replaceAll("@dimensionlab/ui", "@internal/ui");
|
||||||
|
|
||||||
expect(source).not.toContain("dimension");
|
expect(source).not.toContain("dimension");
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import type {
|
||||||
StatusItem,
|
StatusItem,
|
||||||
StatusStrip,
|
StatusStrip,
|
||||||
TelemetryCard,
|
TelemetryCard,
|
||||||
} from "$lib/model";
|
} from "@dimensionlab/dashboard-model";
|
||||||
import type {
|
import type {
|
||||||
UiDashboardPreview,
|
UiDashboardPreview,
|
||||||
UiModuleBlock,
|
UiModuleBlock,
|
||||||
|
|
|
||||||
|
|
@ -88,4 +88,61 @@ describe("workspace boundaries", () => {
|
||||||
expect(uiPackage.exports).toHaveProperty(".");
|
expect(uiPackage.exports).toHaveProperty(".");
|
||||||
expect(uiPackage.exports).toHaveProperty("./styles.css");
|
expect(uiPackage.exports).toHaveProperty("./styles.css");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("keeps the dashboard model in a reusable internal package", () => {
|
||||||
|
const webPackage = JSON.parse(
|
||||||
|
readFileSync(join(root, "apps/web/package.json"), "utf8"),
|
||||||
|
) as { dependencies?: Record<string, string> };
|
||||||
|
const modelPackage = JSON.parse(
|
||||||
|
readFileSync(join(root, "packages/dashboard-model/package.json"), "utf8"),
|
||||||
|
) as { exports?: Record<string, unknown>; name?: string };
|
||||||
|
const tsconfig = JSON.parse(
|
||||||
|
readFileSync(join(root, "tsconfig.json"), "utf8"),
|
||||||
|
) as { references?: Array<{ path: string }> };
|
||||||
|
|
||||||
|
expect(webPackage.dependencies?.["@dimensionlab/dashboard-model"]).toBe(
|
||||||
|
"workspace:*",
|
||||||
|
);
|
||||||
|
expect(modelPackage.name).toBe("@dimensionlab/dashboard-model");
|
||||||
|
expect(modelPackage.exports).toHaveProperty(".");
|
||||||
|
expect(modelPackage.exports).toHaveProperty("./fixtures");
|
||||||
|
expect(tsconfig.references).toEqual(
|
||||||
|
expect.arrayContaining([{ path: "./packages/dashboard-model" }]),
|
||||||
|
);
|
||||||
|
expect(existsSync(join(root, "apps/web/src/lib/model/index.ts"))).toBe(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("stages web workspace dependency manifests before container install", () => {
|
||||||
|
const webPackage = JSON.parse(
|
||||||
|
readFileSync(join(root, "apps/web/package.json"), "utf8"),
|
||||||
|
) as { dependencies?: Record<string, string> };
|
||||||
|
const workspacePackages = [
|
||||||
|
"packages/ui/package.json",
|
||||||
|
"packages/dashboard-model/package.json",
|
||||||
|
].map((manifestPath) => {
|
||||||
|
const packageJson = JSON.parse(
|
||||||
|
readFileSync(join(root, manifestPath), "utf8"),
|
||||||
|
) as { name?: string };
|
||||||
|
|
||||||
|
return [packageJson.name, manifestPath] as const;
|
||||||
|
});
|
||||||
|
const manifestsByPackageName = new Map(workspacePackages);
|
||||||
|
const containerfile = readFileSync(
|
||||||
|
join(root, "apps/web/Containerfile"),
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
|
||||||
|
const workspaceDependencyManifests = Object.entries(
|
||||||
|
webPackage.dependencies ?? {},
|
||||||
|
)
|
||||||
|
.filter(([, version]) => version.startsWith("workspace:"))
|
||||||
|
.map(([packageName]) => manifestsByPackageName.get(packageName));
|
||||||
|
|
||||||
|
expect(workspaceDependencyManifests).not.toContain(undefined);
|
||||||
|
for (const manifestPath of workspaceDependencyManifests) {
|
||||||
|
expect(containerfile).toContain(`COPY ${manifestPath} ${manifestPath}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { renderToString } from "react-dom/server";
|
import { renderToString } from "react-dom/server";
|
||||||
import { describe, expect, test } from "vitest";
|
import { describe, expect, test } from "vitest";
|
||||||
import { genericDashboardFixture } from "$lib/model/fixtures/generic";
|
import { genericDashboardFixture } from "@dimensionlab/dashboard-model/fixtures";
|
||||||
import { AppStateView, resolveDocumentMetadata } from "./App";
|
import { AppStateView, resolveDocumentMetadata } from "./App";
|
||||||
|
|
||||||
describe("home page model renderer", () => {
|
describe("home page model renderer", () => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { describe, expect, test } from "vitest";
|
import { describe, expect, test } from "vitest";
|
||||||
import { dimensionLabDashboardFixture } from "$lib/model/fixtures/dimensionlab";
|
import { dimensionLabDashboardFixture } from "$lib/dashboard-seed/dimensionlab";
|
||||||
import { loadDashboardResponse } from "./dashboard";
|
import { loadDashboardResponse } from "./dashboard";
|
||||||
|
|
||||||
describe("dashboard API route", () => {
|
describe("dashboard API route", () => {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
|
"@dimensionlab/dashboard-model": ["../../packages/dashboard-model/src/index.ts"],
|
||||||
|
"@dimensionlab/dashboard-model/fixtures": [
|
||||||
|
"../../packages/dashboard-model/src/fixtures/index.ts"
|
||||||
|
],
|
||||||
"@dimensionlab/ui": ["../../packages/ui/src/index.ts"],
|
"@dimensionlab/ui": ["../../packages/ui/src/index.ts"],
|
||||||
"@dimensionlab/ui/styles.css": ["../../packages/ui/src/styles.css"],
|
"@dimensionlab/ui/styles.css": ["../../packages/ui/src/styles.css"],
|
||||||
"$lib/*": ["src/lib/*"]
|
"$lib/*": ["src/lib/*"]
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,12 @@ export default defineConfig({
|
||||||
"@dimensionlab/ui": fileURLToPath(
|
"@dimensionlab/ui": fileURLToPath(
|
||||||
new URL("../../packages/ui/src/index.ts", import.meta.url),
|
new URL("../../packages/ui/src/index.ts", import.meta.url),
|
||||||
),
|
),
|
||||||
|
"@dimensionlab/dashboard-model/fixtures": fileURLToPath(
|
||||||
|
new URL("../../packages/dashboard-model/src/fixtures/index.ts", import.meta.url),
|
||||||
|
),
|
||||||
|
"@dimensionlab/dashboard-model": fileURLToPath(
|
||||||
|
new URL("../../packages/dashboard-model/src/index.ts", import.meta.url),
|
||||||
|
),
|
||||||
$lib: fileURLToPath(new URL("./src/lib", import.meta.url)),
|
$lib: fileURLToPath(new URL("./src/lib", import.meta.url)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
57
bun.lock
57
bun.lock
|
|
@ -12,6 +12,7 @@
|
||||||
"name": "@dimensionlab/web",
|
"name": "@dimensionlab/web",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@dimensionlab/dashboard-model": "workspace:*",
|
||||||
"@dimensionlab/ui": "workspace:*",
|
"@dimensionlab/ui": "workspace:*",
|
||||||
"@sinclair/typebox": "^0.34.49",
|
"@sinclair/typebox": "^0.34.49",
|
||||||
"ajv": "^8.20.0",
|
"ajv": "^8.20.0",
|
||||||
|
|
@ -40,6 +41,22 @@
|
||||||
"vitest": "^4.1.9",
|
"vitest": "^4.1.9",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"packages/dashboard-model": {
|
||||||
|
"name": "@dimensionlab/dashboard-model",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"dependencies": {
|
||||||
|
"@sinclair/typebox": "^0.34.49",
|
||||||
|
"ajv": "^8.20.0",
|
||||||
|
"ajv-formats": "^3.0.1",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "^1.3.14",
|
||||||
|
"@types/node": "^25.9.3",
|
||||||
|
"bun-types": "^1.3.14",
|
||||||
|
"typescript": "^6.0.3",
|
||||||
|
"vitest": "^4.1.9",
|
||||||
|
},
|
||||||
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@dimensionlab/ui",
|
"name": "@dimensionlab/ui",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
|
|
@ -137,6 +154,8 @@
|
||||||
|
|
||||||
"@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="],
|
"@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="],
|
||||||
|
|
||||||
|
"@dimensionlab/dashboard-model": ["@dimensionlab/dashboard-model@workspace:packages/dashboard-model"],
|
||||||
|
|
||||||
"@dimensionlab/ui": ["@dimensionlab/ui@workspace:packages/ui"],
|
"@dimensionlab/ui": ["@dimensionlab/ui@workspace:packages/ui"],
|
||||||
|
|
||||||
"@dimensionlab/web": ["@dimensionlab/web@workspace:apps/web"],
|
"@dimensionlab/web": ["@dimensionlab/web@workspace:apps/web"],
|
||||||
|
|
@ -671,7 +690,7 @@
|
||||||
|
|
||||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.2", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.0" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg=="],
|
"@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.2", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.0" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg=="],
|
||||||
|
|
||||||
"@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="],
|
"@vitest/expect": ["@vitest/expect@4.1.9", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.9", "@vitest/utils": "4.1.9", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA=="],
|
||||||
|
|
||||||
"@vitest/mocker": ["@vitest/mocker@4.1.9", "", { "dependencies": { "@vitest/spy": "4.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw=="],
|
"@vitest/mocker": ["@vitest/mocker@4.1.9", "", { "dependencies": { "@vitest/spy": "4.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw=="],
|
||||||
|
|
||||||
|
|
@ -681,7 +700,7 @@
|
||||||
|
|
||||||
"@vitest/snapshot": ["@vitest/snapshot@4.1.9", "", { "dependencies": { "@vitest/pretty-format": "4.1.9", "@vitest/utils": "4.1.9", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA=="],
|
"@vitest/snapshot": ["@vitest/snapshot@4.1.9", "", { "dependencies": { "@vitest/pretty-format": "4.1.9", "@vitest/utils": "4.1.9", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA=="],
|
||||||
|
|
||||||
"@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="],
|
"@vitest/spy": ["@vitest/spy@4.1.9", "", {}, "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA=="],
|
||||||
|
|
||||||
"@vitest/utils": ["@vitest/utils@4.1.9", "", { "dependencies": { "@vitest/pretty-format": "4.1.9", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA=="],
|
"@vitest/utils": ["@vitest/utils@4.1.9", "", { "dependencies": { "@vitest/pretty-format": "4.1.9", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA=="],
|
||||||
|
|
||||||
|
|
@ -745,7 +764,7 @@
|
||||||
|
|
||||||
"caniuse-lite": ["caniuse-lite@1.0.30001799", "", {}, "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw=="],
|
"caniuse-lite": ["caniuse-lite@1.0.30001799", "", {}, "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw=="],
|
||||||
|
|
||||||
"chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="],
|
"chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="],
|
||||||
|
|
||||||
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||||
|
|
||||||
|
|
@ -873,7 +892,7 @@
|
||||||
|
|
||||||
"esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
|
"esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
|
||||||
|
|
||||||
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
|
||||||
|
|
||||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||||
|
|
||||||
|
|
@ -1479,6 +1498,8 @@
|
||||||
|
|
||||||
"@rolldown/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
"@rolldown/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
||||||
|
|
||||||
|
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg=="],
|
||||||
|
|
@ -1495,14 +1516,6 @@
|
||||||
|
|
||||||
"@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="],
|
"@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="],
|
||||||
|
|
||||||
"@vitest/expect/@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="],
|
|
||||||
|
|
||||||
"@vitest/expect/tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="],
|
|
||||||
|
|
||||||
"@vitest/mocker/@vitest/spy": ["@vitest/spy@4.1.9", "", {}, "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA=="],
|
|
||||||
|
|
||||||
"@vitest/mocker/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
|
|
||||||
|
|
||||||
"body-parser/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
|
"body-parser/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
|
||||||
|
|
||||||
"cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
"cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
@ -1549,14 +1562,14 @@
|
||||||
|
|
||||||
"shadcn/open": ["open@11.0.0", "", { "dependencies": { "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.1.0", "wsl-utils": "^0.3.0" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="],
|
"shadcn/open": ["open@11.0.0", "", { "dependencies": { "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.1.0", "wsl-utils": "^0.3.0" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="],
|
||||||
|
|
||||||
|
"storybook/@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="],
|
||||||
|
|
||||||
|
"storybook/@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="],
|
||||||
|
|
||||||
"string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
"string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
"type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
|
"type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
|
||||||
|
|
||||||
"vitest/@vitest/expect": ["@vitest/expect@4.1.9", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.9", "@vitest/utils": "4.1.9", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA=="],
|
|
||||||
|
|
||||||
"vitest/@vitest/spy": ["@vitest/spy@4.1.9", "", {}, "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA=="],
|
|
||||||
|
|
||||||
"wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
"wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||||
|
|
||||||
"wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
"wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
@ -1625,8 +1638,6 @@
|
||||||
|
|
||||||
"@oxc-resolver/binding-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
|
"@oxc-resolver/binding-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
|
||||||
|
|
||||||
"@vitest/expect/@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="],
|
|
||||||
|
|
||||||
"cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
"cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
"cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||||
|
|
@ -1689,10 +1700,16 @@
|
||||||
|
|
||||||
"shadcn/open/wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="],
|
"shadcn/open/wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="],
|
||||||
|
|
||||||
|
"storybook/@vitest/expect/@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="],
|
||||||
|
|
||||||
|
"storybook/@vitest/expect/chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="],
|
||||||
|
|
||||||
|
"storybook/@vitest/expect/tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="],
|
||||||
|
|
||||||
"string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
"vitest/@vitest/expect/chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="],
|
|
||||||
|
|
||||||
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
|
"storybook/@vitest/expect/@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
packages/dashboard-model/package.json
Normal file
34
packages/dashboard-model/package.json
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"name": "@dimensionlab/dashboard-model",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"default": "./dist/index.js"
|
||||||
|
},
|
||||||
|
"./fixtures": {
|
||||||
|
"types": "./dist/fixtures/index.d.ts",
|
||||||
|
"default": "./dist/fixtures/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
||||||
|
"check": "tsc --noEmit",
|
||||||
|
"test": "vitest run",
|
||||||
|
"test:unit": "vitest run"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@sinclair/typebox": "^0.34.49",
|
||||||
|
"ajv": "^8.20.0",
|
||||||
|
"ajv-formats": "^3.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "^1.3.14",
|
||||||
|
"@types/node": "^25.9.3",
|
||||||
|
"bun-types": "^1.3.14",
|
||||||
|
"typescript": "^6.0.3",
|
||||||
|
"vitest": "^4.1.9"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
packages/dashboard-model/src/fixtures/index.ts
Normal file
1
packages/dashboard-model/src/fixtures/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { genericDashboardFixture } from "./generic";
|
||||||
|
|
@ -5,7 +5,6 @@ import {
|
||||||
validateDashboardDocument,
|
validateDashboardDocument,
|
||||||
} from ".";
|
} from ".";
|
||||||
import {
|
import {
|
||||||
dimensionLabDashboardFixture,
|
|
||||||
genericDashboardFixture,
|
genericDashboardFixture,
|
||||||
} from "./fixtures";
|
} from "./fixtures";
|
||||||
|
|
||||||
|
|
@ -19,12 +18,6 @@ describe("dashboard model validation", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("accepts the Dimension Lab dashboard fixture", () => {
|
|
||||||
const result = validateDashboardDocument(dimensionLabDashboardFixture);
|
|
||||||
|
|
||||||
expect(result.valid).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("rejects documents with an unsupported schema version", () => {
|
it("rejects documents with an unsupported schema version", () => {
|
||||||
const invalid = {
|
const invalid = {
|
||||||
...genericDashboardFixture,
|
...genericDashboardFixture,
|
||||||
12
packages/dashboard-model/tsconfig.build.json
Normal file
12
packages/dashboard-model/tsconfig.build.json
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"emitDeclarationOnly": false,
|
||||||
|
"noEmit": false,
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts"],
|
||||||
|
"exclude": ["dist", "node_modules", "src/**/*.test.ts"]
|
||||||
|
}
|
||||||
9
packages/dashboard-model/tsconfig.json
Normal file
9
packages/dashboard-model/tsconfig.json
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"types": ["node", "bun-types"]
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts"],
|
||||||
|
"exclude": ["dist", "node_modules"]
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"files": [],
|
"files": [],
|
||||||
"references": [
|
"references": [
|
||||||
|
{ "path": "./packages/dashboard-model" },
|
||||||
{ "path": "./apps/web" },
|
{ "path": "./apps/web" },
|
||||||
{ "path": "./packages/ui" }
|
{ "path": "./packages/ui" }
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue