2025-09-11 19:25:17 +03:00
|
|
|
import { BoardViewData } from ".";
|
2025-09-11 21:11:44 +03:00
|
|
|
import appContext from "../../../components/app_context";
|
2025-09-10 21:10:31 +03:00
|
|
|
import FNote from "../../../entities/fnote";
|
|
|
|
|
import attributes from "../../../services/attributes";
|
2025-09-12 21:50:56 +03:00
|
|
|
import branches from "../../../services/branches";
|
2025-09-11 19:25:17 +03:00
|
|
|
import { executeBulkActions } from "../../../services/bulk_action";
|
2025-09-12 21:50:56 +03:00
|
|
|
import froca from "../../../services/froca";
|
2025-09-11 22:35:31 +03:00
|
|
|
import { t } from "../../../services/i18n";
|
2025-09-10 21:10:31 +03:00
|
|
|
import note_create from "../../../services/note_create";
|
2025-09-11 20:02:58 +03:00
|
|
|
import server from "../../../services/server";
|
2025-09-11 19:25:17 +03:00
|
|
|
import { ColumnMap } from "./data";
|
2025-09-10 21:10:31 +03:00
|
|
|
|
2025-09-11 19:14:54 +03:00
|
|
|
export default class BoardApi {
|
|
|
|
|
|
|
|
|
|
constructor(
|
2025-09-11 19:25:17 +03:00
|
|
|
private byColumn: ColumnMap | undefined,
|
2025-09-11 19:35:46 +03:00
|
|
|
public columns: string[],
|
2025-09-11 19:14:54 +03:00
|
|
|
private parentNote: FNote,
|
2025-09-11 19:25:17 +03:00
|
|
|
private statusAttribute: string,
|
|
|
|
|
private viewConfig: BoardViewData,
|
2025-09-11 20:02:58 +03:00
|
|
|
private saveConfig: (newConfig: BoardViewData) => void,
|
|
|
|
|
private setBranchIdToEdit: (branchId: string | undefined) => void
|
2025-09-11 19:14:54 +03:00
|
|
|
) {};
|
|
|
|
|
|
2025-09-12 16:57:23 +03:00
|
|
|
async createNewItem(column: string, title: string) {
|
2025-09-11 19:14:54 +03:00
|
|
|
try {
|
|
|
|
|
// Get the parent note path
|
|
|
|
|
const parentNotePath = this.parentNote.noteId;
|
|
|
|
|
|
|
|
|
|
// Create a new note as a child of the parent note
|
2025-09-11 20:02:58 +03:00
|
|
|
const { note: newNote, branch: newBranch } = await note_create.createNote(parentNotePath, {
|
2025-09-11 19:14:54 +03:00
|
|
|
activate: false,
|
2025-09-12 16:57:23 +03:00
|
|
|
title
|
2025-09-11 19:14:54 +03:00
|
|
|
});
|
|
|
|
|
|
2025-09-11 21:11:44 +03:00
|
|
|
if (newNote && newBranch) {
|
2025-09-11 19:14:54 +03:00
|
|
|
await this.changeColumn(newNote.noteId, column);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Failed to create new item:", error);
|
2025-09-10 21:10:31 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-11 19:14:54 +03:00
|
|
|
async changeColumn(noteId: string, newColumn: string) {
|
|
|
|
|
await attributes.setLabel(noteId, this.statusAttribute, newColumn);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-12 17:05:17 +03:00
|
|
|
async addNewColumn(columnName: string) {
|
|
|
|
|
if (!columnName.trim()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!this.viewConfig) {
|
|
|
|
|
this.viewConfig = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!this.viewConfig.columns) {
|
|
|
|
|
this.viewConfig.columns = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add the new column to persisted data if it doesn't exist
|
|
|
|
|
const existingColumn = this.viewConfig.columns.find(col => col.value === columnName);
|
|
|
|
|
if (!existingColumn) {
|
|
|
|
|
this.viewConfig.columns.push({ value: columnName });
|
|
|
|
|
this.saveConfig(this.viewConfig);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-11 19:25:17 +03:00
|
|
|
async removeColumn(column: string) {
|
|
|
|
|
// Remove the value from the notes.
|
|
|
|
|
const noteIds = this.byColumn?.get(column)?.map(item => item.note.noteId) || [];
|
|
|
|
|
await executeBulkActions(noteIds, [
|
|
|
|
|
{
|
|
|
|
|
name: "deleteLabel",
|
|
|
|
|
labelName: this.statusAttribute
|
|
|
|
|
}
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
this.viewConfig.columns = (this.viewConfig.columns ?? []).filter(col => col.value !== column);
|
|
|
|
|
this.saveConfig(this.viewConfig);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-11 21:34:10 +03:00
|
|
|
async renameColumn(oldValue: string, newValue: string) {
|
|
|
|
|
const noteIds = this.byColumn?.get(oldValue)?.map(item => item.note.noteId) || [];
|
|
|
|
|
|
|
|
|
|
// Change the value in the notes.
|
|
|
|
|
await executeBulkActions(noteIds, [
|
|
|
|
|
{
|
|
|
|
|
name: "updateLabelValue",
|
|
|
|
|
labelName: this.statusAttribute,
|
|
|
|
|
labelValue: newValue
|
|
|
|
|
}
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Rename the column in the persisted data.
|
|
|
|
|
for (const column of this.viewConfig.columns || []) {
|
|
|
|
|
if (column.value === oldValue) {
|
|
|
|
|
column.value = newValue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.saveConfig(this.viewConfig);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-12 17:39:52 +03:00
|
|
|
reorderColumn(fromIndex: number, toIndex: number) {
|
|
|
|
|
if (!this.columns || fromIndex === toIndex) return;
|
|
|
|
|
|
|
|
|
|
const newColumns = [...this.columns];
|
|
|
|
|
const [movedColumn] = newColumns.splice(fromIndex, 1);
|
|
|
|
|
newColumns.splice(toIndex, 0, movedColumn);
|
|
|
|
|
|
|
|
|
|
// Update view config with new column order
|
|
|
|
|
const newViewConfig = {
|
|
|
|
|
...this.viewConfig,
|
|
|
|
|
columns: newColumns.map(col => ({ value: col }))
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this.saveConfig(newViewConfig);
|
|
|
|
|
return newColumns;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-11 21:11:44 +03:00
|
|
|
async insertRowAtPosition(
|
|
|
|
|
column: string,
|
|
|
|
|
relativeToBranchId: string,
|
|
|
|
|
direction: "before" | "after") {
|
|
|
|
|
const { note, branch } = await note_create.createNote(this.parentNote.noteId, {
|
|
|
|
|
activate: false,
|
|
|
|
|
targetBranchId: relativeToBranchId,
|
|
|
|
|
target: direction,
|
2025-09-11 22:35:31 +03:00
|
|
|
title: t("board_view.new-item")
|
2025-09-11 21:11:44 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!note || !branch) {
|
|
|
|
|
throw new Error("Failed to create note");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { noteId } = note;
|
|
|
|
|
await this.changeColumn(noteId, column);
|
|
|
|
|
this.startEditing(branch.branchId);
|
|
|
|
|
|
|
|
|
|
return note;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
openNote(noteId: string) {
|
|
|
|
|
appContext.triggerCommand("openInPopup", { noteIdOrPath: noteId });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
startEditing(branchId: string) {
|
|
|
|
|
this.setBranchIdToEdit(branchId);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-11 20:02:58 +03:00
|
|
|
dismissEditingTitle() {
|
|
|
|
|
this.setBranchIdToEdit(undefined);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
renameCard(noteId: string, newTitle: string) {
|
|
|
|
|
return server.put(`notes/${noteId}/title`, { title: newTitle.trim() });
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-12 22:25:33 +03:00
|
|
|
removeFromBoard(noteId: string) {
|
|
|
|
|
const note = froca.getNoteFromCache(noteId);
|
|
|
|
|
if (!note) return;
|
|
|
|
|
return attributes.removeOwnedLabelByName(note, this.statusAttribute);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-12 21:50:56 +03:00
|
|
|
async moveWithinBoard(noteId: string, sourceBranchId: string, sourceIndex: number, targetIndex: number, sourceColumn: string, targetColumn: string) {
|
|
|
|
|
const targetItems = this.byColumn?.get(targetColumn) ?? [];
|
|
|
|
|
|
|
|
|
|
const note = froca.getNoteFromCache(noteId);
|
|
|
|
|
if (!note) return;
|
|
|
|
|
|
|
|
|
|
if (sourceColumn !== targetColumn) {
|
|
|
|
|
// Moving to a different column
|
|
|
|
|
await this.changeColumn(noteId, targetColumn);
|
|
|
|
|
|
|
|
|
|
// If there are items in the target column, reorder
|
|
|
|
|
if (targetItems.length > 0 && targetIndex < targetItems.length) {
|
|
|
|
|
const targetBranch = targetItems[targetIndex].branch;
|
|
|
|
|
await branches.moveBeforeBranch([ sourceBranchId ], targetBranch.branchId);
|
|
|
|
|
}
|
|
|
|
|
} else if (sourceIndex !== targetIndex) {
|
|
|
|
|
// Reordering within the same column
|
|
|
|
|
let targetBranchId: string | null = null;
|
|
|
|
|
|
|
|
|
|
if (targetIndex < targetItems.length) {
|
|
|
|
|
// Moving before an existing item
|
|
|
|
|
const adjustedIndex = sourceIndex < targetIndex ? targetIndex : targetIndex;
|
|
|
|
|
if (adjustedIndex < targetItems.length) {
|
|
|
|
|
targetBranchId = targetItems[adjustedIndex].branch.branchId;
|
|
|
|
|
if (targetBranchId) {
|
|
|
|
|
await branches.moveBeforeBranch([ sourceBranchId ], targetBranchId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (targetIndex > 0) {
|
|
|
|
|
// Moving to the end - place after the last item
|
|
|
|
|
const lastItem = targetItems[targetItems.length - 1];
|
|
|
|
|
await branches.moveAfterBranch([ sourceBranchId ], lastItem.branch.branchId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-10 21:10:31 +03:00
|
|
|
}
|
2025-09-11 19:14:54 +03:00
|
|
|
|