import { objectEntries } from "@homarr/common"; import type { WidgetKind } from "@homarr/definitions"; import type { z } from "@homarr/validation"; import { widgetImports } from "."; interface CommonInput { defaultValue?: TType; withDescription?: boolean; } interface TextInput extends CommonInput { validate: z.ZodType; } interface MultiSelectInput extends CommonInput { options: TOptions; } interface SelectInput extends CommonInput { options: TOptions; } interface NumberInput extends CommonInput { validate: z.ZodNumber; step?: number; } interface SliderInput extends CommonInput { validate: z.ZodNumber; step?: number; } interface OptLocation { name: string; latitude: number; longitude: number; } const optionsFactory = { switch: (input?: CommonInput) => ({ type: "switch" as const, defaultValue: input?.defaultValue ?? false, withDescription: input?.withDescription ?? false, }), text: (input?: TextInput) => ({ type: "text" as const, defaultValue: input?.defaultValue ?? "", withDescription: input?.withDescription ?? false, validate: input?.validate, }), multiSelect: ( input: MultiSelectInput, ) => ({ type: "multiSelect" as const, defaultValue: input.defaultValue ?? [], options: input.options, withDescription: input.withDescription ?? false, }), select: ( input: SelectInput, ) => ({ type: "select" as const, defaultValue: input.defaultValue ?? input.options[0], options: input.options, withDescription: input.withDescription ?? false, }), number: (input: NumberInput) => ({ type: "number" as const, defaultValue: input.defaultValue ?? ("" as const), step: input.step, withDescription: input.withDescription ?? false, validate: input.validate, }), slider: (input: SliderInput) => ({ type: "slider" as const, defaultValue: input.defaultValue ?? input.validate.minValue ?? 0, step: input.step, withDescription: input.withDescription ?? false, validate: input.validate, }), location: (input?: CommonInput) => ({ type: "location" as const, defaultValue: input?.defaultValue ?? { name: "", latitude: 0, longitude: 0, }, withDescription: input?.withDescription ?? false, }), multiText: (input?: CommonInput) => ({ type: "multiText" as const, defaultValue: input?.defaultValue ?? [], withDescription: input?.withDescription ?? false, }), }; type WidgetOptionFactory = typeof optionsFactory; export type WidgetOptionDefinition = ReturnType< WidgetOptionFactory[keyof WidgetOptionFactory] >; export type WidgetOptionsRecord = Record; export type WidgetOptionType = WidgetOptionDefinition["type"]; export type WidgetOptionOfType = Extract< WidgetOptionDefinition, { type: TType } >; type inferOptionFromDefinition = TDefinition["defaultValue"]; export type inferOptionsFromDefinition = { [key in keyof TOptions]: inferOptionFromDefinition; }; interface FieldConfiguration { shouldHide: (options: inferOptionsFromDefinition) => boolean; } type ConfigurationInput = Partial< Record> >; const createOptions = ( optionsCallback: (factory: WidgetOptionFactory) => TOptions, configuration?: ConfigurationInput, ) => { const obj = {} as Record; const options = optionsCallback(optionsFactory); for (const key in options) { obj[key] = { ...configuration?.[key], ...options[key], }; } return obj as { [key in keyof TOptions]: TOptions[key] & FieldConfiguration; }; }; export const opt = { from: createOptions, }; export const reduceWidgetOptionsWithDefaultValues = ( kind: WidgetKind, currentValue: Record = {}, ) => { const definition = widgetImports[kind].definition; const options = definition.options as Record; return objectEntries(options).reduce( (prev, [key, value]) => ({ ...prev, [key]: currentValue[key] ?? value.defaultValue, }), {} as Record, ); };