From 2b452a18dffb06e81dfc188fd130533f98f68f52 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 11 Sep 2025 19:14:54 +0300 Subject: [PATCH] refactor(react/collections/table): use class-based API --- .../src/widgets/collections/board/api.ts | 49 +++++++++++-------- .../src/widgets/collections/board/index.tsx | 27 +++++----- apps/client/src/widgets/react/hooks.tsx | 5 ++ 3 files changed, 49 insertions(+), 32 deletions(-) diff --git a/apps/client/src/widgets/collections/board/api.ts b/apps/client/src/widgets/collections/board/api.ts index 103ae3a0e..600c5ebd1 100644 --- a/apps/client/src/widgets/collections/board/api.ts +++ b/apps/client/src/widgets/collections/board/api.ts @@ -2,30 +2,39 @@ import FNote from "../../../entities/fnote"; import attributes from "../../../services/attributes"; import note_create from "../../../services/note_create"; -export async function createNewItem(parentNote: FNote, column: string) { - try { - // Get the parent note path - const parentNotePath = parentNote.noteId; - const statusAttribute = parentNote.getLabelValue("board:groupBy") ?? "status"; +export default class BoardApi { - // Create a new note as a child of the parent note - const { note: newNote } = await note_create.createNote(parentNotePath, { - activate: false, - title: "New item" - }); + constructor( + private parentNote: FNote, + private statusAttribute: string + ) {}; - if (newNote) { - // Set the status label to place it in the correct column - await changeColumn(newNote.noteId, column, statusAttribute); + async createNewItem(column: string) { + try { + // Get the parent note path + const parentNotePath = this.parentNote.noteId; - // Start inline editing of the newly created card - //this.startInlineEditingCard(newNote.noteId); + // Create a new note as a child of the parent note + const { note: newNote } = await note_create.createNote(parentNotePath, { + activate: false, + title: "New item" + }); + + if (newNote) { + // Set the status label to place it in the correct column + await this.changeColumn(newNote.noteId, column); + + // Start inline editing of the newly created card + //this.startInlineEditingCard(newNote.noteId); + } + } catch (error) { + console.error("Failed to create new item:", error); } - } catch (error) { - console.error("Failed to create new item:", error); } + + async changeColumn(noteId: string, newColumn: string) { + await attributes.setLabel(noteId, this.statusAttribute, newColumn); + } + } -export async function changeColumn(noteId: string, newColumn: string, statusAttribute: string) { - await attributes.setLabel(noteId, statusAttribute, newColumn); -} diff --git a/apps/client/src/widgets/collections/board/index.tsx b/apps/client/src/widgets/collections/board/index.tsx index ae122c65e..b5f4ea603 100644 --- a/apps/client/src/widgets/collections/board/index.tsx +++ b/apps/client/src/widgets/collections/board/index.tsx @@ -1,13 +1,13 @@ -import { useCallback, useEffect, useRef, useState } from "preact/hooks"; +import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks"; import { ViewModeProps } from "../interface"; import "./index.css"; import { ColumnMap, getBoardData } from "./data"; -import { useNoteLabel, useTriliumEvent } from "../../react/hooks"; +import { useNoteLabelWithDefault, useTriliumEvent } from "../../react/hooks"; import FNote from "../../../entities/fnote"; import FBranch from "../../../entities/fbranch"; import Icon from "../../react/Icon"; import { t } from "../../../services/i18n"; -import { createNewItem, changeColumn } from "./api"; +import Api from "./api"; import FormTextBox from "../../react/FormTextBox"; import branchService from "../../../services/branches"; @@ -20,7 +20,7 @@ export interface BoardColumnData { } export default function BoardView({ note: parentNote, noteIds, viewConfig, saveConfig }: ViewModeProps) { - const [ statusAttribute ] = useNoteLabel(parentNote, "board:groupBy"); + const [ statusAttribute ] = useNoteLabelWithDefault(parentNote, "board:groupBy", "status"); const [ byColumn, setByColumn ] = useState(); const [ columns, setColumns ] = useState(); const [ draggedCard, setDraggedCard ] = useState<{ noteId: string, branchId: string, fromColumn: string, index: number } | null>(null); @@ -28,9 +28,12 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC const [ dropPosition, setDropPosition ] = useState<{ column: string, index: number } | null>(null); const [ draggedColumn, setDraggedColumn ] = useState<{ column: string, index: number } | null>(null); const [ columnDropPosition, setColumnDropPosition ] = useState(null); + const api = useMemo(() => { + return new Api(parentNote, statusAttribute); + }, [ parentNote, statusAttribute ]); function refresh() { - getBoardData(parentNote, statusAttribute ?? "status", viewConfig ?? {}).then(({ byColumn, newPersistedData }) => { + getBoardData(parentNote, statusAttribute, viewConfig ?? {}).then(({ byColumn, newPersistedData }) => { setByColumn(byColumn); if (newPersistedData) { @@ -132,10 +135,10 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC
)} void, draggedColumn: { column: string, index: number } | null, setDraggedColumn: (column: { column: string, index: number } | null) => void, - isDraggingColumn: boolean + isDraggingColumn: boolean, + api: Api }) { const handleColumnDragStart = useCallback((e: DragEvent) => { e.dataTransfer!.effectAllowed = 'move'; @@ -250,7 +253,7 @@ function Column({ if (draggedCard.fromColumn !== column) { // Moving to a different column - await changeColumn(draggedCard.noteId, column, statusAttribute); + await api.changeColumn(draggedCard.noteId, column); // If there are items in the target column, reorder if (targetItems.length > 0 && targetIndex < targetItems.length) { @@ -323,7 +326,7 @@ function Column({
)} -
createNewItem(parentNote, column)}> +
api.createNewItem(column)}> {" "} {t("board_view.new-item")}
diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index 4e7200328..13eff8c46 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -324,6 +324,11 @@ export function useNoteLabel(note: FNote | undefined | null, labelName: string): ] as const; } +export function useNoteLabelWithDefault(note: FNote | undefined | null, labelName: string, defaultValue: string): [string, (newValue: string | null | undefined) => void] { + const [ labelValue, setLabelValue ] = useNoteLabel(note, labelName); + return [ labelValue ?? defaultValue, setLabelValue]; +} + export function useNoteLabelBoolean(note: FNote | undefined | null, labelName: string): [ boolean, (newValue: boolean) => void] { const [ labelValue, setLabelValue ] = useState(!!note?.hasLabel(labelName));