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

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) {