import type { CreateInstancePayload, Instance, PluginStatus, SecretData, TemplateSecret, TemplateSummary, TemplateVariable, TemplateVariableValidator, VariableData, VariableValueType, } from "@/api/configTemplates"; import { markup } from "@/components/ObjectStore/configurationMarkdown"; export interface FormEntry { name: string; label?: string; optional?: boolean; help?: string | null; type: string; value?: any; validators?: TemplateVariableValidator[]; } export function metadataFormEntryName(what: string): FormEntry { return { name: "_meta_name", label: "Name", type: "text", optional: false, help: `Label this new ${what} with a name.`, }; } export function metadataFormEntryDescription(what: string): FormEntry { return { name: "_meta_description", label: "Description", optional: true, type: "textarea", help: `Provide some notes to yourself about this ${what} - perhaps to remind you how it is configured, where it stores the data, etc..`, }; } export function templateVariableFormEntry(variable: TemplateVariable, variableValue?: VariableValueType): FormEntry { const common_fields = { name: variable.name, label: variable.label ?? variable.name, help: markup(variable.help || "", true), validators: variable.validators ?? [], optional: variable.optional || false, }; if (variable.type == "string") { const defaultValue = variable.default ?? ""; return { type: "text", value: variableValue == undefined ? defaultValue : variableValue, ...common_fields, }; } else if (variable.type == "path_component") { const defaultValue = variable.default ?? ""; return { type: "text", value: variableValue == undefined ? defaultValue : variableValue, ...common_fields, }; } else if (variable.type == "integer") { const defaultValue = variable.default ?? 0; return { type: "integer", value: variableValue == undefined ? defaultValue : variableValue, ...common_fields, }; } else if (variable.type == "boolean") { const defaultValue = variable.default ?? false; return { type: "boolean", value: variableValue == undefined ? defaultValue : variableValue, ...common_fields, }; } else { throw Error("Invalid template form input type found."); } } export function templateSecretFormEntry(secret: TemplateSecret): FormEntry { return { name: secret.name, label: secret.label ?? secret.name, type: "password", help: markup(secret.help || "", true), value: "", optional: secret.optional || false, }; } export function editTemplateForm(template: TemplateSummary, what: string, instance: Instance): FormEntry[] { const form = []; const nameInput = metadataFormEntryName(what); form.push({ value: instance.name ?? "", ...nameInput }); const descriptionInput = metadataFormEntryDescription(what); form.push({ value: instance.description ?? "", ...descriptionInput }); const variables = template.variables ?? []; const variableValues: VariableData = instance.variables || {}; for (const variable of variables) { form.push(templateVariableFormEntry(variable, variableValues[variable.name])); } return form; } export function editFormDataToPayload(template: TemplateSummary, formData: any) { const variables = template.variables ?? []; const name = formData["_meta_name"]; const description = formData["_meta_description"]; const variableData: VariableData = {}; for (const variable of variables) { const variableValue = formDataTypedGet(variable, formData); if (variableValue !== undefined) { variableData[variable.name] = variableValue; } } const payload = { name: name, description: description, variables: variableData, }; return payload; } export function createTemplateForm(template: TemplateSummary, what: string): FormEntry[] { const form = []; const variables = template.variables ?? []; const secrets = template.secrets ?? []; form.push(metadataFormEntryName(what)); form.push(metadataFormEntryDescription(what)); for (const variable of variables) { form.push(templateVariableFormEntry(variable, undefined)); } for (const secret of secrets) { form.push(templateSecretFormEntry(secret)); } return form; } export function createFormDataToPayload(template: TemplateSummary, formData: any): CreateInstancePayload { const variables = template.variables ?? []; const secrets = template.secrets ?? []; const variableData: VariableData = {}; const secretData: SecretData = {}; for (const variable of variables) { const variableValue = formDataTypedGet(variable, formData); if (variableValue !== undefined) { variableData[variable.name] = variableValue; } } for (const secret of secrets) { secretData[secret.name] = formData[secret.name]; } const name: string = formData._meta_name; const description: string = formData._meta_description; const payload: CreateInstancePayload = { name: name, description: description, secrets: secretData, variables: variableData, template_id: template.id, template_version: template.version ?? 0, }; return payload; } export function formDataTypedGet(variableDefinition: TemplateVariable, formData: any): VariableValueType | undefined { // galaxy form library doesn't type values traditionally, so add a typed // access to the data if coming back as string. Though it does seem to be // typed properly - this might not be needed anymore? const variableType = variableDefinition.type; const variableName = variableDefinition.name; const rawValue: boolean | string | number | null | undefined = formData[variableName]; if (variableType == "string") { if (rawValue == null || rawValue == undefined) { return undefined; } else { return String(rawValue); } } else if (variableType == "path_component") { if (rawValue == null || rawValue == undefined) { return undefined; } else { return String(rawValue); } } else if (variableType == "boolean") { if (rawValue == null || rawValue == undefined || typeof rawValue == "number") { return undefined; } else { return String(rawValue).toLowerCase() == "true"; } } else if (variableType == "integer") { if (rawValue == null || rawValue == undefined || typeof rawValue == "boolean") { return undefined; } else { if (typeof rawValue == "string") { return parseInt(rawValue); } else { return rawValue; } } } else { throw Error("Unknown variable type encountered, shouldn't be possible."); } } export function upgradeForm(template: TemplateSummary, instance: Instance): FormEntry[] { const form = []; const variables = template.variables ?? []; const secrets = template.secrets ?? []; const variableValues: VariableData = instance.variables || {}; const secretsSet = instance.secrets || []; for (const variable of variables) { form.push(templateVariableFormEntry(variable, variableValues[variable.name])); } for (const secret of secrets) { const secretName = secret.name; if (secretsSet.indexOf(secretName) < 0) { form.push(templateSecretFormEntry(secret)); } } return form; } export function upgradeFormDataToPayload(template: TemplateSummary, formData: any) { const variables = template.variables ?? []; const variableData: VariableData = {}; for (const variable of variables) { variableData[variable.name] = formData[variable.name]; } const secrets = {}; // ideally we would be able to force a template version here, // maybe rework backend types to force this in the API response // even if we don't need it in the config files const templateVersion: number = template.version || 0; const payload = { template_version: templateVersion, variables: variableData, secrets: secrets, }; return payload; } export function pluginStatusToErrorMessage(pluginStatus: PluginStatus): string | null { if (pluginStatus.template_definition.state == "not_ok") { return pluginStatus.template_definition.message; } else if (pluginStatus.template_settings?.state == "not_ok") { return pluginStatus.template_settings.message; } else if (pluginStatus.connection?.state == "not_ok") { return pluginStatus.connection.message; } return null; }