feat(client): batch delete column values

This commit is contained in:
Elian Doran 2025-07-16 21:30:16 +03:00
parent 34f1a84769
commit 66486541fe
No known key found for this signature in database
4 changed files with 76 additions and 26 deletions

View File

@ -41,8 +41,14 @@ async function info(message: string) {
return new Promise((res) => appContext.triggerCommand("showInfoDialog", { message, callback: res }));
}
/**
* Displays a confirmation dialog with the given message.
*
* @param message the message to display in the dialog.
* @returns A promise that resolves to true if the user confirmed, false otherwise.
*/
async function confirm(message: string) {
return new Promise((res) =>
return new Promise<boolean>((res) =>
appContext.triggerCommand("showConfirmDialog", <ConfirmWithMessageOptions>{
message,
callback: (x: false | ConfirmDialogOptions) => res(x && x.confirmed)

View File

@ -1956,7 +1956,9 @@
"row-insert-child": "Insert child note",
"add-column-to-the-left": "Add column to the left",
"add-column-to-the-right": "Add column to the right",
"edit-column": "Edit column"
"edit-column": "Edit column",
"delete_column_confirmation": "Are you sure you want to delete this column? The corresponding attribute will be removed from all notes.",
"delete-column": "Delete column"
},
"book_properties_config": {
"hide-weekends": "Hide weekends",

View File

@ -6,27 +6,48 @@ import toast from "../../../services/toast";
import ws from "../../../services/ws";
export async function renameColumn(parentNoteId: string, type: "label" | "relation", originalName: string, newName: string) {
if (type === "label") {
return executeBulkAction(parentNoteId, {
name: "renameLabel",
oldLabelName: originalName,
newLabelName: newName
});
} else {
return executeBulkAction(parentNoteId, {
name: "renameRelation",
oldRelationName: originalName,
newRelationName: newName
});
}
}
export async function deleteColumn(parentNoteId: string, type: "label" | "relation", columnName: string) {
if (type === "label") {
return executeBulkAction(parentNoteId, {
name: "deleteLabel",
labelName: columnName
});
} else {
return executeBulkAction(parentNoteId, {
name: "deleteRelation",
relationName: columnName
});
}
}
async function executeBulkAction(parentNoteId: string, action: {}) {
const bulkActionNote = await froca.getNote("_bulkAction");
if (!bulkActionNote) {
console.warn("Bulk action note not found");
return;
}
if (type === "label") {
attributes.setLabel("_bulkAction", "action", JSON.stringify({
name: "renameLabel",
oldLabelName: originalName,
newLabelName: newName
}));
await server.post("bulk-action/execute", {
noteIds: [ parentNoteId ],
includeDescendants: true
});
attributes.setLabel("_bulkAction", "action", JSON.stringify(action));
await server.post("bulk-action/execute", {
noteIds: [ parentNoteId ],
includeDescendants: true
});
await ws.waitForMaxKnownEntityChangeId();
toast.showMessage(t("bulk_actions.bulk_actions_executed"), 3000);
} else {
console.warn("Renaming relation columns is not supported yet");
return;
}
await ws.waitForMaxKnownEntityChangeId();
toast.showMessage(t("bulk_actions.bulk_actions_executed"), 3000);
}

View File

@ -7,10 +7,12 @@ import link_context_menu from "../../../menus/link_context_menu.js";
import type FNote from "../../../entities/fnote.js";
import froca from "../../../services/froca.js";
import type Component from "../../../components/component.js";
import dialog from "../../../services/dialog.js";
import { deleteColumn } from "./bulk_actions.js";
export function setupContextMenu(tabulator: Tabulator, parentNote: FNote) {
tabulator.on("rowContext", (e, row) => showRowContextMenu(e, row, parentNote, tabulator));
tabulator.on("headerContext", (e, col) => showColumnContextMenu(e, col, tabulator));
tabulator.on("headerContext", (e, col) => showColumnContextMenu(e, col, parentNote, tabulator));
// Pressing the expand button prevents bubbling and the context menu remains menu when it shouldn't.
if (tabulator.options.dataTree) {
@ -20,7 +22,7 @@ export function setupContextMenu(tabulator: Tabulator, parentNote: FNote) {
}
}
function showColumnContextMenu(_e: UIEvent, column: ColumnComponent, tabulator: Tabulator) {
function showColumnContextMenu(_e: UIEvent, column: ColumnComponent, parentNote: FNote, tabulator: Tabulator) {
const e = _e as MouseEvent;
const { title, field } = column.getDefinition();
@ -87,6 +89,15 @@ function showColumnContextMenu(_e: UIEvent, column: ColumnComponent, tabulator:
referenceColumn: column
})
},
{
title: t("table_view.add-column-to-the-right"),
uiIcon: "bx bx-horizontal-right",
handler: () => getParentComponent(e)?.triggerCommand("addNewTableColumn", {
referenceColumn: column,
direction: "after"
})
},
{ title: "----" },
{
title: t("table_view.edit-column"),
uiIcon: "bx bx-edit",
@ -97,12 +108,22 @@ function showColumnContextMenu(_e: UIEvent, column: ColumnComponent, tabulator:
})
},
{
title: t("table_view.add-column-to-the-right"),
uiIcon: "bx bx-horizontal-right",
handler: () => getParentComponent(e)?.triggerCommand("addNewTableColumn", {
referenceColumn: column,
direction: "after"
})
title: t("table_view.delete-column"),
uiIcon: "bx bx-trash",
enabled: !!column.getField() && column.getField() !== "title",
handler: async () => {
if (!await dialog.confirm(t("table_view.delete_column_confirmation"))) {
return;
}
let [ type, name ] = column.getField()?.split(".", 2);
if (!type || !name) {
return;
}
type = type.replace("s", "");
deleteColumn(parentNote.noteId, type as "label" | "relation", name);
}
}
],
selectMenuItemHandler() {},