refactor: split renderer ipc and unraid domains
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
async function handleInventoryActions(event, target, action, repository) {
|
||||
if (action === "scan-server-inventory") {
|
||||
setLoading(true, "Scanning Docker, Compose and DockerMan workloads…");
|
||||
try {
|
||||
await refreshDeploymentTruth(true);
|
||||
const detected = (ui.serverDiscovery || []).reduce(
|
||||
(total, item) => total + Number(item.detected || 0),
|
||||
0,
|
||||
);
|
||||
const review = (ui.serverDiscovery || []).reduce(
|
||||
(total, item) => total + Number(item.needsReview || 0),
|
||||
0,
|
||||
);
|
||||
const failures = (ui.serverDiscovery || []).filter((item) => item.error);
|
||||
if (failures.length) {
|
||||
showToast(
|
||||
"Server scan failed",
|
||||
failures.map((item) => `${item.serverName || item.serverId}: ${item.error}`).join(" · "),
|
||||
"error",
|
||||
);
|
||||
} else {
|
||||
showToast(
|
||||
"Server inventory updated",
|
||||
`${detected} workload${detected === 1 ? "" : "s"} detected; ${review} require manual review.`,
|
||||
review ? "info" : "success",
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
showToast("Server scan failed", error.message, "error");
|
||||
}
|
||||
setLoading(false);
|
||||
} else if (action === "plan-server-reconciliation") {
|
||||
setLoading(true, "Building a read-only reconciliation preview…");
|
||||
try {
|
||||
const result = await window.forgeflow.planServerReconciliation(target.dataset.serverId);
|
||||
ui.modal = { type: "server-reconciliation-plan", result };
|
||||
render();
|
||||
} catch (error) {
|
||||
showToast("Could not build reconciliation plan", error.message, "error");
|
||||
}
|
||||
setLoading(false);
|
||||
} else if (action === "apply-server-reconciliation") {
|
||||
setLoading(true, "Applying the reviewed configuration plan…");
|
||||
try {
|
||||
const result = await window.forgeflow.applyServerReconciliation(target.dataset.serverId, target.dataset.planId);
|
||||
if (result.state) ui.boot.state = result.state;
|
||||
ui.modal = null;
|
||||
await refreshRepositories(false, true);
|
||||
await refreshDeploymentTruth(false);
|
||||
showToast("Reconciliation applied", `${result.adopted || 0} link(s) added and ${result.refreshed || 0} profile(s) refreshed. No containers were changed.`, "success");
|
||||
} catch (error) {
|
||||
showToast("Reconciliation was not applied", error.message, "error");
|
||||
}
|
||||
setLoading(false);
|
||||
} else if (action === "quick-link-server-workload") {
|
||||
const serverResult = (ui.serverDiscovery || []).find(
|
||||
(item) => item.serverId === target.dataset.serverId,
|
||||
);
|
||||
const workload = serverResult?.workloads?.find(
|
||||
(item) => item.workloadId === target.dataset.workloadId,
|
||||
);
|
||||
const linkedRepository = ui.repositories.find(
|
||||
(item) => item.fullName === target.dataset.repository,
|
||||
);
|
||||
if (!workload || !linkedRepository || !workload.remoteFolderCandidate) {
|
||||
showToast("Automatic link unavailable", "Scan the server again and use Review & link.", "error");
|
||||
return;
|
||||
}
|
||||
setLoading(true, `Linking ${workload.displayName} to ${linkedRepository.fullName}…`);
|
||||
try {
|
||||
const result = await window.forgeflow.linkServerWorkload(
|
||||
linkedRepository,
|
||||
target.dataset.serverId,
|
||||
target.dataset.workloadId,
|
||||
"server-git",
|
||||
workload.remoteFolderCandidate,
|
||||
);
|
||||
if (result.state) ui.boot.state = result.state;
|
||||
ui.selectedProfileId = result.profile?.id || null;
|
||||
await refreshRepositories(false, true);
|
||||
await refreshDeploymentTruth(false);
|
||||
showToast(
|
||||
"Deployment linked",
|
||||
`${linkedRepository.fullName} is linked to ${workload.compose?.workingDir || workload.remoteFolderCandidate}. Compose values were read from the server.`,
|
||||
"success",
|
||||
);
|
||||
} catch (error) {
|
||||
showToast("Could not link deployment", error.message, "error");
|
||||
}
|
||||
setLoading(false);
|
||||
} else if (action === "preview-inventory-review") {
|
||||
const reviewAction = document.querySelector("#inventory-review-action")?.value || "ignore";
|
||||
const reason = document.querySelector("#inventory-review-reason")?.value.trim() || "";
|
||||
const serverId = target.dataset.serverId;
|
||||
const workloadId = target.dataset.workloadId;
|
||||
try {
|
||||
ui.inventoryReviewPlan = await window.forgeflow.planInventoryReview(serverId, workloadId, reviewAction, reason, document.querySelector("#workload-repository")?.value || null);
|
||||
ui.modal = { type: "inventory-review-plan" };
|
||||
render();
|
||||
} catch (error) { showToast("Review preview unavailable", error.message, "error"); }
|
||||
} else if (action === "apply-inventory-review") {
|
||||
const plan = ui.inventoryReviewPlan;
|
||||
if (!plan?.id) return;
|
||||
setLoading(true, "Saving the evidence-bound inventory decision…");
|
||||
try {
|
||||
const result = await window.forgeflow.applyInventoryReview(plan.serverId, plan.workloadId, plan.action, plan.reason, plan.repositoryFullName, plan.id);
|
||||
if (result.state) ui.boot.state = result.state;
|
||||
ui.serverDiscovery = (ui.serverDiscovery || []).map((item) => item.serverId === plan.serverId ? result.inventory : item);
|
||||
ui.inventoryReviewPlan = null; ui.modal = null; render();
|
||||
showToast("Inventory decision saved", "Containers and Compose runtime were not changed.", "success");
|
||||
} catch (error) { showToast("Inventory review failed safely", error.message, "error"); }
|
||||
finally { setLoading(false); }
|
||||
} else if (action === "link-server-workload") {
|
||||
const serverResult = (ui.serverDiscovery || []).find(
|
||||
(item) => item.serverId === target.dataset.serverId,
|
||||
);
|
||||
const workload = serverResult?.workloads?.find(
|
||||
(item) => item.workloadId === target.dataset.workloadId,
|
||||
);
|
||||
if (!workload) {
|
||||
showToast(
|
||||
"Workload unavailable",
|
||||
"Scan the server inventory again before linking this workload.",
|
||||
"error",
|
||||
);
|
||||
return;
|
||||
}
|
||||
ui.modal = {
|
||||
type: "workload-link",
|
||||
serverId: target.dataset.serverId,
|
||||
workloadId: target.dataset.workloadId,
|
||||
repositoryFullName:
|
||||
workload.candidates?.[0]?.repositoryFullName ||
|
||||
repository?.fullName ||
|
||||
ui.repositories[0]?.fullName ||
|
||||
"",
|
||||
remoteFolder: workload.remoteFolderCandidate || "",
|
||||
};
|
||||
render();
|
||||
} else if (action === "confirm-link-server-workload") {
|
||||
const repositoryFullName = document
|
||||
.querySelector("#workload-repository")
|
||||
?.value.trim();
|
||||
const deploymentMode = document.querySelector("#workload-deployment-mode")?.value || "server-git";
|
||||
const remoteFolder = document
|
||||
.querySelector("#workload-remote-folder")
|
||||
?.value.trim();
|
||||
const linkedRepository = ui.repositories.find(
|
||||
(item) => item.fullName === repositoryFullName,
|
||||
);
|
||||
if (!linkedRepository) {
|
||||
showToast(
|
||||
"Choose a repository",
|
||||
"The workload must be linked to a ForgeFlow project.",
|
||||
"error",
|
||||
);
|
||||
return;
|
||||
}
|
||||
setLoading(true, "Saving the permanent server workload link…");
|
||||
try {
|
||||
const result = await window.forgeflow.linkServerWorkload(
|
||||
linkedRepository,
|
||||
target.dataset.serverId,
|
||||
target.dataset.workloadId,
|
||||
deploymentMode,
|
||||
remoteFolder,
|
||||
);
|
||||
if (result.state) ui.boot.state = result.state;
|
||||
ui.modal = null;
|
||||
ui.selectedProfileId = result.profile?.id || null;
|
||||
await refreshRepositories(false, true);
|
||||
await refreshDeploymentTruth(false);
|
||||
showToast(
|
||||
"Workload linked",
|
||||
`${linkedRepository.fullName} now uses direct desktop-to-Unraid copy and the Compose configuration detected on the server.`,
|
||||
"success",
|
||||
);
|
||||
} catch (error) {
|
||||
showToast("Could not link workload", error.message, "error");
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user