ai #1
@@ -21,6 +21,10 @@ export function ConfigTemplate(props: ConfigTemplateProps) {
|
||||
}
|
||||
}, [props.config.template.content, mode]);
|
||||
|
||||
// Validate placeholders (check if @placeholders@ have matching params)
|
||||
const missingPlaceholders = props.config.validatePlaceholders();
|
||||
const hasValidationWarnings = missingPlaceholders.length > 0;
|
||||
|
||||
function handleEdit() {
|
||||
setOriginalContent(props.config.template.content);
|
||||
setDraftContent(props.config.template.content);
|
||||
@@ -67,11 +71,21 @@ export function ConfigTemplate(props: ConfigTemplateProps) {
|
||||
<div className="config-template-editor">
|
||||
{mode === 'view' ? (
|
||||
<>
|
||||
<div className="mb-2">
|
||||
<div className="mb-2 d-flex gap-2 align-items-center">
|
||||
<button className="btn btn-primary btn-sm" onClick={handleEdit}>
|
||||
✎ Edit
|
||||
</button>
|
||||
{hasValidationWarnings && (
|
||||
<span className="text-warning">
|
||||
⚠ {missingPlaceholders.length} placeholder(s) without params
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{hasValidationWarnings && (
|
||||
<div className="alert alert-warning py-2 px-3 mb-2" style={{ fontSize: '0.875rem' }}>
|
||||
<strong>Missing parameters:</strong> {missingPlaceholders.join(", ")}
|
||||
</div>
|
||||
)}
|
||||
<Highlight className="language-json">
|
||||
{props.config.template.content || "{}"}
|
||||
</Highlight>
|
||||
|
||||
@@ -109,5 +109,50 @@ export class Config {
|
||||
|
||||
return missingParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that all @placeholders@ in template have corresponding params.
|
||||
* Checks DEFAULT env first, then all custom envs.
|
||||
* Returns array of placeholder names that are not defined.
|
||||
*/
|
||||
validatePlaceholders(): string[] {
|
||||
const defaultEnv = this.envs.find(e => e.name === "DEFAULT");
|
||||
const customEnvs = this.envs.filter(e => e.name !== "DEFAULT");
|
||||
|
||||
// Collect all param names from DEFAULT
|
||||
const defaultParamNames = new Set(
|
||||
defaultEnv?.params.map(p => p.name).filter(n => n && n.trim() !== "") || []
|
||||
);
|
||||
|
||||
// Collect all param names from all custom envs
|
||||
const customParamNames = new Set(
|
||||
customEnvs.flatMap(e => e.params.map(p => p.name).filter(n => n && n.trim() !== ""))
|
||||
);
|
||||
|
||||
// Extract all @placeholders@ from template
|
||||
const placeholderRegex = /@(\w+)@/g;
|
||||
const placeholdersInTemplate = new Set<string>();
|
||||
let match;
|
||||
while ((match = placeholderRegex.exec(this.template.content)) !== null) {
|
||||
placeholdersInTemplate.add(match[1]);
|
||||
}
|
||||
|
||||
// Find placeholders that don't have matching params
|
||||
const missingParams: string[] = [];
|
||||
for (const placeholder of placeholdersInTemplate) {
|
||||
if (placeholder === Config.ENV_NAME_PARAM) continue; // Skip built-in
|
||||
|
||||
// Check if exists in DEFAULT or in ANY custom env
|
||||
const inDefault = defaultParamNames.has(placeholder);
|
||||
const inCustom = customParamNames.has(placeholder);
|
||||
|
||||
// Valid if: in DEFAULT, or in at least one custom env
|
||||
if (!inDefault && !inCustom) {
|
||||
missingParams.push(placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
return missingParams;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user