refactor: split renderer ipc and unraid domains
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
async function runOperation(
|
||||
message,
|
||||
operation,
|
||||
successMessage,
|
||||
{ refresh = true } = {},
|
||||
) {
|
||||
setLoading(true, message);
|
||||
try {
|
||||
const result = await operation();
|
||||
if (successMessage) showToast("Done", successMessage, "success");
|
||||
if (refresh) await refreshRepositories(false);
|
||||
return result;
|
||||
} catch (error) {
|
||||
const pushAfterCommit = error.code === "PUSH_AFTER_COMMIT_FAILED";
|
||||
showToast(
|
||||
pushAfterCommit
|
||||
? "Commit saved locally; push failed"
|
||||
: "Operation failed",
|
||||
error.message,
|
||||
"error",
|
||||
);
|
||||
// Always reload the real Git state. A failed stage must keep changes visible, while a
|
||||
// failed push after a successful commit must immediately surface as an ahead branch.
|
||||
await refreshRepositories(false, true);
|
||||
if (pushAfterCommit) {
|
||||
ui.selectedFiles.clear();
|
||||
ui.selectedFile = null;
|
||||
ui.diff = "";
|
||||
ui.commitMessage = "";
|
||||
render();
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function executeDeployment(profileId) {
|
||||
const repository = selectedRepository();
|
||||
const profile =
|
||||
repository?.deploymentProfiles?.find((item) => item.id === profileId) ||
|
||||
selectedProfile(repository);
|
||||
if (!repository || !profile) return;
|
||||
const targetSha = deploymentTargetSha(repository, profile);
|
||||
if (!targetSha) {
|
||||
showToast("Refresh required", "Refresh Gitea and server truth before deploying this environment.", "error");
|
||||
return;
|
||||
}
|
||||
const deploymentOptions = {
|
||||
note: document.querySelector("#deployment-note")?.value.trim() || "",
|
||||
override: document.querySelector("#deployment-override")?.checked === true,
|
||||
overrideReason:
|
||||
document.querySelector("#deployment-override-reason")?.value.trim() || "",
|
||||
};
|
||||
ui.modal = null;
|
||||
setLoading(
|
||||
true,
|
||||
profile.provider === "ssh-unraid"
|
||||
? `Deploying ${repository.name} to ${profile.remoteFolder} over SSH…`
|
||||
: `Dispatching ${profile.name} workflow…`,
|
||||
);
|
||||
try {
|
||||
ui.activeDeployment = await window.forgeflow.deploy(
|
||||
repository,
|
||||
profile.id,
|
||||
targetSha,
|
||||
deploymentOptions,
|
||||
);
|
||||
updateOperationInState(ui.activeDeployment);
|
||||
ui.currentView = "deployment-run";
|
||||
showToast(
|
||||
"Deployment started",
|
||||
`${repository.name} ${shortSha(targetSha)} → ${profile.environment}`,
|
||||
"success",
|
||||
);
|
||||
startOperationPolling();
|
||||
} catch (error) {
|
||||
if (profile.provider === "ssh-unraid" && isSshCredentialError(error)) {
|
||||
ui.modal = {
|
||||
type: "server-password",
|
||||
serverId: profile.serverId,
|
||||
retry: {
|
||||
type: "deploy",
|
||||
repositoryFullName: repository.fullName,
|
||||
profileId: profile.id,
|
||||
},
|
||||
};
|
||||
showToast("SSH key rejected", "Enter the Unraid server password once; ForgeFlow will retry the direct desktop → Unraid connection.", "error");
|
||||
render();
|
||||
} else {
|
||||
showToast("Deployment failed to start", error.message, "error");
|
||||
}
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
async function executeRollback(profileId) {
|
||||
const repository = selectedRepository();
|
||||
const profile = repository?.deploymentProfiles?.find(
|
||||
(item) => item.id === profileId,
|
||||
);
|
||||
const target = profile?.state?.previousSha;
|
||||
if (!repository || !profile || !target) return;
|
||||
ui.modal = null;
|
||||
setLoading(
|
||||
true,
|
||||
profile?.provider === "ssh-unraid"
|
||||
? `Rolling back ${profile.remoteFolder} over SSH…`
|
||||
: `Dispatching rollback to ${shortSha(target)}…`,
|
||||
);
|
||||
try {
|
||||
ui.activeDeployment = await window.forgeflow.rollback(
|
||||
repository,
|
||||
profile.id,
|
||||
target,
|
||||
);
|
||||
updateOperationInState(ui.activeDeployment);
|
||||
ui.currentView = "deployment-run";
|
||||
showToast(
|
||||
"Rollback requested",
|
||||
`${profile.environment} → ${shortSha(target)}`,
|
||||
"success",
|
||||
);
|
||||
} catch (error) {
|
||||
showToast("Rollback failed to start", error.message, "error");
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
async function loadGitTools(repository) {
|
||||
if (!repository?.localPath) return;
|
||||
setLoading(true, "Loading branches and stashes…");
|
||||
try {
|
||||
[ui.branches, ui.stashes, ui.gitRecovery] = await Promise.all([
|
||||
window.forgeflow.branches(repository.localPath),
|
||||
window.forgeflow.stashList(repository.localPath),
|
||||
window.forgeflow.gitRecoveryStatus(repository.localPath),
|
||||
]);
|
||||
ui.repositoryTab = "gittools";
|
||||
} catch (error) {
|
||||
showToast("Git tools unavailable", error.message, "error");
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
function profileRepository(profileId) {
|
||||
return ui.repositories.find((repository) =>
|
||||
repository.deploymentProfiles?.some((profile) => profile.id === profileId),
|
||||
);
|
||||
}
|
||||
|
||||
async function runSystemPreflight({ setup = false } = {}) {
|
||||
setLoading(true, "Checking local readiness…");
|
||||
try {
|
||||
ui.systemPreflight = await window.forgeflow.setupPreflight({
|
||||
baseUrl: ui.setupDraft.baseUrl,
|
||||
token: ui.setupDraft.token,
|
||||
roots: setup ? ui.setupDraft.roots : ui.boot.state.workspaceRoots,
|
||||
});
|
||||
if (!setup)
|
||||
ui.diagnosticsStatus = await window.forgeflow.diagnosticsStatus();
|
||||
showToast(
|
||||
ui.systemPreflight.summary.ready
|
||||
? "Readiness checks passed"
|
||||
: "Readiness needs attention",
|
||||
ui.systemPreflight.summary.ready
|
||||
? `${ui.systemPreflight.summary.counts.pass} checks passed.`
|
||||
: `${ui.systemPreflight.summary.blocking.length} blocking check(s) must be resolved.`,
|
||||
ui.systemPreflight.summary.ready ? "success" : "error",
|
||||
);
|
||||
return ui.systemPreflight;
|
||||
} catch (error) {
|
||||
showToast("Readiness check failed", error.message, "error");
|
||||
return null;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function runDeploymentPreflight(
|
||||
repository,
|
||||
profileId,
|
||||
{ showModal = true } = {},
|
||||
) {
|
||||
if (!repository || !profileId) return null;
|
||||
if (String(repository.id) !== String(ui.selectedRepoId))
|
||||
selectRepository(repository.id, false);
|
||||
ui.selectedProfileId = profileId;
|
||||
ui.deploymentPreflight = null;
|
||||
setLoading(true, "Verifying repository, workflow and server…");
|
||||
try {
|
||||
const report = await window.forgeflow.deploymentPreflight(
|
||||
repository,
|
||||
profileId,
|
||||
);
|
||||
ui.deploymentPreflight = report;
|
||||
if (showModal)
|
||||
ui.modal = {
|
||||
type: "deployment-preflight",
|
||||
profileId,
|
||||
repositoryFullName: repository.fullName,
|
||||
};
|
||||
return report;
|
||||
} catch (error) {
|
||||
showToast("Deployment preflight failed", error.message, "error");
|
||||
return null;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user