feat (ui): selecteer meerdere bestanden tegelijkertijd
This commit is contained in:
+53
-9
@@ -17,6 +17,7 @@
|
||||
modalKnownFiles: {},
|
||||
modalFileFilter: "",
|
||||
modalVisibleFiles: [],
|
||||
modalSelectionAnchorPath: null,
|
||||
syncScrolling: false,
|
||||
settings: {
|
||||
set_file_date_to_first_aired_date: false,
|
||||
@@ -755,6 +756,7 @@
|
||||
};
|
||||
});
|
||||
state.modalFileFilter = "";
|
||||
state.modalSelectionAnchorPath = null;
|
||||
el.fileModalTitle.textContent = "File Discovery";
|
||||
el.modalAddSelectedFilesBtn.style.display = "";
|
||||
if (el.modalFileFilterInput) {
|
||||
@@ -819,22 +821,62 @@
|
||||
|
||||
const isSelected = state.modalSelectedFilePaths.has(file.path);
|
||||
if (isSelected) li.classList.add("selected");
|
||||
|
||||
li.addEventListener("click", () => {
|
||||
if (state.modalSelectedFilePaths.has(file.path)) {
|
||||
state.modalSelectedFilePaths.delete(file.path);
|
||||
li.classList.remove("selected");
|
||||
} else {
|
||||
state.modalSelectedFilePaths.add(file.path);
|
||||
li.classList.add("selected");
|
||||
if (state.modalSelectionAnchorPath && state.modalSelectionAnchorPath === file.path) {
|
||||
li.classList.add("modal-anchor");
|
||||
}
|
||||
updateModalSelectionCount();
|
||||
|
||||
li.addEventListener("click", (event) => {
|
||||
handleModalFileRowClick(file.path, event);
|
||||
});
|
||||
el.modalFilesList.appendChild(li);
|
||||
});
|
||||
updateModalSelectionCount();
|
||||
}
|
||||
|
||||
function handleModalFileRowClick(path, event) {
|
||||
const clickedPath = (path || "").toString().trim();
|
||||
if (!clickedPath) return;
|
||||
|
||||
const visiblePaths = (state.modalVisibleFiles || [])
|
||||
.map((f) => (f && f.path ? f.path : ""))
|
||||
.filter((p) => p);
|
||||
const isShift = !!(event && event.shiftKey);
|
||||
const isToggle = !!(event && (event.ctrlKey || event.metaKey));
|
||||
|
||||
if (isShift) {
|
||||
const anchor = state.modalSelectionAnchorPath || "";
|
||||
const from = visiblePaths.indexOf(anchor);
|
||||
const to = visiblePaths.indexOf(clickedPath);
|
||||
if (from >= 0 && to >= 0) {
|
||||
const start = Math.min(from, to);
|
||||
const end = Math.max(from, to);
|
||||
const rangePaths = visiblePaths.slice(start, end + 1);
|
||||
state.modalSelectedFilePaths = new Set(rangePaths);
|
||||
} else {
|
||||
// Fallback: no valid anchor in current visible list.
|
||||
state.modalSelectedFilePaths = new Set([clickedPath]);
|
||||
}
|
||||
state.modalSelectionAnchorPath = clickedPath;
|
||||
renderModalFiles();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isToggle) {
|
||||
if (state.modalSelectedFilePaths.has(clickedPath)) {
|
||||
state.modalSelectedFilePaths.delete(clickedPath);
|
||||
} else {
|
||||
state.modalSelectedFilePaths.add(clickedPath);
|
||||
}
|
||||
state.modalSelectionAnchorPath = clickedPath;
|
||||
renderModalFiles();
|
||||
return;
|
||||
}
|
||||
|
||||
state.modalSelectedFilePaths = new Set([clickedPath]);
|
||||
state.modalSelectionAnchorPath = clickedPath;
|
||||
renderModalFiles();
|
||||
}
|
||||
|
||||
async function loadModalFiles(subpath) {
|
||||
const rootId = el.modalRootSelect.value;
|
||||
const chosenSubpath = (subpath || "").trim();
|
||||
@@ -845,6 +887,7 @@
|
||||
const data = await api(
|
||||
`/api/files/discover?root_id=${encodeURIComponent(rootId)}&subpath=${encodeURIComponent(chosenSubpath)}&recursive=${recursive}&limit=200`
|
||||
);
|
||||
state.modalSelectionAnchorPath = null;
|
||||
state.modalFiles = data.items || [];
|
||||
state.modalFiles.forEach((file) => {
|
||||
const path = file.path || "";
|
||||
@@ -891,6 +934,7 @@
|
||||
|
||||
function clearModalSelection() {
|
||||
state.modalSelectedFilePaths.clear();
|
||||
state.modalSelectionAnchorPath = null;
|
||||
renderModalFiles();
|
||||
}
|
||||
|
||||
|
||||
@@ -506,6 +506,10 @@ button.secondary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#modalFilesList li.modal-anchor {
|
||||
box-shadow: inset 0 0 0 1px var(--button-primary-border);
|
||||
}
|
||||
|
||||
.modal-files-tools {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
Binary file not shown.
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
BASE_URL="${BASE_URL:-http://127.0.0.1:8085}"
|
||||
ALT_BASE_URL="http://host.containers.internal:8085"
|
||||
|
||||
detect_base_url() {
|
||||
if curl -fsS --max-time 2 "$BASE_URL/api/health" >/dev/null 2>&1; then
|
||||
echo "$BASE_URL"
|
||||
return
|
||||
fi
|
||||
if curl -fsS --max-time 2 "$ALT_BASE_URL/api/health" >/dev/null 2>&1; then
|
||||
echo "$ALT_BASE_URL"
|
||||
return
|
||||
fi
|
||||
echo "$BASE_URL"
|
||||
}
|
||||
|
||||
BASE_URL="$(detect_base_url)"
|
||||
echo "Using BASE_URL=$BASE_URL"
|
||||
|
||||
echo "== Feature test 1: modal selection modifiers are implemented =="
|
||||
grep -q "modalSelectionAnchorPath" app/static/app.js || { echo "anchor state missing"; exit 1; }
|
||||
grep -q "event.shiftKey" app/static/app.js || { echo "shift handling missing"; exit 1; }
|
||||
grep -q "event.ctrlKey || event.metaKey" app/static/app.js || { echo "ctrl/meta handling missing"; exit 1; }
|
||||
echo "modifier selection validation passed"
|
||||
|
||||
echo
|
||||
echo "== Feature test 2: anchor reset on clear and folder reload =="
|
||||
grep -q "state.modalSelectionAnchorPath = null;" app/static/app.js || { echo "anchor reset missing"; exit 1; }
|
||||
grep -q "function clearModalSelection()" app/static/app.js || { echo "clearModalSelection missing"; exit 1; }
|
||||
grep -q "async function loadModalFiles(subpath)" app/static/app.js || { echo "loadModalFiles missing"; exit 1; }
|
||||
echo "anchor reset validation passed"
|
||||
|
||||
echo
|
||||
echo "== Feature test 3: modal file list UI still present with batch actions =="
|
||||
page="$(curl -fsS "$BASE_URL/")"
|
||||
echo "$page" | grep -q 'id="modalFilesList"' || { echo "modalFilesList missing"; exit 1; }
|
||||
echo "$page" | grep -q 'id="modalSelectAllFilesBtn"' || { echo "Select All button missing"; exit 1; }
|
||||
echo "$page" | grep -q 'id="modalClearSelectionBtn"' || { echo "Clear Selection button missing"; exit 1; }
|
||||
echo "modal UI validation passed"
|
||||
|
||||
echo
|
||||
echo "All file modal selection feature tests passed."
|
||||
Reference in New Issue
Block a user