dimensionlab-website/packages/dashboard-model/src/schema.ts

252 lines
7.2 KiB
TypeScript

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 },
);
export 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 },
);
export const PlaceholderDatasourceSchema = Type.Object(
{
type: Type.Literal("placeholder"),
reason: Type.String({ minLength: 1 }),
},
{ additionalProperties: false },
);
export 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 },
);
export 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 },
);
export const MetricValueSchema = Type.Union([
PercentMetricValueSchema,
NonNegativeMetricValueSchema,
TextMetricValueSchema,
]);
export 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<typeof SeveritySchema>;
export type DatasourceReference = Static<typeof DatasourceReferenceSchema>;
export type MetricValue = Static<typeof MetricValueSchema>;
export type TelemetryCard = Static<typeof TelemetryCardSchema>;
export type ServiceEntry = Static<typeof ServiceEntrySchema>;
export type ServiceGroup = Static<typeof ServiceGroupSchema>;
export type StatusItem = Static<typeof StatusItemSchema>;
export type StatusStrip = Static<typeof StatusStripSchema>;
export type DashboardModule = Static<typeof DashboardModuleSchema>;
export type DashboardDocument = Static<typeof DashboardDocumentSchema>;
export const dashboardDocumentJsonSchema = DashboardDocumentSchema;