feat: feedback verbetering 05

This commit is contained in:
kodi
2026-03-15 15:30:55 +01:00
parent 61d0c8de41
commit ae6a9d8c45
13 changed files with 139 additions and 31 deletions
@@ -368,7 +368,7 @@ class UiSmokeGoldenTest(unittest.TestCase):
pollTimer: null,
lastRenderKey: "",
}};
const ACTIVE_TASK_OPERATIONS = new Set(["copy", "move", "duplicate", "delete"]);
const ACTIVE_OPERATION_OPERATIONS = new Set(["copy", "move", "duplicate"]);
const ACTIVE_TASK_STATUSES = new Set(["queued", "running", "cancelling"]);
{functions}
@@ -388,28 +388,28 @@ class UiSmokeGoldenTest(unittest.TestCase):
];
const activeTasks = activeTasksFromItems(mixedTasks);
assert(activeTasks.length === 5, "Only active task-based file actions should count as active");
assert(activeTasks.length === 4, "Only active user-visible operations should count as active");
assert(activeTasks.every((task) => isActiveTask(task)), "All filtered tasks should be active");
assert(activeTasks.some((task) => task.operation === "delete"), "Delete should count once it uses the shared task flow");
assert(!activeTasks.some((task) => task.operation === "delete"), "Delete should stay out of operation UI until it maps cleanly to one user-visible operation");
assert(activeTasks.some((task) => task.status === "cancelling"), "Cancelling tasks should remain visible while stopping");
assert(activeTaskChipLabel(activeTasks) === "5 active tasks", "Chip label should reflect active task count");
assert(activeTaskChipLabel(activeTasks) === "4 active operations", "Chip label should reflect active operation count");
updateHeaderTaskState(mixedTasks);
assert(!elements["header-task-chip-container"].classList.contains("hidden"), "Chip should be visible with active tasks");
assert(elements["header-task-chip-label"].textContent === "5 active tasks", "Chip label should render active task count");
assert(elements["header-task-chip-label"].textContent === "4 active operations", "Chip label should render active operation count");
assert(shouldPollHeaderTasks(), "Active tasks should enable header polling");
setHeaderTaskPopoverOpen(true);
assert(headerTaskState.popoverOpen, "Popover should open when active tasks exist");
assert(!elements["header-task-popover"].classList.contains("hidden"), "Popover should be visible when open");
assert(elements["header-task-chip-btn"].attributes["aria-expanded"] === "true", "Chip button should expose expanded state");
assert(elements["header-task-popover-list"].children.length === 5, "Popover should render only active file-action tasks");
assert(elements["header-task-popover-list"].children.length === 4, "Popover should render only active operations");
const moveRow = elements["header-task-popover-list"].children[1];
const moveProgress = moveRow.children[3];
const moveCurrent = moveRow.children[4];
assert(moveProgress.textContent === "1/3", "Popover should show done/total progress when available");
assert(moveCurrent.textContent === "b.mkv", "Popover should show compact current item");
const cancellingRow = elements["header-task-popover-list"].children[4];
const cancellingRow = elements["header-task-popover-list"].children[3];
const cancellingProgress = cancellingRow.children[3];
const cancellingCurrent = cancellingRow.children[4];
const cancellingSubtext = cancellingRow.children[5];
@@ -417,7 +417,7 @@ class UiSmokeGoldenTest(unittest.TestCase):
assert(cancellingCurrent.textContent === "nested/final-file.txt", "Cancelling tasks should show current item");
assert(cancellingSubtext.textContent === "Stopping after current item...", "Cancelling tasks should explain stop semantics");
const firstActionButton = elements["header-task-popover-list"].children[0].children[3].children[0];
const cancellingActionButton = elements["header-task-popover-list"].children[4].children[6].children[0];
const cancellingActionButton = elements["header-task-popover-list"].children[3].children[6].children[0];
assert(firstActionButton.textContent === "Stop", "Queued/running tasks should expose a Stop action");
assert(!firstActionButton.disabled, "Queued/running tasks should be cancellable");
assert(cancellingActionButton.textContent === "Stopping...", "Cancelling tasks should show stopping state");
@@ -582,7 +582,7 @@ class UiSmokeGoldenTest(unittest.TestCase):
pollTimer: null,
lastRenderKey: "",
}};
const ACTIVE_TASK_OPERATIONS = new Set(["copy", "move", "duplicate", "delete"]);
const ACTIVE_OPERATION_OPERATIONS = new Set(["copy", "move", "duplicate"]);
const ACTIVE_TASK_STATUSES = new Set(["queued", "running", "cancelling"]);
{functions}
@@ -905,6 +905,7 @@ class UiSmokeGoldenTest(unittest.TestCase):
def test_ui_static_assets_are_present_and_mapped(self) -> None:
mount = self._ui_mount()
static_root = Path(mount.app.directory)
index_html = (static_root / "index.html").read_text(encoding="utf-8")
self.assertTrue((static_root / "app.js").exists())
self.assertTrue((static_root / "base.css").exists())
self.assertTrue((static_root / "theme-default.css").exists())
@@ -964,9 +965,9 @@ class UiSmokeGoldenTest(unittest.TestCase):
self.assertIn('function inferDownloadTaskContext(task)', app_js)
self.assertIn('function formatTaskLine(task)', app_js)
self.assertIn('let headerTaskState = {', app_js)
self.assertIn('const ACTIVE_TASK_OPERATIONS = new Set(["copy", "move", "duplicate", "delete"]);', app_js)
self.assertIn('const ACTIVE_OPERATION_OPERATIONS = new Set(["copy", "move", "duplicate"]);', app_js)
self.assertIn('const ACTIVE_TASK_STATUSES = new Set(["queued", "running", "cancelling"]);', app_js)
self.assertIn("The header chip reflects only user-visible file actions that use the shared task system.", app_js)
self.assertIn("The header chip/popover reflects user-visible file operations, not every task-backed file action.", app_js)
self.assertIn('function headerTaskElements()', app_js)
self.assertIn('function isActiveTask(task)', app_js)
self.assertIn('function activeTasksFromItems(items)', app_js)
@@ -986,12 +987,12 @@ class UiSmokeGoldenTest(unittest.TestCase):
self.assertIn('function renderHeaderTaskChip(items)', app_js)
self.assertIn('function updateHeaderTaskState(taskItems)', app_js)
self.assertIn('function applyTaskSnapshot(taskItems)', app_js)
self.assertIn('return `${count} active task${count === 1 ? "" : "s"}`;', app_js)
self.assertIn('return `${count} active operation${count === 1 ? "" : "s"}`;', app_js)
self.assertIn('return task.operation === "copy" || task.operation === "duplicate";', app_js)
self.assertIn('return `${action} ${task.done_items}/${task.total_items}`;', app_js)
self.assertIn('return `${action} running`;', app_js)
self.assertIn('return "Stopping after current item...";', app_js)
self.assertIn('ACTIVE_TASK_OPERATIONS.has(task.operation)', app_js)
self.assertIn('ACTIVE_OPERATION_OPERATIONS.has(task.operation)', app_js)
self.assertIn('headerTaskState.activeItems = activeTasksFromItems(taskItems);', app_js)
self.assertIn('const open = Boolean(nextOpen) && headerTaskState.activeItems.length > 0;', app_js)
self.assertIn('const headerTasks = headerTaskElements();', app_js)
@@ -1135,6 +1136,8 @@ class UiSmokeGoldenTest(unittest.TestCase):
self.assertIn('destination_base: baseDestination,', app_js)
self.assertIn('setStatus("Copy: operation started");', app_js)
self.assertIn('setStatus("Move: operation started");', app_js)
self.assertIn('Active operations', index_html)
self.assertIn('No active operations right now.', app_js)
self.assertIn('const confirmed = await openConfirmModal({', app_js)
self.assertIn('title: selectedItems.length === 1 ? "Delete item?" : "Delete selected items?"', app_js)
self.assertIn('title: "Discard unsaved changes?"', app_js)