feat(smart-url): step builder form in cell editor (add/remove/configure steps inline)

This commit is contained in:
Mitchell R 2026-05-23 02:35:57 +02:00
parent af639b4d46
commit 565cd01ca6
No known key found for this signature in database
2 changed files with 66 additions and 0 deletions

View file

@ -1104,6 +1104,40 @@ export function registerAdminRoutes(app: H3, deps: AdminDeps): void {
await resolveOverlaps(deps, layoutId, cellId, axis);
}
}
// Parse smart URL steps from the step builder form fields.
const steps: Array<Record<string, unknown>> = [];
for (let i = 0; i < 50; i++) {
const stepType = body?.[`step_${i}_type`];
const stepValue = body?.[`step_${i}_value`];
if (!stepType) break;
const step: Record<string, unknown> = { type: stepType };
if (stepType === "navigate") step["url"] = stepValue;
else if (stepType === "fill" && stepValue?.includes("=")) {
const eqIdx = stepValue.indexOf("=");
step["selector"] = stepValue.slice(0, eqIdx);
step["value"] = stepValue.slice(eqIdx + 1);
}
else if (stepType === "click" || stepType === "wait_for") step["selector"] = stepValue;
else if (stepType === "wait") step["delay_ms"] = Number(stepValue) || 1000;
else if (stepType === "javascript") step["script"] = stepValue;
steps.push(step);
}
const loginDetect = (body?.["smart_url_login_detect"] ?? "").trim();
const updatedCell = await deps.repo.getLayoutCellById(cellId);
if (updatedCell) {
const opts = { ...(updatedCell.options ?? {}) };
if (steps.length > 0) {
opts["smart_url"] = {
steps,
...(loginDetect ? { login_detect_url: loginDetect } : {}),
};
} else {
delete opts["smart_url"];
}
await deps.repo.updateLayoutCell(cellId, { options: JSON.stringify(opts) } as any);
}
notifyKiosks();
if (isHtmxRequest(event)) {

View file

@ -2316,6 +2316,38 @@ export function renderCell(
</select>
</div>
{/* Smart URL step builder — shown for web/dashboard cells */}
<div class="form-group" id={`smart-url-${String(c.id)}`}>
<label style="font-weight:600">Smart URL Steps</label>
<div style="font-size:0.7rem;color:#666;margin-bottom:0.5rem">
Auto-login / navigate sequences. Leave empty for direct URL load.
</div>
<div id={`steps-${String(c.id)}`}>
{((c.options?.["smart_url"] as any)?.steps ?? []).map((step: any, idx: number) => (
<div style="display:grid;grid-template-columns:100px 1fr auto;gap:4px;margin-bottom:4px;align-items:center">
<select name={`step_${idx}_type`} class="form-input" style="font-size:0.75rem">
{["navigate","fill","click","wait","wait_for","javascript"].map((t) => (
<option value={t} selected={step.type === t}>{t}</option>
))}
</select>
<input name={`step_${idx}_value`} type="text" class="form-input" style="font-size:0.75rem"
placeholder={step.type === "navigate" ? "URL" : step.type === "fill" ? "selector=value" : step.type === "click" ? "CSS selector" : step.type === "wait" ? "ms" : step.type === "javascript" ? "JS code" : "selector"}
value={step.type === "fill" ? `${step.selector ?? ""}=${step.value ?? ""}` : step.url ?? step.selector ?? step.script ?? (step.delay_ms != null ? String(step.delay_ms) : "")} />
<button type="button" class="btn btn-sm btn-danger" style="padding:2px 6px"
onclick={`this.closest('div').remove()`}>×</button>
</div>
))}
</div>
<button type="button" class="btn btn-sm btn-ghost" style="font-size:0.75rem"
onclick={`var d=document.createElement('div');d.style='display:grid;grid-template-columns:100px 1fr auto;gap:4px;margin-bottom:4px;align-items:center';var n=document.querySelectorAll('#steps-${String(c.id)} > div').length;d.innerHTML='<select name=\"step_'+n+'_type\" class=\"form-input\" style=\"font-size:0.75rem\"><option value=\"navigate\">navigate</option><option value=\"fill\">fill</option><option value=\"click\">click</option><option value=\"wait\">wait</option><option value=\"wait_for\">wait_for</option><option value=\"javascript\">javascript</option></select><input name=\"step_'+n+'_value\" type=\"text\" class=\"form-input\" style=\"font-size:0.75rem\" placeholder=\"value\"><button type=\"button\" class=\"btn btn-sm btn-danger\" style=\"padding:2px 6px\" onclick=\"this.closest(\\'div\\').remove()\">×</button>';document.getElementById('steps-${String(c.id)}').appendChild(d)`}
>+ Add Step</button>
<div style="margin-top:0.5rem">
<label style="font-size:0.7rem">Login detect URL (re-run steps when redirected here)</label>
<input name="smart_url_login_detect" type="text" class="form-input" style="font-size:0.75rem"
value={(c.options?.["smart_url"] as any)?.login_detect_url ?? ""} placeholder="e.g. /login" />
</div>
</div>
<div class="form-group span-grid">
<div>
<label>Width</label>