fix(ui): keep manifest options available in run trigger
This commit is contained in:
@@ -117,6 +117,9 @@ const MANIFEST_EVENT_TRIGGERS = [
|
|||||||
"branch_merged",
|
"branch_merged",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const RUN_MANIFEST_EDITOR_VALUE = "__editor__";
|
||||||
|
const RUN_MANIFEST_EDITOR_LABEL = "[Use Manifest Editor JSON]";
|
||||||
|
|
||||||
function fmtMoney(value) {
|
function fmtMoney(value) {
|
||||||
return `$${Number(value || 0).toFixed(4)}`;
|
return `$${Number(value || 0).toFixed(4)}`;
|
||||||
}
|
}
|
||||||
@@ -838,6 +841,26 @@ function parseJsonSafe(text, fallback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dedupeNonEmptyStrings(values) {
|
||||||
|
const output = [];
|
||||||
|
const seen = new Set();
|
||||||
|
|
||||||
|
for (const value of values) {
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = value.trim();
|
||||||
|
if (!normalized || seen.has(normalized)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seen.add(normalized);
|
||||||
|
output.push(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
function populateSelect(select, values, selectedValue) {
|
function populateSelect(select, values, selectedValue) {
|
||||||
const previous = selectedValue || select.value;
|
const previous = selectedValue || select.value;
|
||||||
select.innerHTML = "";
|
select.innerHTML = "";
|
||||||
@@ -857,6 +880,35 @@ function populateSelect(select, values, selectedValue) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function populateRunManifestSelect(values, selectedValue) {
|
||||||
|
const previous = selectedValue || dom.runManifestSelect.value;
|
||||||
|
dom.runManifestSelect.innerHTML = "";
|
||||||
|
|
||||||
|
const editorOption = document.createElement("option");
|
||||||
|
editorOption.value = RUN_MANIFEST_EDITOR_VALUE;
|
||||||
|
editorOption.textContent = RUN_MANIFEST_EDITOR_LABEL;
|
||||||
|
dom.runManifestSelect.append(editorOption);
|
||||||
|
|
||||||
|
for (const value of values) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = value;
|
||||||
|
option.textContent = value;
|
||||||
|
dom.runManifestSelect.append(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previous && [...dom.runManifestSelect.options].some((option) => option.value === previous)) {
|
||||||
|
dom.runManifestSelect.value = previous;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.selectedManifestPath && values.includes(state.selectedManifestPath)) {
|
||||||
|
dom.runManifestSelect.value = state.selectedManifestPath;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dom.runManifestSelect.value = RUN_MANIFEST_EDITOR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
async function loadConfig() {
|
async function loadConfig() {
|
||||||
const payload = await apiRequest("/api/config");
|
const payload = await apiRequest("/api/config");
|
||||||
state.config = payload.config;
|
state.config = payload.config;
|
||||||
@@ -888,14 +940,19 @@ async function loadConfig() {
|
|||||||
|
|
||||||
async function loadManifests() {
|
async function loadManifests() {
|
||||||
const payload = await apiRequest("/api/manifests");
|
const payload = await apiRequest("/api/manifests");
|
||||||
state.manifests = payload.manifests;
|
const manifests = dedupeNonEmptyStrings([
|
||||||
|
...(Array.isArray(payload.manifests) ? payload.manifests : []),
|
||||||
|
state.selectedManifestPath,
|
||||||
|
dom.manifestPath.value,
|
||||||
|
]);
|
||||||
|
state.manifests = manifests;
|
||||||
|
|
||||||
if (!state.selectedManifestPath && state.manifests.length > 0) {
|
if (!state.selectedManifestPath && state.manifests.length > 0) {
|
||||||
state.selectedManifestPath = state.manifests[0];
|
state.selectedManifestPath = state.manifests[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
populateSelect(dom.graphManifestSelect, state.manifests, state.selectedManifestPath);
|
populateSelect(dom.graphManifestSelect, state.manifests, state.selectedManifestPath);
|
||||||
populateSelect(dom.runManifestSelect, state.manifests, state.selectedManifestPath);
|
populateRunManifestSelect(state.manifests, state.selectedManifestPath);
|
||||||
|
|
||||||
if (state.selectedManifestPath) {
|
if (state.selectedManifestPath) {
|
||||||
dom.manifestPath.value = state.selectedManifestPath;
|
dom.manifestPath.value = state.selectedManifestPath;
|
||||||
@@ -1332,9 +1389,10 @@ async function startRun(event) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const manifestSelection = dom.runManifestSelect.value.trim();
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
prompt,
|
prompt,
|
||||||
manifestPath: dom.runManifestSelect.value,
|
|
||||||
executionMode: dom.runExecutionMode.value,
|
executionMode: dom.runExecutionMode.value,
|
||||||
provider: dom.runProvider.value,
|
provider: dom.runProvider.value,
|
||||||
topologyHint: dom.runTopologyHint.value.trim() || undefined,
|
topologyHint: dom.runTopologyHint.value.trim() || undefined,
|
||||||
@@ -1342,6 +1400,20 @@ async function startRun(event) {
|
|||||||
simulateValidationNodeIds: fromCsv(dom.runValidationNodes.value),
|
simulateValidationNodeIds: fromCsv(dom.runValidationNodes.value),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (manifestSelection === RUN_MANIFEST_EDITOR_VALUE) {
|
||||||
|
const manifestFromEditor = parseJsonSafe(dom.manifestEditor.value, null);
|
||||||
|
if (!manifestFromEditor) {
|
||||||
|
showRunStatus("Manifest editor JSON is invalid. Save or fix it before running.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
payload.manifest = manifestFromEditor;
|
||||||
|
} else if (manifestSelection) {
|
||||||
|
payload.manifestPath = manifestSelection;
|
||||||
|
} else {
|
||||||
|
showRunStatus("Select a manifest path or choose editor JSON.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await apiRequest("/api/runs", {
|
const response = await apiRequest("/api/runs", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -1458,7 +1530,7 @@ async function loadManifestEditor() {
|
|||||||
dom.manifestPath.value = payload.manifest.path;
|
dom.manifestPath.value = payload.manifest.path;
|
||||||
state.selectedManifestPath = payload.manifest.path;
|
state.selectedManifestPath = payload.manifest.path;
|
||||||
populateSelect(dom.graphManifestSelect, state.manifests, state.selectedManifestPath);
|
populateSelect(dom.graphManifestSelect, state.manifests, state.selectedManifestPath);
|
||||||
populateSelect(dom.runManifestSelect, state.manifests, state.selectedManifestPath);
|
populateRunManifestSelect(state.manifests, state.selectedManifestPath);
|
||||||
setManifestStatus(`Loaded ${payload.manifest.path}.`);
|
setManifestStatus(`Loaded ${payload.manifest.path}.`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setManifestStatus(error instanceof Error ? error.message : String(error), true);
|
setManifestStatus(error instanceof Error ? error.message : String(error), true);
|
||||||
@@ -1511,7 +1583,9 @@ async function saveManifest(event) {
|
|||||||
renderManifestHelper();
|
renderManifestHelper();
|
||||||
await loadManifests();
|
await loadManifests();
|
||||||
dom.graphManifestSelect.value = state.selectedManifestPath;
|
dom.graphManifestSelect.value = state.selectedManifestPath;
|
||||||
|
if ([...dom.runManifestSelect.options].some((option) => option.value === state.selectedManifestPath)) {
|
||||||
dom.runManifestSelect.value = state.selectedManifestPath;
|
dom.runManifestSelect.value = state.selectedManifestPath;
|
||||||
|
}
|
||||||
setManifestStatus(`Saved ${payload.manifest.path}.`);
|
setManifestStatus(`Saved ${payload.manifest.path}.`);
|
||||||
await refreshGraph();
|
await refreshGraph();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1528,7 +1602,9 @@ function bindUiEvents() {
|
|||||||
|
|
||||||
dom.graphManifestSelect.addEventListener("change", async () => {
|
dom.graphManifestSelect.addEventListener("change", async () => {
|
||||||
state.selectedManifestPath = dom.graphManifestSelect.value;
|
state.selectedManifestPath = dom.graphManifestSelect.value;
|
||||||
|
if ([...dom.runManifestSelect.options].some((option) => option.value === state.selectedManifestPath)) {
|
||||||
dom.runManifestSelect.value = state.selectedManifestPath;
|
dom.runManifestSelect.value = state.selectedManifestPath;
|
||||||
|
}
|
||||||
dom.manifestPath.value = state.selectedManifestPath;
|
dom.manifestPath.value = state.selectedManifestPath;
|
||||||
await refreshGraph();
|
await refreshGraph();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user