+12








fcd7c979df
Co-authored-by: Artur <145776561+arturict@users.noreply.github.com> Co-authored-by: arturict <arturict@users.noreply.github.com> Co-authored-by: Thomas <thomas@ajnart.fr> Co-authored-by: Afonso Jorge Ramos <afonsojorgeramos@gmail.com> Co-authored-by: Danura30082 <danura30082+github@gmail.com> Co-authored-by: Kushie <122986913+kushiemoon-dev@users.noreply.github.com> Co-authored-by: ajnart <thomas@ajnart.fr> Co-authored-by: ajnart <thomas@ajnart.dev> Co-authored-by: chenjun <chenjun@foxmail.com> Co-authored-by: Wikibear <wikibear@users.noreply.github.com> Co-authored-by: Bergasha <bergasha@gmail.com> Co-authored-by: leafyelin <43306196+leafyelin@users.noreply.github.com> Co-authored-by: Lucas Araujo <lucas.lra@gmail.com> Co-authored-by: GreenMonito <86085570+GreenMonito@users.noreply.github.com> Co-authored-by: Nerdy-Technician <roffo@nerdy-technician.social> Co-authored-by: Jun <34545896+jcstrong@users.noreply.github.com> Co-authored-by: Edmond Abraham <54119952+gitedmond@users.noreply.github.com> Co-authored-by: thrawnx <tight.bulb9384@fastmail.com> Co-authored-by: Chris <58918656+nordada@users.noreply.github.com> Co-authored-by: yi111 <153097222+Yi-111-a@users.noreply.github.com> Co-authored-by: Yanis <naamaneyanis@gmail.com> Co-authored-by: Wikibear <me@sej.de> Co-authored-by: alessiottavo <93441886+alessiottavo@users.noreply.github.com>
113 lines
4.0 KiB
TypeScript
113 lines
4.0 KiB
TypeScript
import { z } from "zod/v4";
|
|
|
|
import {
|
|
colorSchemes,
|
|
integrationKinds,
|
|
integrationSecretKinds,
|
|
onboardingLayoutPresets,
|
|
widgetKinds,
|
|
} from "@homarr/definitions";
|
|
import { supportedLanguages } from "@homarr/translation/languages";
|
|
|
|
import { boardNameSchema } from "./board";
|
|
import { zodEnumFromArray } from "./enums";
|
|
|
|
const hexColorSchema = z.string().regex(/^#[0-9A-Fa-f]{6}$/);
|
|
const serviceAddressSchema = z.string().trim().min(1).max(2048);
|
|
const uniqueIdsSchema = (maxLength = 255) =>
|
|
z
|
|
.array(z.string().trim().min(1).max(maxLength))
|
|
.max(128)
|
|
.refine((ids) => new Set(ids).size === ids.length, { message: "IDs must be unique" });
|
|
const sourceIdSchema = z.string().trim().min(1).max(512);
|
|
|
|
export const onboardingCreateIntegrationSchema = z.object({
|
|
name: z.string().trim().min(1).max(127),
|
|
url: serviceAddressSchema,
|
|
sourceId: sourceIdSchema.optional(),
|
|
iconUrl: z.string().trim().min(1).max(2048).nullable().optional(),
|
|
description: z.string().trim().max(512).nullable().optional(),
|
|
pingUrl: serviceAddressSchema.nullable().optional(),
|
|
});
|
|
|
|
export const onboardingIntegrationDraftSchema = onboardingCreateIntegrationSchema.extend({
|
|
sourceId: sourceIdSchema,
|
|
kind: zodEnumFromArray(integrationKinds),
|
|
secrets: z.array(
|
|
z.object({
|
|
kind: zodEnumFromArray(integrationSecretKinds),
|
|
value: z.string().nonempty(),
|
|
}),
|
|
),
|
|
});
|
|
|
|
export const onboardingDiscoveredAppSchema = z.object({
|
|
sourceId: sourceIdSchema.optional(),
|
|
name: z.string().trim().min(1).max(127),
|
|
href: serviceAddressSchema.nullable(),
|
|
pingUrl: serviceAddressSchema.nullable().optional(),
|
|
iconUrl: z.string().trim().min(1).nullable(),
|
|
description: z.string().trim().max(512).nullable().optional(),
|
|
});
|
|
|
|
export const onboardingAppDraftSchema = onboardingDiscoveredAppSchema.extend({
|
|
sourceId: sourceIdSchema,
|
|
href: serviceAddressSchema,
|
|
});
|
|
|
|
const integrationDraftsSchema = z
|
|
.array(onboardingIntegrationDraftSchema)
|
|
.max(128)
|
|
.refine((drafts) => new Set(drafts.map((draft) => draft.sourceId)).size === drafts.length, {
|
|
message: "Integration source IDs must be unique",
|
|
});
|
|
const appDraftsSchema = z
|
|
.array(onboardingAppDraftSchema)
|
|
.max(128)
|
|
.refine((drafts) => new Set(drafts.map((draft) => draft.sourceId)).size === drafts.length, {
|
|
message: "App source IDs must be unique",
|
|
});
|
|
|
|
export const onboardingCompleteSetupSchema = z
|
|
.object({
|
|
server: z.object({
|
|
defaultLocale: z.enum(supportedLanguages),
|
|
defaultColorScheme: z.enum(colorSchemes),
|
|
analyticsEnabled: z.boolean().optional(),
|
|
}),
|
|
board: z.object({
|
|
id: z.string().trim().min(1).max(255).optional(),
|
|
name: boardNameSchema,
|
|
primaryColor: hexColorSchema,
|
|
secondaryColor: hexColorSchema,
|
|
itemRadius: z.enum(["xs", "sm", "md", "lg", "xl"]),
|
|
layoutPreset: z.enum(onboardingLayoutPresets).default("balanced"),
|
|
columnCount: z.number().int().min(8).max(24).optional(),
|
|
leftSidebar: z.boolean().default(false),
|
|
rightSidebar: z.boolean().default(false),
|
|
}),
|
|
selectedIntegrationIds: uniqueIdsSchema().default([]),
|
|
selectedAppIds: uniqueIdsSchema().default([]),
|
|
integrations: integrationDraftsSchema.default([]),
|
|
apps: appDraftsSchema.default([]),
|
|
selectedDockerSourceIds: uniqueIdsSchema(512).default([]),
|
|
selectedWidgetKinds: z
|
|
.array(z.enum(widgetKinds))
|
|
.max(widgetKinds.length)
|
|
.refine((kinds) => new Set(kinds).size === kinds.length, { message: "Widget kinds must be unique" })
|
|
.default([]),
|
|
})
|
|
.superRefine((input, ctx) => {
|
|
const integrationSourceIds = new Set(input.integrations.map((integration) => integration.sourceId));
|
|
for (const [index, app] of input.apps.entries()) {
|
|
if (!integrationSourceIds.has(app.sourceId)) continue;
|
|
ctx.addIssue({
|
|
code: "custom",
|
|
message: "A source ID cannot be used by both an integration and an app",
|
|
path: ["apps", index, "sourceId"],
|
|
});
|
|
}
|
|
});
|
|
|
|
export type OnboardingCompleteSetupInput = z.infer<typeof onboardingCompleteSetupSchema>;
|