import { Type, type Static } from "@sinclair/typebox"; export const DASHBOARD_SCHEMA_VERSION = "dashboard.v1" as const; const IdentifierSchema = Type.String({ minLength: 1, pattern: "^[a-z0-9][a-z0-9-_.:]*$", }); const SeveritySchema = Type.Union([ Type.Literal("neutral"), Type.Literal("ok"), Type.Literal("warning"), Type.Literal("danger"), Type.Literal("stale"), Type.Literal("unavailable"), ]); const IconReferenceSchema = Type.String({ minLength: 1 }); const LinkSchema = Type.Object( { href: Type.String({ format: "uri" }), label: Type.Optional(Type.String({ minLength: 1 })), external: Type.Optional(Type.Boolean()), }, { additionalProperties: false }, ); const StaticDatasourceSchema = Type.Object( { type: Type.Literal("static"), label: Type.Optional(Type.String({ minLength: 1 })), updatedAt: Type.Optional(Type.String({ format: "date-time" })), }, { additionalProperties: false }, ); const PlaceholderDatasourceSchema = Type.Object( { type: Type.Literal("placeholder"), reason: Type.String({ minLength: 1 }), }, { additionalProperties: false }, ); const ExternalDatasourceSchema = Type.Object( { type: Type.Literal("external"), adapter: Type.Union([ Type.Literal("prometheus"), Type.Literal("http-status"), Type.Literal("weather"), Type.Literal("custom"), ]), reference: Type.String({ minLength: 1 }), }, { additionalProperties: false }, ); const DatasourceReferenceSchema = Type.Union([ StaticDatasourceSchema, PlaceholderDatasourceSchema, ExternalDatasourceSchema, ]); const PercentMetricValueSchema = Type.Object( { kind: Type.Literal("percent"), value: Type.Number({ minimum: 0, maximum: 100 }), unit: Type.Optional(Type.String({ minLength: 1 })), precision: Type.Optional(Type.Integer({ minimum: 0, maximum: 4 })), }, { additionalProperties: false }, ); const NonNegativeMetricValueSchema = Type.Object( { kind: Type.Union([ Type.Literal("bytes"), Type.Literal("temperature"), Type.Literal("latency"), Type.Literal("number"), ]), value: Type.Number({ minimum: 0 }), unit: Type.Optional(Type.String({ minLength: 1 })), precision: Type.Optional(Type.Integer({ minimum: 0, maximum: 4 })), }, { additionalProperties: false }, ); const TextMetricValueSchema = Type.Object( { kind: Type.Literal("text"), value: Type.String(), unit: Type.Optional(Type.String({ minLength: 1 })), }, { additionalProperties: false }, ); const MetricValueSchema = Type.Union([ PercentMetricValueSchema, NonNegativeMetricValueSchema, TextMetricValueSchema, ]); const ThresholdSchema = Type.Object( { warning: Type.Optional(Type.Number({ minimum: 0 })), danger: Type.Optional(Type.Number({ minimum: 0 })), }, { additionalProperties: false, minProperties: 1 }, ); export const TelemetryCardSchema = Type.Object( { id: IdentifierSchema, label: Type.String({ minLength: 1 }), description: Type.Optional(Type.String()), icon: Type.Optional(IconReferenceSchema), value: MetricValueSchema, detail: Type.Optional(Type.String()), severity: SeveritySchema, thresholds: Type.Optional(ThresholdSchema), datasource: Type.Optional(DatasourceReferenceSchema), sparkline: Type.Optional(Type.Array(Type.Number())), }, { additionalProperties: false }, ); export const ServiceEntrySchema = Type.Object( { id: IdentifierSchema, label: Type.String({ minLength: 1 }), description: Type.String(), icon: Type.Optional(IconReferenceSchema), link: Type.Optional(LinkSchema), severity: SeveritySchema, detail: Type.Optional(Type.String()), datasource: Type.Optional(DatasourceReferenceSchema), }, { additionalProperties: false }, ); export const ServiceGroupSchema = Type.Object( { id: IdentifierSchema, title: Type.String({ minLength: 1 }), layout: Type.Optional(Type.Union([Type.Literal("list"), Type.Literal("grid")])), services: Type.Array(ServiceEntrySchema), }, { additionalProperties: false }, ); export const StatusItemSchema = Type.Object( { id: IdentifierSchema, label: Type.String({ minLength: 1 }), value: Type.String(), severity: Type.Optional(SeveritySchema), link: Type.Optional(LinkSchema), }, { additionalProperties: false }, ); export const StatusStripSchema = Type.Object( { id: IdentifierSchema, title: Type.Optional(Type.String({ minLength: 1 })), items: Type.Array(StatusItemSchema), }, { additionalProperties: false }, ); export const DashboardModuleSchema = Type.Object( { id: IdentifierSchema, kind: Type.Union([ Type.Literal("summary"), Type.Literal("weather"), Type.Literal("custom"), ]), title: Type.Optional(Type.String({ minLength: 1 })), label: Type.Optional(Type.String()), value: Type.Optional(Type.String()), detail: Type.Optional(Type.String()), icon: Type.Optional(IconReferenceSchema), severity: Type.Optional(SeveritySchema), datasource: Type.Optional(DatasourceReferenceSchema), }, { additionalProperties: false }, ); const LayoutSchema = Type.Object( { density: Type.Optional(Type.Union([Type.Literal("compact"), Type.Literal("dense")])), telemetry: Type.Array(IdentifierSchema), serviceGroups: Type.Array(IdentifierSchema), statusStrips: Type.Array(IdentifierSchema), modules: Type.Optional(Type.Array(IdentifierSchema)), }, { additionalProperties: false }, ); const MetadataSchema = Type.Object( { title: Type.String({ minLength: 1 }), subtitle: Type.Optional(Type.String()), description: Type.Optional(Type.String()), timezone: Type.Optional(Type.String({ minLength: 1 })), refreshIntervalSeconds: Type.Optional(Type.Integer({ minimum: 5 })), }, { additionalProperties: false }, ); export const DashboardDocumentSchema = Type.Object( { schemaVersion: Type.Literal(DASHBOARD_SCHEMA_VERSION), metadata: MetadataSchema, layout: LayoutSchema, telemetry: Type.Array(TelemetryCardSchema), serviceGroups: Type.Array(ServiceGroupSchema), statusStrips: Type.Array(StatusStripSchema), modules: Type.Optional(Type.Array(DashboardModuleSchema)), migration: Type.Optional( Type.Object( { previousVersion: Type.Optional(Type.String({ minLength: 1 })), notes: Type.Optional(Type.String()), }, { additionalProperties: false }, ), ), }, { $id: "https://dimensionlab.net/schemas/dashboard-document.v1.json", additionalProperties: false, }, ); export type Severity = Static; export type DatasourceReference = Static; export type MetricValue = Static; export type TelemetryCard = Static; export type ServiceEntry = Static; export type ServiceGroup = Static; export type StatusItem = Static; export type StatusStrip = Static; export type DashboardModule = Static; export type DashboardDocument = Static; export const dashboardDocumentJsonSchema = DashboardDocumentSchema;