mirror of
https://github.com/zadam/trilium.git
synced 2025-11-26 02:24:23 +01:00
feat(print/table): basic implementation using export module
This commit is contained in:
parent
4552b2b158
commit
6f83b932b0
@ -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 <GeoView {...props} />;
|
||||
case "calendar":
|
||||
return <CalendarView {...props} />
|
||||
return <CalendarView {...props} />;
|
||||
case "table":
|
||||
return <TableView {...props} />
|
||||
if (props.media !== "print") {
|
||||
return <TableView {...props} />;
|
||||
} else {
|
||||
return <TablePrintView {...props} />;
|
||||
}
|
||||
case "board":
|
||||
return <BoardView {...props} />
|
||||
case "presentation":
|
||||
|
||||
38
apps/client/src/widgets/collections/table/TablePrintView.tsx
Normal file
38
apps/client/src/widgets/collections/table/TablePrintView.tsx
Normal file
@ -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<TableConfig>) {
|
||||
const tabulatorRef = useRef<VanillaTabulator>(null);
|
||||
const { columnDefs, rowData, movableRows, hasChildren } = useData(note, noteIds, viewConfig, undefined, () => {});
|
||||
const [ html, setHtml ] = useState<string>();
|
||||
|
||||
return rowData && (
|
||||
<div className="table-print-view">
|
||||
{!html ? (
|
||||
<Tabulator
|
||||
tabulatorRef={tabulatorRef}
|
||||
className="table-print-view-container"
|
||||
modules={[ PrintModule, ExportModule ]}
|
||||
columns={columnDefs ?? []}
|
||||
data={rowData}
|
||||
index="branchId"
|
||||
dataTree={hasChildren}
|
||||
printAsHtml={true}
|
||||
printStyled={true}
|
||||
onReady={() => {
|
||||
const tabulator = tabulatorRef.current;
|
||||
if (!tabulator) return;
|
||||
setHtml(tabulator.getHtml());
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<RawHtmlBlock html={html} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
77
apps/client/src/widgets/collections/table/data.tsx
Normal file
77
apps/client/src/widgets/collections/table/data.tsx
Normal file
@ -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<number | undefined> | undefined, resetNewAttributePosition: () => void) {
|
||||
const [ maxDepth ] = useNoteLabelInt(note, "maxNestingDepth") ?? -1;
|
||||
const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived");
|
||||
|
||||
const [ columnDefs, setColumnDefs ] = useState<ColumnDefinition[]>();
|
||||
const [ rowData, setRowData ] = useState<TableData[]>();
|
||||
const [ hasChildren, setHasChildren ] = useState<boolean>();
|
||||
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 };
|
||||
}
|
||||
@ -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<TableConfig>) {
|
||||
const tabulatorRef = useRef<VanillaTabulator>(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<number | undefined>, resetNewAttributePosition: () => void) {
|
||||
const [ maxDepth ] = useNoteLabelInt(note, "maxNestingDepth") ?? -1;
|
||||
const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived");
|
||||
|
||||
const [ columnDefs, setColumnDefs ] = useState<ColumnDefinition[]>();
|
||||
const [ rowData, setRowData ] = useState<TableData[]>();
|
||||
const [ hasChildren, setHasChildren ] = useState<boolean>();
|
||||
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 };
|
||||
}
|
||||
|
||||
@ -14,9 +14,10 @@ interface TableProps<T> extends Omit<Options, "data" | "footerElement" | "index"
|
||||
events?: Partial<EventCallBackMethods>;
|
||||
index: keyof T;
|
||||
footerElement?: string | HTMLElement | JSX.Element;
|
||||
onReady?: () => void;
|
||||
}
|
||||
|
||||
export default function Tabulator<T>({ className, columns, data, modules, tabulatorRef: externalTabulatorRef, footerElement, events, index, dataTree, ...restProps }: TableProps<T>) {
|
||||
export default function Tabulator<T>({ className, columns, data, modules, tabulatorRef: externalTabulatorRef, footerElement, events, index, dataTree, onReady, ...restProps }: TableProps<T>) {
|
||||
const parentComponent = useContext(ParentComponent);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const tabulatorRef = useRef<VanillaTabulator>(null);
|
||||
@ -43,6 +44,7 @@ export default function Tabulator<T>({ className, columns, data, modules, tabula
|
||||
tabulator.on("tableBuilt", () => {
|
||||
tabulatorRef.current = tabulator;
|
||||
externalTabulatorRef.current = tabulator;
|
||||
onReady?.();
|
||||
});
|
||||
|
||||
return () => tabulator.destroy();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user