Add previewArgs support for template functions and enhance validation logic for form inputs

This commit is contained in:
Gregory Schier
2025-11-27 12:55:39 -08:00
parent 0c7034eefc
commit 8d1b17cac1
24 changed files with 340 additions and 92 deletions

View File

@@ -1 +1,3 @@
export * from './debounce';
export * from './formatSize';
export * from './templateFunction';

View File

@@ -0,0 +1,49 @@
import type {
CallTemplateFunctionArgs,
JsonPrimitive,
TemplateFunctionArg,
} from '@yaakapp-internal/plugins';
export function validateTemplateFunctionArgs(
fnName: string,
args: TemplateFunctionArg[],
values: CallTemplateFunctionArgs['values'],
): string | null {
for (const arg of args) {
if ('inputs' in arg && arg.inputs) {
// Recurse down
const err = validateTemplateFunctionArgs(fnName, arg.inputs, values);
if (err) return err;
}
if (!('name' in arg)) continue;
if (arg.optional) continue;
if (arg.defaultValue != null) continue;
if (arg.hidden) continue;
if (values[arg.name] != null) continue;
return `Missing required argument "${arg.label || arg.name}" for template function ${fnName}()`;
}
return null;
}
/** Recursively apply form input defaults to a set of values */
export function applyFormInputDefaults(
inputs: TemplateFunctionArg[],
values: { [p: string]: JsonPrimitive | undefined },
) {
let newValues: { [p: string]: JsonPrimitive | undefined } = { ...values };
for (const input of inputs) {
if ('defaultValue' in input && values[input.name] === undefined) {
newValues[input.name] = input.defaultValue;
}
if (input.type === 'checkbox' && values[input.name] === undefined) {
newValues[input.name] = false;
}
// Recurse down to all child inputs
if ('inputs' in input) {
newValues = applyFormInputDefaults(input.inputs ?? [], newValues);
}
}
return newValues;
}

View File

@@ -450,7 +450,11 @@ export type TemplateFunction = { name: string, previewType?: TemplateFunctionPre
* Also support alternative names. This is useful for not breaking existing
* tags when changing the `name` property
*/
aliases?: Array<string>, args: Array<TemplateFunctionArg>, };
aliases?: Array<string>, args: Array<TemplateFunctionArg>,
/**
* A list of arg names to show in the inline preview. If not provided, none will be shown (for privacy reasons).
*/
previewArgs?: Array<string>, };
/**
* Similar to FormInput, but contains

View File

@@ -1,3 +1,4 @@
import { validateTemplateFunctionArgs } from '@yaakapp-internal/lib/templateFunction';
import {
BootRequest,
DeleteKeyValueResponse,
@@ -28,7 +29,6 @@ import path from 'node:path';
import {
applyDynamicFormInput,
applyFormInputDefaults,
validateTemplateFunctionArgs,
} from './common';
import { EventChannel } from './EventChannel';
import { migrateTemplateFunctionSelectOptions } from './migrations';

View File

@@ -1,31 +1,6 @@
import {
CallHttpAuthenticationActionArgs,
CallTemplateFunctionArgs,
JsonPrimitive,
TemplateFunctionArg,
} from '@yaakapp-internal/plugins';
import { CallHttpAuthenticationActionArgs, CallTemplateFunctionArgs } from '@yaakapp-internal/plugins';
import { Context, DynamicAuthenticationArg, DynamicTemplateFunctionArg } from '@yaakapp/api';
/** Recursively apply form input defaults to a set of values */
export function applyFormInputDefaults(
inputs: TemplateFunctionArg[],
values: { [p: string]: JsonPrimitive | undefined },
) {
let newValues: { [p: string]: JsonPrimitive | undefined } = { ...values };
for (const input of inputs) {
if ('defaultValue' in input && values[input.name] === undefined) {
newValues[input.name] = input.defaultValue;
} else if (input.type === 'checkbox' && values[input.name] === undefined) {
newValues[input.name] = false;
}
// Recurse down to all child inputs
if ('inputs' in input) {
newValues = applyFormInputDefaults(input.inputs ?? [], newValues);
}
}
return newValues;
}
export async function applyDynamicFormInput(
ctx: Context,
args: DynamicTemplateFunctionArg[],
@@ -60,26 +35,3 @@ export async function applyDynamicFormInput(
}
return resolvedArgs;
}
export function validateTemplateFunctionArgs(
fnName: string,
args: TemplateFunctionArg[],
values: CallTemplateFunctionArgs['values'],
): string | null {
for (const arg of args) {
if ('inputs' in arg && arg.inputs) {
// Recurse down
const err = validateTemplateFunctionArgs(fnName, arg.inputs, values);
if (err) return err;
}
if (!('name' in arg)) continue;
if (arg.optional) continue;
if (arg.defaultValue != null) continue;
if (arg.hidden) continue;
if (values[arg.name] != null) continue;
return `Missing required argument "${arg.label || arg.name}" for template function ${fnName}()`;
}
return null;
}