feat(kol): expand variable schema and polish KOL UI
- Add length/range limits to KOL variable definitions: max_length and default_value for input/textarea, min_value/max_value/default_number for number. Backend validates and normalizes; frontend renders limit inputs in KolVariableConfig and applies limits at runtime in KolDynamicForm. - Sort workspace cards by most recent prompt/package update, falling back to granted_at. Adds updated_at to KolWorkspaceCard. - Polish TemplatesView, WorkspaceView, and KOL package management UI; route create/update/publish/archive/delete toasts through i18n and expand package form copy and status labels. - Remove stale KnowledgeView.vue.patch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -297,10 +297,7 @@ export const kolManageApi = {
|
||||
}>>("/api/tenant/kol/manage/profile/avatar", formData);
|
||||
|
||||
markImageUploadRequestFinished(progressToken);
|
||||
return {
|
||||
...response.data.data,
|
||||
url: resolveApiURL(response.data.data.url),
|
||||
};
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
markImageUploadRequestFailed(progressToken);
|
||||
throw error;
|
||||
|
||||
@@ -4,6 +4,10 @@ import { newVariableId } from "./kol-variable-id";
|
||||
|
||||
const KOL_PLACEHOLDER_RE = /\{\{\s*([^{}]+?)\s*\}\}/g;
|
||||
|
||||
export const DEFAULT_KOL_TEXT_MAX_LENGTH = 20;
|
||||
export const DEFAULT_KOL_NUMBER_MIN = 0;
|
||||
export const DEFAULT_KOL_NUMBER_MAX = 10000;
|
||||
|
||||
function normalizePlaceholderKey(value: string): string {
|
||||
return value.trim();
|
||||
}
|
||||
@@ -21,6 +25,32 @@ function normalizeVariableType(type?: KolVariableType): KolVariableType {
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeFiniteNumber(value: unknown): number | undefined {
|
||||
if (typeof value === "number" && Number.isFinite(value)) {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "string" && value.trim()) {
|
||||
const parsed = Number(value);
|
||||
if (Number.isFinite(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function normalizePositiveInteger(value: unknown, fallback: number): number {
|
||||
const normalized = normalizeFiniteNumber(value);
|
||||
if (normalized === undefined) {
|
||||
return fallback;
|
||||
}
|
||||
const rounded = Math.trunc(normalized);
|
||||
return rounded > 0 ? rounded : fallback;
|
||||
}
|
||||
|
||||
function clampNumber(value: number, min: number, max: number): number {
|
||||
return Math.min(max, Math.max(min, value));
|
||||
}
|
||||
|
||||
export function buildKolPlaceholderToken(key: string): string {
|
||||
return `{{${normalizePlaceholderKey(key)}}}`;
|
||||
}
|
||||
@@ -70,7 +100,7 @@ export function createKolVariableDefinition(
|
||||
): KolVariableDefinition {
|
||||
const normalizedKey = normalizePlaceholderKey(key);
|
||||
|
||||
return {
|
||||
return normalizeKolVariableDefinition({
|
||||
id: overrides.id?.trim() || newVariableId(),
|
||||
key: normalizedKey,
|
||||
label: overrides.label?.trim() || normalizedKey,
|
||||
@@ -78,7 +108,145 @@ export function createKolVariableDefinition(
|
||||
required: overrides.required ?? true,
|
||||
placeholder: overrides.placeholder,
|
||||
options: overrides.options,
|
||||
max_length: overrides.max_length,
|
||||
default_value: overrides.default_value,
|
||||
min_value: overrides.min_value,
|
||||
max_value: overrides.max_value,
|
||||
default_number: overrides.default_number,
|
||||
});
|
||||
}
|
||||
|
||||
export function getKolVariableTextMaxLength(variable: KolVariableDefinition): number {
|
||||
return normalizePositiveInteger(variable.max_length, DEFAULT_KOL_TEXT_MAX_LENGTH);
|
||||
}
|
||||
|
||||
export function getKolVariableNumberMin(variable: KolVariableDefinition): number {
|
||||
return normalizeFiniteNumber(variable.min_value) ?? DEFAULT_KOL_NUMBER_MIN;
|
||||
}
|
||||
|
||||
export function getKolVariableNumberMax(variable: KolVariableDefinition): number {
|
||||
const min = getKolVariableNumberMin(variable);
|
||||
const max = normalizeFiniteNumber(variable.max_value) ?? DEFAULT_KOL_NUMBER_MAX;
|
||||
return max >= min ? max : min;
|
||||
}
|
||||
|
||||
export function normalizeKolVariableDefinition(variable: KolVariableDefinition): KolVariableDefinition {
|
||||
const type = normalizeVariableType(variable.type);
|
||||
const normalizedKey = normalizePlaceholderKey(variable.key || variable.label || variable.id);
|
||||
const normalizedLabel = variable.label?.trim() || normalizedKey;
|
||||
const normalizedOptions =
|
||||
type === "select" || type === "checkbox"
|
||||
? (variable.options || []).map((item) => item.trim()).filter(Boolean)
|
||||
: undefined;
|
||||
|
||||
const baseVariable: KolVariableDefinition = {
|
||||
...variable,
|
||||
id: variable.id?.trim() || newVariableId(),
|
||||
key: normalizedKey,
|
||||
label: normalizedLabel,
|
||||
type,
|
||||
required: variable.required ?? true,
|
||||
placeholder: variable.placeholder,
|
||||
options: normalizedOptions,
|
||||
};
|
||||
|
||||
if (type === "input" || type === "textarea") {
|
||||
const maxLength = getKolVariableTextMaxLength(baseVariable);
|
||||
const defaultValue =
|
||||
typeof variable.default_value === "string"
|
||||
? variable.default_value.slice(0, maxLength)
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
...baseVariable,
|
||||
max_length: maxLength,
|
||||
default_value: defaultValue,
|
||||
min_value: undefined,
|
||||
max_value: undefined,
|
||||
default_number: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
if (type === "number") {
|
||||
const minValue = getKolVariableNumberMin(baseVariable);
|
||||
const maxValue = getKolVariableNumberMax(baseVariable);
|
||||
const rawDefaultNumber = normalizeFiniteNumber(variable.default_number);
|
||||
const defaultNumber =
|
||||
rawDefaultNumber === undefined ? undefined : clampNumber(rawDefaultNumber, minValue, maxValue);
|
||||
|
||||
return {
|
||||
...baseVariable,
|
||||
options: undefined,
|
||||
max_length: undefined,
|
||||
default_value: undefined,
|
||||
min_value: minValue,
|
||||
max_value: maxValue,
|
||||
default_number: defaultNumber,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...baseVariable,
|
||||
max_length: undefined,
|
||||
default_value: undefined,
|
||||
min_value: undefined,
|
||||
max_value: undefined,
|
||||
default_number: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export function getKolVariableInitialValue(variable: KolVariableDefinition): any {
|
||||
const normalized = normalizeKolVariableDefinition(variable);
|
||||
|
||||
if (normalized.type === "checkbox") {
|
||||
return [];
|
||||
}
|
||||
if (normalized.type === "number") {
|
||||
return normalized.default_number;
|
||||
}
|
||||
if (normalized.type === "input" || normalized.type === "textarea") {
|
||||
return normalized.default_value;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function sanitizeKolVariableValue(variable: KolVariableDefinition, value: any): any {
|
||||
const normalized = normalizeKolVariableDefinition(variable);
|
||||
|
||||
if (normalized.type === "number") {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return undefined;
|
||||
}
|
||||
const numericValue = normalizeFiniteNumber(value);
|
||||
if (numericValue === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return clampNumber(numericValue, getKolVariableNumberMin(normalized), getKolVariableNumberMax(normalized));
|
||||
}
|
||||
|
||||
if (normalized.type === "input" || normalized.type === "textarea") {
|
||||
if (value === null || value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return String(value).slice(0, getKolVariableTextMaxLength(normalized));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export function isKolVariableValueEmpty(variable: KolVariableDefinition, value: any): boolean {
|
||||
const normalized = normalizeKolVariableDefinition(variable);
|
||||
|
||||
if (normalized.type === "checkbox") {
|
||||
return !Array.isArray(value) || value.length === 0;
|
||||
}
|
||||
if (normalized.type === "number") {
|
||||
return value === null || value === undefined || value === "";
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
return value.trim().length === 0;
|
||||
}
|
||||
return value === null || value === undefined;
|
||||
}
|
||||
|
||||
export function syncKolVariablesWithContent(
|
||||
@@ -95,7 +263,7 @@ export function syncKolVariablesWithContent(
|
||||
}
|
||||
byKey.set(
|
||||
key,
|
||||
createKolVariableDefinition(key, {
|
||||
normalizeKolVariableDefinition({
|
||||
...variable,
|
||||
key,
|
||||
label: variable.label?.trim() || key,
|
||||
|
||||
Reference in New Issue
Block a user