189 lines
7.1 KiB
JavaScript
189 lines
7.1 KiB
JavaScript
app.addEventListener("click", async (event) => {
|
|
const target = event.target.closest("[data-action]");
|
|
if (!target) return;
|
|
const action = target.dataset.action;
|
|
let repository = selectedRepository();
|
|
if (target.dataset.repositoryId) {
|
|
const actionRepository = ui.repositories.find(
|
|
(item) => String(item.id) === String(target.dataset.repositoryId),
|
|
);
|
|
if (actionRepository) repository = actionRepository;
|
|
}
|
|
|
|
const handlers = [handleShellActions, handleInventoryActions, handleDeploymentProfileActions, handleDeploymentOperationActions, handleSetupAndSettingsActions, handleRecoveryActions, handleCommandActions];
|
|
for (const handler of handlers) if (await handler(event, target, action, repository)) return;
|
|
});
|
|
|
|
app.addEventListener("input", (event) => {
|
|
if (event.target.id === "global-search") {
|
|
ui.search = event.target.value;
|
|
scheduleInputRender();
|
|
} else if (event.target.id === "repo-filter") {
|
|
ui.repoSearch = event.target.value;
|
|
scheduleInputRender();
|
|
} else if (event.target.id === "commit-message") {
|
|
ui.commitMessage = event.target.value;
|
|
const repository = selectedRepository();
|
|
const hasSelection = Boolean(ui.selectedFiles.size || repository?.localStatus?.counts?.staged);
|
|
const ready = Boolean(hasSelection && ui.commitMessage.trim());
|
|
const blocker = !hasSelection
|
|
? "Select files or stage one or more hunks."
|
|
: ready
|
|
? ui.selectedFiles.size
|
|
? "Ready to commit. ForgeFlow stages the selected files automatically."
|
|
: "Ready to commit only the reviewed staged hunks."
|
|
: "Enter a commit message to enable commit and push.";
|
|
const readiness = document.querySelector(".commit-readiness");
|
|
if (readiness) {
|
|
readiness.classList.toggle("ready", ready);
|
|
readiness.classList.toggle("blocked", !ready);
|
|
readiness.innerHTML = `${icon(ready ? "check" : "warning")}<span>${escapeHtml(blocker)}</span>`;
|
|
}
|
|
for (const button of document.querySelectorAll('[data-action="commit-push"], [data-action="commit-only"]')) {
|
|
button.disabled = !ready;
|
|
if (ready) button.removeAttribute("title");
|
|
else button.title = blocker;
|
|
}
|
|
} else if (event.target.id === "setup-url")
|
|
ui.setupDraft.baseUrl = event.target.value;
|
|
else if (event.target.id === "setup-token")
|
|
ui.setupDraft.token = event.target.value;
|
|
else if (event.target.id === "palette-input") {
|
|
ui.paletteQuery = event.target.value;
|
|
scheduleInputRender(60);
|
|
} else if (event.target.id === "help-search") {
|
|
ui.helpQuery = event.target.value;
|
|
scheduleInputRender(60);
|
|
}
|
|
});
|
|
|
|
app.addEventListener("change", async (event) => {
|
|
if (event.target.matches("[data-file-select]")) {
|
|
const filePath = event.target.dataset.fileSelect;
|
|
if (event.target.checked) ui.selectedFiles.add(filePath);
|
|
else ui.selectedFiles.delete(filePath);
|
|
render();
|
|
} else if (event.target.id === "appearance-select") {
|
|
ui.boot.state = await window.forgeflow.setAppearance(event.target.value);
|
|
applyTheme(event.target.value);
|
|
render();
|
|
} else if (event.target.id === "action-profile-select") {
|
|
ui.selectedProfileId = event.target.value;
|
|
render();
|
|
} else if (event.target.id === "validator-policy") {
|
|
await handleShellActions(event, event.target, "git-validator-policy", selectedRepository());
|
|
} else if (event.target.id === "profile-provider") {
|
|
ui.modal.provider = event.target.value;
|
|
render();
|
|
} else if (event.target.id === "server-auth-type") {
|
|
ui.modal.authType = event.target.value;
|
|
render();
|
|
}
|
|
});
|
|
|
|
document.addEventListener("keydown", (event) => {
|
|
if (
|
|
(event.key === "Enter" || event.key === " ") &&
|
|
event.target.matches('.file-row[data-action="select-file"]')
|
|
) {
|
|
event.preventDefault();
|
|
event.target.click();
|
|
return;
|
|
}
|
|
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "k") {
|
|
event.preventDefault();
|
|
ui.paletteQuery = "";
|
|
ui.modal = { type: "command-palette" };
|
|
render();
|
|
return;
|
|
}
|
|
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "f" && ui.currentView === "help") {
|
|
event.preventDefault();
|
|
document.querySelector("#help-search")?.focus();
|
|
return;
|
|
}
|
|
if (
|
|
(event.ctrlKey || event.metaKey) &&
|
|
event.key === "Enter" &&
|
|
ui.currentView === "repository"
|
|
) {
|
|
const button = document.querySelector(
|
|
'[data-action="commit-push"]:not(:disabled)',
|
|
);
|
|
if (button) button.click();
|
|
}
|
|
if (event.key === "F5") {
|
|
event.preventDefault();
|
|
refreshRepositories(true);
|
|
}
|
|
if (event.key === "Escape" && ui.modal) {
|
|
ui.modal = null;
|
|
render();
|
|
}
|
|
});
|
|
|
|
let pointerAnimationFrame = null;
|
|
let pendingPointer = null;
|
|
|
|
document.addEventListener("pointermove", (event) => {
|
|
pendingPointer = { target: event.target, clientX: event.clientX, clientY: event.clientY };
|
|
if (pointerAnimationFrame) return;
|
|
pointerAnimationFrame = requestAnimationFrame(() => {
|
|
pointerAnimationFrame = null;
|
|
const current = pendingPointer;
|
|
pendingPointer = null;
|
|
if (!current) return;
|
|
const illustration = current.target.closest?.("[data-project-illustration]");
|
|
if (illustration) {
|
|
const bounds = illustration.getBoundingClientRect();
|
|
illustration.style.setProperty("--tilt-x", `${((current.clientY - bounds.top) / bounds.height - 0.5) * -7}deg`);
|
|
illustration.style.setProperty("--tilt-y", `${((current.clientX - bounds.left) / bounds.width - 0.5) * 9}deg`);
|
|
}
|
|
const diffPanel = current.target.closest?.(".diff-panel");
|
|
const atmosphere = diffPanel?.querySelector("[data-diff-atmosphere]");
|
|
if (atmosphere) {
|
|
const bounds = diffPanel.getBoundingClientRect();
|
|
atmosphere.style.setProperty("--diff-tilt-x", `${((current.clientY - bounds.top) / bounds.height - 0.5) * -3}deg`);
|
|
atmosphere.style.setProperty("--diff-tilt-y", `${((current.clientX - bounds.left) / bounds.width - 0.5) * 4}deg`);
|
|
}
|
|
});
|
|
});
|
|
document.addEventListener("pointerout", (event) => {
|
|
const illustration = event.target.closest?.("[data-project-illustration]");
|
|
if (illustration && !illustration.contains(event.relatedTarget)) {
|
|
illustration.style.removeProperty("--tilt-x");
|
|
illustration.style.removeProperty("--tilt-y");
|
|
}
|
|
|
|
const diffPanel = event.target.closest?.(".diff-panel");
|
|
if (diffPanel && !diffPanel.contains(event.relatedTarget)) {
|
|
const atmosphere = diffPanel.querySelector("[data-diff-atmosphere]");
|
|
atmosphere?.style.removeProperty("--diff-tilt-x");
|
|
atmosphere?.style.removeProperty("--diff-tilt-y");
|
|
}
|
|
});
|
|
|
|
window.addEventListener("error", (event) => {
|
|
window.forgeflow
|
|
.reportRendererEvent?.("error", "uncaught-error", {
|
|
message: event.message,
|
|
filename: event.filename,
|
|
line: event.lineno,
|
|
column: event.colno,
|
|
stack: event.error?.stack,
|
|
})
|
|
.catch(() => {});
|
|
});
|
|
|
|
window.addEventListener("unhandledrejection", (event) => {
|
|
const reason = event.reason;
|
|
window.forgeflow
|
|
.reportRendererEvent?.("error", "unhandled-rejection", {
|
|
message: reason?.message || String(reason || "Unknown rejection"),
|
|
stack: reason?.stack,
|
|
})
|
|
.catch(() => {});
|
|
});
|
|
|
|
bootstrap();
|