diff --git a/apps/client/src/widgets/collections/NoteList.tsx b/apps/client/src/widgets/collections/NoteList.tsx index c613f8d39..bd007a40f 100644 --- a/apps/client/src/widgets/collections/NoteList.tsx +++ b/apps/client/src/widgets/collections/NoteList.tsx @@ -14,6 +14,7 @@ import { WebSocketMessage } from "@triliumnext/commons"; import froca from "../../services/froca"; import PresentationView from "./presentation"; import { ListPrintView } from "./legacy/ListPrintView"; +import TablePrintView from "./table/TablePrintView"; interface NoteListProps { note: FNote | null | undefined; @@ -117,9 +118,13 @@ function getComponentByViewType(viewType: ViewTypeOptions, props: ViewModeProps< case "geoMap": return ; case "calendar": - return + return ; case "table": - return + if (props.media !== "print") { + return ; + } else { + return ; + } case "board": return case "presentation": diff --git a/apps/client/src/widgets/collections/table/TablePrintView.tsx b/apps/client/src/widgets/collections/table/TablePrintView.tsx new file mode 100644 index 000000000..a7e36dfb3 --- /dev/null +++ b/apps/client/src/widgets/collections/table/TablePrintView.tsx @@ -0,0 +1,38 @@ +import { useRef, useState } from "preact/hooks"; +import { ViewModeProps } from "../interface"; +import useData, { TableConfig } from "./data"; +import { ExportModule, PrintModule, Tabulator as VanillaTabulator} from 'tabulator-tables'; +import Tabulator from "./tabulator"; +import { RawHtmlBlock } from "../../react/RawHtml"; + +export default function TablePrintView({ note, noteIds, viewConfig }: ViewModeProps) { + const tabulatorRef = useRef(null); + const { columnDefs, rowData, movableRows, hasChildren } = useData(note, noteIds, viewConfig, undefined, () => {}); + const [ html, setHtml ] = useState(); + + return rowData && ( +
+ {!html ? ( + { + const tabulator = tabulatorRef.current; + if (!tabulator) return; + setHtml(tabulator.getHtml()); + }} + /> + ) : ( + + )} +
+ + ) +} diff --git a/apps/client/src/widgets/collections/table/data.tsx b/apps/client/src/widgets/collections/table/data.tsx new file mode 100644 index 000000000..b77a1545e --- /dev/null +++ b/apps/client/src/widgets/collections/table/data.tsx @@ -0,0 +1,77 @@ +import type { ColumnDefinition } from "tabulator-tables"; +import FNote from "../../../entities/fnote"; +import { useNoteLabelBoolean, useNoteLabelInt, useTriliumEvent } from "../../react/hooks"; +import { useEffect, useState } from "preact/hooks"; +import getAttributeDefinitionInformation, { buildRowDefinitions, TableData } from "./rows"; +import froca from "../../../services/froca"; +import { buildColumnDefinitions } from "./columns"; +import attributes from "../../../services/attributes"; +import { RefObject } from "preact"; + +export interface TableConfig { + tableData: { + columns?: ColumnDefinition[]; + }; +} + +export default function useData(note: FNote, noteIds: string[], viewConfig: TableConfig | undefined, newAttributePosition: RefObject | undefined, resetNewAttributePosition: () => void) { + const [ maxDepth ] = useNoteLabelInt(note, "maxNestingDepth") ?? -1; + const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived"); + + const [ columnDefs, setColumnDefs ] = useState(); + const [ rowData, setRowData ] = useState(); + const [ hasChildren, setHasChildren ] = useState(); + const [ isSorted ] = useNoteLabelBoolean(note, "sorted"); + const [ movableRows, setMovableRows ] = useState(false); + + async function refresh() { + const info = getAttributeDefinitionInformation(note); + + // Ensure all note IDs are loaded. + await froca.getNotes(noteIds); + + const { definitions: rowData, hasSubtree: hasChildren, rowNumber } = await buildRowDefinitions(note, info, includeArchived, maxDepth); + const columnDefs = buildColumnDefinitions({ + info, + movableRows, + existingColumnData: viewConfig?.tableData?.columns, + rowNumberHint: rowNumber, + position: newAttributePosition?.current ?? undefined + }); + setColumnDefs(columnDefs); + setRowData(rowData); + setHasChildren(hasChildren); + resetNewAttributePosition(); + } + + useEffect(() => { refresh() }, [ note, noteIds, maxDepth, movableRows ]); + + useTriliumEvent("entitiesReloaded", ({ loadResults}) => { + if (glob.device === "print") return; + + // React to column changes. + if (loadResults.getAttributeRows().find(attr => + attr.type === "label" && + (attr.name?.startsWith("label:") || attr.name?.startsWith("relation:")) && + attributes.isAffecting(attr, note))) { + refresh(); + return; + } + + // React to external row updates. + if (loadResults.getBranchRows().some(branch => branch.parentNoteId === note.noteId || noteIds.includes(branch.parentNoteId ?? "")) + || loadResults.getNoteIds().some(noteId => noteIds.includes(noteId)) + || loadResults.getAttributeRows().some(attr => noteIds.includes(attr.noteId!)) + || loadResults.getAttributeRows().some(attr => attr.name === "archived" && attr.noteId && noteIds.includes(attr.noteId))) { + refresh(); + return; + } + }); + + // Identify if movable rows. + useEffect(() => { + setMovableRows(!isSorted && note.type !== "search" && !hasChildren); + }, [ isSorted, note, hasChildren ]); + + return { columnDefs, rowData, movableRows, hasChildren }; +} diff --git a/apps/client/src/widgets/collections/table/index.tsx b/apps/client/src/widgets/collections/table/index.tsx index f6ae82009..d557f12d3 100644 --- a/apps/client/src/widgets/collections/table/index.tsx +++ b/apps/client/src/widgets/collections/table/index.tsx @@ -1,10 +1,9 @@ import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "preact/hooks"; import { ViewModeProps } from "../interface"; -import { buildColumnDefinitions } from "./columns"; -import getAttributeDefinitionInformation, { buildRowDefinitions, TableData } from "./rows"; -import { useLegacyWidget, useNoteLabelBoolean, useNoteLabelInt, useTriliumEvent } from "../../react/hooks"; +import { TableData } from "./rows"; +import { useLegacyWidget } from "../../react/hooks"; import Tabulator from "./tabulator"; -import { Tabulator as VanillaTabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, ColumnDefinition, DataTreeModule, Options, RowComponent} from 'tabulator-tables'; +import { Tabulator as VanillaTabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, DataTreeModule, Options, RowComponent} from 'tabulator-tables'; import { useContextMenu } from "./context_menu"; import { ParentComponent } from "../../react/react_utils"; import FNote from "../../../entities/fnote"; @@ -14,16 +13,8 @@ import "./index.css"; import useRowTableEditing from "./row_editing"; import useColTableEditing from "./col_editing"; import AttributeDetailWidget from "../../attribute_widgets/attribute_detail"; -import attributes from "../../../services/attributes"; -import { RefObject } from "preact"; import SpacedUpdate from "../../../services/spaced_update"; -import froca from "../../../services/froca"; - -interface TableConfig { - tableData: { - columns?: ColumnDefinition[]; - }; -} +import useData, { TableConfig } from "./data"; export default function TableView({ note, noteIds, notePath, viewConfig, saveConfig }: ViewModeProps) { const tabulatorRef = useRef(null); @@ -118,67 +109,7 @@ function usePersistence(viewConfig: TableConfig | null | undefined, saveConfig: return () => { spacedUpdate.updateNowIfNecessary(); }; - }, [ viewConfig, saveConfig ]) + }, [ viewConfig, saveConfig ]); return persistenceProps; } - -function useData(note: FNote, noteIds: string[], viewConfig: TableConfig | undefined, newAttributePosition: RefObject, resetNewAttributePosition: () => void) { - const [ maxDepth ] = useNoteLabelInt(note, "maxNestingDepth") ?? -1; - const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived"); - - const [ columnDefs, setColumnDefs ] = useState(); - const [ rowData, setRowData ] = useState(); - const [ hasChildren, setHasChildren ] = useState(); - const [ isSorted ] = useNoteLabelBoolean(note, "sorted"); - const [ movableRows, setMovableRows ] = useState(false); - - async function refresh() { - const info = getAttributeDefinitionInformation(note); - - // Ensure all note IDs are loaded. - await froca.getNotes(noteIds); - - const { definitions: rowData, hasSubtree: hasChildren, rowNumber } = await buildRowDefinitions(note, info, includeArchived, maxDepth); - const columnDefs = buildColumnDefinitions({ - info, - movableRows, - existingColumnData: viewConfig?.tableData?.columns, - rowNumberHint: rowNumber, - position: newAttributePosition.current ?? undefined - }); - setColumnDefs(columnDefs); - setRowData(rowData); - setHasChildren(hasChildren); - resetNewAttributePosition(); - } - - useEffect(() => { refresh() }, [ note, noteIds, maxDepth, movableRows ]); - - useTriliumEvent("entitiesReloaded", ({ loadResults}) => { - // React to column changes. - if (loadResults.getAttributeRows().find(attr => - attr.type === "label" && - (attr.name?.startsWith("label:") || attr.name?.startsWith("relation:")) && - attributes.isAffecting(attr, note))) { - refresh(); - return; - } - - // React to external row updates. - if (loadResults.getBranchRows().some(branch => branch.parentNoteId === note.noteId || noteIds.includes(branch.parentNoteId ?? "")) - || loadResults.getNoteIds().some(noteId => noteIds.includes(noteId)) - || loadResults.getAttributeRows().some(attr => noteIds.includes(attr.noteId!)) - || loadResults.getAttributeRows().some(attr => attr.name === "archived" && attr.noteId && noteIds.includes(attr.noteId))) { - refresh(); - return; - } - }); - - // Identify if movable rows. - useEffect(() => { - setMovableRows(!isSorted && note.type !== "search" && !hasChildren); - }, [ isSorted, note, hasChildren ]); - - return { columnDefs, rowData, movableRows, hasChildren }; -} diff --git a/apps/client/src/widgets/collections/table/tabulator.tsx b/apps/client/src/widgets/collections/table/tabulator.tsx index 6301d5b38..31fb8d4f8 100644 --- a/apps/client/src/widgets/collections/table/tabulator.tsx +++ b/apps/client/src/widgets/collections/table/tabulator.tsx @@ -14,9 +14,10 @@ interface TableProps extends Omit; index: keyof T; footerElement?: string | HTMLElement | JSX.Element; + onReady?: () => void; } -export default function Tabulator({ className, columns, data, modules, tabulatorRef: externalTabulatorRef, footerElement, events, index, dataTree, ...restProps }: TableProps) { +export default function Tabulator({ className, columns, data, modules, tabulatorRef: externalTabulatorRef, footerElement, events, index, dataTree, onReady, ...restProps }: TableProps) { const parentComponent = useContext(ParentComponent); const containerRef = useRef(null); const tabulatorRef = useRef(null); @@ -43,6 +44,7 @@ export default function Tabulator({ className, columns, data, modules, tabula tabulator.on("tableBuilt", () => { tabulatorRef.current = tabulator; externalTabulatorRef.current = tabulator; + onReady?.(); }); return () => tabulator.destroy();