feat(tree): allow multiple selection for archive/unarchive

This commit is contained in:
Elian Doran
2025-09-13 17:26:27 +03:00
parent f42d375cc7
commit 8a66ee7565

View File

@@ -14,6 +14,7 @@ import type FAttachment from "../entities/fattachment.js";
import type { SelectMenuItemEventListener } from "../components/events.js"; import type { SelectMenuItemEventListener } from "../components/events.js";
import utils from "../services/utils.js"; import utils from "../services/utils.js";
import attributes from "../services/attributes.js"; import attributes from "../services/attributes.js";
import { executeBulkActions } from "../services/bulk_action.js";
// TODO: Deduplicate once client/server is well split. // TODO: Deduplicate once client/server is well split.
interface ConvertToAttachmentResponse { interface ConvertToAttachmentResponse {
@@ -56,13 +57,17 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
const branch = froca.getBranch(this.node.data.branchId); const branch = froca.getBranch(this.node.data.branchId);
const isNotRoot = note?.noteId !== "root"; const isNotRoot = note?.noteId !== "root";
const isHoisted = note?.noteId === appContext.tabManager.getActiveContext()?.hoistedNoteId; const isHoisted = note?.noteId === appContext.tabManager.getActiveContext()?.hoistedNoteId;
const isArchived = note?.isArchived;
const parentNote = isNotRoot && branch ? await froca.getNote(branch.parentNoteId) : null; const parentNote = isNotRoot && branch ? await froca.getNote(branch.parentNoteId) : null;
// some actions don't support multi-note, so they are disabled when notes are selected, // some actions don't support multi-note, so they are disabled when notes are selected,
// the only exception is when the only selected note is the one that was right-clicked, then // the only exception is when the only selected note is the one that was right-clicked, then
// it's clear what the user meant to do. // it's clear what the user meant to do.
const selNodes = this.treeWidget.getSelectedNodes(); const selNodes = this.treeWidget.getSelectedNodes();
const selectedNotes = await froca.getNotes(selNodes.map(node => node.data.noteId));
if (note && !selectedNotes.includes(note)) selectedNotes.push(note);
const isArchived = selectedNotes.every(note => note.isArchived);
const canToggleArchived = !selectedNotes.some(note => note.isArchived !== isArchived);
const noSelectedNotes = selNodes.length === 0 || (selNodes.length === 1 && selNodes[0] === this.node); const noSelectedNotes = selNodes.length === 0 || (selNodes.length === 1 && selNodes[0] === this.node);
const notSearch = note?.type !== "search"; const notSearch = note?.type !== "search";
@@ -194,15 +199,30 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
{ {
title: !isArchived ? t("tree-context-menu.archive") : t("tree-context-menu.unarchive"), title: !isArchived ? t("tree-context-menu.archive") : t("tree-context-menu.unarchive"),
uiIcon: !isArchived ? "bx bx-archive" : "bx bx-archive-out", uiIcon: !isArchived ? "bx bx-archive" : "bx bx-archive-out",
enabled: canToggleArchived,
handler: () => { handler: () => {
if (!note) return; if (!selectedNotes.length) return;
if (!isArchived) {
attributes.addLabel(note.noteId, "archived"); if (selectedNotes.length == 1) {
const note = selectedNotes[0];
if (!isArchived) {
attributes.addLabel(note.noteId, "archived");
} else {
attributes.removeOwnedLabelByName(note, "archived");
}
} else { } else {
attributes.removeOwnedLabelByName(note, "archived"); const noteIds = selectedNotes.map(note => note.noteId);
if (!isArchived) {
executeBulkActions(noteIds, [{
name: "addLabel", labelName: "archived"
}]);
} else {
executeBulkActions(noteIds, [{
name: "deleteLabel", labelName: "archived"
}]);
}
} }
}, }
enabled: noSelectedNotes
}, },
{ {
title: `${t("tree-context-menu.delete")} <kbd data-command="deleteNotes"></kbd>`, title: `${t("tree-context-menu.delete")} <kbd data-command="deleteNotes"></kbd>`,