252 lines
7.2 KiB
TypeScript
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;
|