Some checks failed
test / test (push) Failing after 24s
Реализация целевого дизайна (docs/architecture/target-design.md): - src/: модульная структура (config, logger, errors, http, core: auth/history/jobs/engines/comfy/codex/images) - Очередь заданий: FIFO, кониурентность codex=1 / comfy-upscale=2, MAX_QUEUED_JOBS=5, JSONL-журнал и восстановление после рестарта (running → interrupted, upscale requeue) - Персистентные сессии (sha256-хеши токенов), scrypt-хеш пароля, rate-limit входа, Origin-проверка, magic-byte валидация аплоадов - Атомарная запись манифеста истории, каскадное удаление, URL с фактическим расширением + 302-алиас /image.jpg, миграция history/ → data/history - Даунскейл sharp до 1024px перед Codex + масштабирование области референса - SSE /api/events с фолбэком на polling, фронтенд переведён на ES-модули (public/js/) - Тесты node:test + supertest (27), CI workflow test.yml, Docker/деплой: том kadr-data - Документация: README, docs/architecture/
78 lines
2.3 KiB
JavaScript
78 lines
2.3 KiB
JavaScript
/**
|
|
* main.js — Главная точка входа клиентского приложения «Кадр» v2
|
|
*/
|
|
|
|
import { checkAuth, submitLogin, logout } from "./auth.js";
|
|
import { startHealthPolling } from "./health.js";
|
|
import { initUpload } from "./upload.js";
|
|
import { initReference } from "./reference.js";
|
|
import { initSuggest } from "./suggest.js";
|
|
import { initJobsEvents, runJob } from "./jobs.js";
|
|
import { refreshHistory } from "./history-tree.js";
|
|
import { subscribe, getState } from "./state.js";
|
|
|
|
function setupButtonsAndInputs() {
|
|
const loginForm = document.querySelector("#login-form");
|
|
const logoutBtn = document.querySelector("#logout-button");
|
|
const editBtn = document.querySelector("#edit-button");
|
|
const upscaleBtn = document.querySelector("#upscale-button");
|
|
const promptInput = document.querySelector("#prompt");
|
|
const promptCounter = document.querySelector("#prompt-counter");
|
|
|
|
if (loginForm) {
|
|
loginForm.addEventListener("submit", submitLogin);
|
|
}
|
|
|
|
if (logoutBtn) {
|
|
logoutBtn.addEventListener("click", logout);
|
|
}
|
|
|
|
if (promptInput) {
|
|
promptInput.addEventListener("input", () => {
|
|
const val = promptInput.value;
|
|
if (promptCounter) {
|
|
promptCounter.textContent = `${val.length} / 1000`;
|
|
}
|
|
const state = getState();
|
|
if (editBtn) {
|
|
editBtn.disabled = !state.currentVersionId || !val.trim() || state.isBusy;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (editBtn) {
|
|
editBtn.addEventListener("click", () => runJob("edit"));
|
|
}
|
|
|
|
if (upscaleBtn) {
|
|
upscaleBtn.addEventListener("click", () => runJob("upscale"));
|
|
}
|
|
|
|
// Subscribe to state changes to update button states
|
|
subscribe((state, changeKey) => {
|
|
if (changeKey === "isBusy" || changeKey === "currentVersionId") {
|
|
const hasVersion = Boolean(state.currentVersionId);
|
|
const promptVal = promptInput?.value?.trim() || "";
|
|
|
|
if (upscaleBtn) upscaleBtn.disabled = !hasVersion || state.isBusy;
|
|
if (editBtn) editBtn.disabled = !hasVersion || !promptVal || state.isBusy;
|
|
}
|
|
});
|
|
}
|
|
|
|
async function init() {
|
|
setupButtonsAndInputs();
|
|
initUpload();
|
|
initReference();
|
|
initSuggest();
|
|
startHealthPolling();
|
|
|
|
const authenticated = await checkAuth();
|
|
if (authenticated) {
|
|
initJobsEvents();
|
|
await refreshHistory(true);
|
|
}
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", init);
|