feat: add plan step

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2026-03-15 22:38:18 +01:00
parent 7eb6ae7cbb
commit 04e452ecc3
71 changed files with 1059 additions and 319 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -42,6 +42,7 @@ class PipelineBuilder extends HTMLElement {
if (!config) return "deploy";
if (config.Deploy !== undefined) return "deploy";
if (config.Wait !== undefined) return "wait";
if (config.Plan !== undefined) return "plan";
return "deploy";
}
@@ -50,6 +51,7 @@ class PipelineBuilder extends HTMLElement {
if (!config) return "";
if (config.Deploy) return config.Deploy.environment || "";
if (config.Wait) return config.Wait.duration_seconds ? `${config.Wait.duration_seconds}s` : "";
if (config.Plan) return config.Plan.environment || "";
return "";
}
@@ -367,7 +369,7 @@ class PipelineBuilder extends HTMLElement {
// Type select (deploy / wait)
const typeSelect = el("select", "border border-gray-200 rounded px-2 py-1 text-xs bg-white shrink-0");
for (const t of ["deploy", "wait"]) {
for (const t of ["deploy", "wait", "plan"]) {
const opt = document.createElement("option");
opt.value = t;
opt.textContent = t;
@@ -379,6 +381,8 @@ class PipelineBuilder extends HTMLElement {
clearTimeout(this._blurTimer);
if (typeSelect.value === "wait") {
this.stages[index].config = { Wait: { duration_seconds: 0 } };
} else if (typeSelect.value === "plan") {
this.stages[index].config = { Plan: { environment: "", auto_approve: false } };
} else {
this.stages[index].config = { Deploy: { environment: "" } };
}
@@ -440,6 +444,33 @@ class PipelineBuilder extends HTMLElement {
};
const secLabel = el("span", "text-xs text-gray-400", "seconds");
configRow.append(durLabel, durInput, secLabel);
} else if (type === "plan") {
const envLabel = el("span", "text-xs text-gray-500 shrink-0", "env:");
const envInput = el("input", "border border-gray-200 rounded px-2 py-1 text-xs w-32 focus:outline-none focus:ring-1 focus:ring-gray-400");
envInput.type = "text";
envInput.value = (stage.config.Plan && stage.config.Plan.environment) || "";
envInput.placeholder = "environment";
envInput.onmousedown = (e) => e.stopPropagation();
envInput.oninput = () => {
if (!this.stages[index].config.Plan) this.stages[index].config = { Plan: { environment: "", auto_approve: false } };
this.stages[index].config.Plan.environment = envInput.value.trim();
this._sync();
};
envInput.onblur = () => {
this._blurTimer = setTimeout(() => this._render(), 150);
};
const autoLabel = el("label", "text-xs text-gray-500 flex items-center gap-1 ml-2 shrink-0");
const autoCheck = el("input", "");
autoCheck.type = "checkbox";
autoCheck.checked = !!(stage.config.Plan && stage.config.Plan.auto_approve);
autoCheck.onmousedown = (e) => e.stopPropagation();
autoCheck.onchange = () => {
if (!this.stages[index].config.Plan) this.stages[index].config = { Plan: { environment: "", auto_approve: false } };
this.stages[index].config.Plan.auto_approve = autoCheck.checked;
this._sync();
};
autoLabel.append(autoCheck, document.createTextNode("auto-approve"));
configRow.append(envLabel, envInput, autoLabel);
}
card.append(configRow);
@@ -568,6 +599,7 @@ class PipelineBuilder extends HTMLElement {
const TYPE_COLORS = {
deploy: { bg: "#dbeafe", border: "#93c5fd", text: "#1e40af" },
wait: { bg: "#fef3c7", border: "#fcd34d", text: "#92400e" },
plan: { bg: "#ede9fe", border: "#c4b5fd", text: "#5b21b6" },
};
for (const s of named) {