chore(react/collections/table): fix some issues with col editing

This commit is contained in:
Elian Doran 2025-09-09 18:48:09 +03:00
parent 1e654fbcd6
commit 4e37a5f08e
No known key found for this signature in database
5 changed files with 80 additions and 77 deletions

View File

@ -2,31 +2,27 @@ import { useLegacyImperativeHandlers } from "../../react/hooks";
import { Attribute } from "../../../services/attribute_parser"; import { Attribute } from "../../../services/attribute_parser";
import { RefObject } from "preact"; import { RefObject } from "preact";
import { Tabulator } from "tabulator-tables"; import { Tabulator } from "tabulator-tables";
import { useEffect, useState } from "preact/hooks"; import { useRef, useState } from "preact/hooks";
import { CommandListenerData, EventData } from "../../../components/app_context"; import { CommandListenerData, EventData } from "../../../components/app_context";
import AttributeDetailWidget from "../../attribute_widgets/attribute_detail"; import AttributeDetailWidget from "../../attribute_widgets/attribute_detail";
import attributes from "../../../services/attributes"; import attributes from "../../../services/attributes";
import { renameColumn } from "../../view_widgets/table_view/bulk_actions"; import { renameColumn } from "../../view_widgets/table_view/bulk_actions";
import FNote from "../../../entities/fnote"; import FNote from "../../../entities/fnote";
import { getAttributeFromField } from "./utils";
export default function useColTableEditing(api: RefObject<Tabulator>, attributeDetailWidget: AttributeDetailWidget, parentNote: FNote) { export default function useColTableEditing(api: RefObject<Tabulator>, attributeDetailWidget: AttributeDetailWidget, parentNote: FNote) {
const [ existingAttributeToEdit, setExistingAttributeToEdit ] = useState<Attribute>(); const [ existingAttributeToEdit, setExistingAttributeToEdit ] = useState<Attribute>();
const [ newAttribute, setNewAttribute ] = useState<Attribute>(); const newAttribute = useRef<Attribute>();
const [ newAttributePosition, setNewAttributePosition ] = useState<number>(); const newAttributePosition = useRef<number>();
useEffect(() => {
}, []);
useLegacyImperativeHandlers({ useLegacyImperativeHandlers({
addNewTableColumnCommand({ referenceColumn, columnToEdit, direction, type }: EventData<"addNewTableColumn">) { addNewTableColumnCommand({ referenceColumn, columnToEdit, direction, type }: EventData<"addNewTableColumn">) {
console.log("Ding");
let attr: Attribute | undefined; let attr: Attribute | undefined;
setExistingAttributeToEdit(undefined); setExistingAttributeToEdit(undefined);
if (columnToEdit) { if (columnToEdit) {
attr = this.getAttributeFromField(columnToEdit.getField()); attr = getAttributeFromField(parentNote, columnToEdit.getField());
if (attr) { if (attr) {
setExistingAttributeToEdit({ ...attr }); setExistingAttributeToEdit({ ...attr });
} }
@ -47,9 +43,9 @@ export default function useColTableEditing(api: RefObject<Tabulator>, attributeD
newPosition++; newPosition++;
} }
setNewAttributePosition(newPosition); newAttributePosition.current = newPosition;
} else { } else {
setNewAttributePosition(undefined); newAttributePosition.current = undefined;
} }
attributeDetailWidget.showAttributeDetail({ attributeDetailWidget.showAttributeDetail({
@ -63,26 +59,26 @@ export default function useColTableEditing(api: RefObject<Tabulator>, attributeD
}); });
}, },
async updateAttributeListCommand({ attributes }: CommandListenerData<"updateAttributeList">) { async updateAttributeListCommand({ attributes }: CommandListenerData<"updateAttributeList">) {
setNewAttribute(attributes[0]); newAttribute.current = attributes[0];
}, },
async saveAttributesCommand() { async saveAttributesCommand() {
if (!newAttribute || !api.current) { if (!newAttribute.current || !api.current) {
return; return;
} }
const { name, value, isInheritable } = newAttribute; const { name, value, isInheritable } = newAttribute.current;
api.current.blockRedraw(); api.current.blockRedraw();
const isRename = (this.existingAttributeToEdit && this.existingAttributeToEdit.name !== name); const isRename = (existingAttributeToEdit && existingAttributeToEdit.name !== name);
try { try {
if (isRename) { if (isRename) {
const oldName = this.existingAttributeToEdit!.name.split(":")[1]; const oldName = existingAttributeToEdit!.name.split(":")[1];
const [ type, newName ] = name.split(":"); const [ type, newName ] = name.split(":");
await renameColumn(parentNote.noteId, type as "label" | "relation", oldName, newName); await renameColumn(parentNote.noteId, type as "label" | "relation", oldName, newName);
} }
if (existingAttributeToEdit && (isRename || existingAttributeToEdit.isInheritable !== isInheritable)) { if (existingAttributeToEdit && (isRename || existingAttributeToEdit.isInheritable !== isInheritable)) {
attributes.removeOwnedLabelByName(parentNote, this.existingAttributeToEdit.name); attributes.removeOwnedLabelByName(parentNote, existingAttributeToEdit.name);
} }
attributes.setLabel(parentNote.noteId, name, value, isInheritable); attributes.setLabel(parentNote.noteId, name, value, isInheritable);
} finally { } finally {
@ -91,5 +87,5 @@ export default function useColTableEditing(api: RefObject<Tabulator>, attributeD
} }
}); });
return {}; return { newAttributePosition };
} }

View File

@ -15,7 +15,7 @@ import useRowTableEditing, { canReorderRows } from "./row_editing";
import useColTableEditing from "./col_editing"; import useColTableEditing from "./col_editing";
import AttributeDetailWidget from "../../attribute_widgets/attribute_detail"; import AttributeDetailWidget from "../../attribute_widgets/attribute_detail";
import attributes from "../../../services/attributes"; import attributes from "../../../services/attributes";
import { refreshTextDimensions } from "@excalidraw/excalidraw/element/newElement"; import { RefObject } from "preact";
interface TableConfig { interface TableConfig {
tableData?: { tableData?: {
@ -24,48 +24,15 @@ interface TableConfig {
} }
export default function TableView({ note, noteIds, notePath, viewConfig, saveConfig }: ViewModeProps<TableConfig>) { export default function TableView({ note, noteIds, notePath, viewConfig, saveConfig }: ViewModeProps<TableConfig>) {
const [ maxDepth ] = useNoteLabelInt(note, "maxNestingDepth") ?? -1;
const [ columnDefs, setColumnDefs ] = useState<ColumnDefinition[]>();
const [ rowData, setRowData ] = useState<TableData[]>();
const [ movableRows, setMovableRows ] = useState<boolean>();
const [ hasChildren, setHasChildren ] = useState<boolean>();
const tabulatorRef = useRef<VanillaTabulator>(null); const tabulatorRef = useRef<VanillaTabulator>(null);
const parentComponent = useContext(ParentComponent); const parentComponent = useContext(ParentComponent);
function refresh() {
const info = getAttributeDefinitionInformation(note);
buildRowDefinitions(note, info, maxDepth).then(({ definitions: rowData, hasSubtree: hasChildren, rowNumber }) => {
const movableRows = canReorderRows(note) && !hasChildren;
const columnDefs = buildColumnDefinitions({
info,
movableRows,
existingColumnData: viewConfig?.tableData?.columns,
rowNumberHint: rowNumber
});
setColumnDefs(columnDefs);
setRowData(rowData);
setMovableRows(movableRows);
setHasChildren(hasChildren);
});
}
useEffect(refresh, [ note, noteIds ]);
// React to column changes.
useTriliumEvent("entitiesReloaded", ({ loadResults}) => {
if (loadResults.getAttributeRows().find(attr =>
attr.type === "label" &&
(attr.name?.startsWith("label:") || attr.name?.startsWith("relation:")) &&
attributes.isAffecting(attr, note))) {
refresh();
}
});
const [ attributeDetailWidgetEl, attributeDetailWidget ] = useLegacyWidget(() => new AttributeDetailWidget().contentSized()); const [ attributeDetailWidgetEl, attributeDetailWidget ] = useLegacyWidget(() => new AttributeDetailWidget().contentSized());
const contextMenuEvents = useContextMenu(note, parentComponent, tabulatorRef); const contextMenuEvents = useContextMenu(note, parentComponent, tabulatorRef);
const persistenceProps = usePersistence(viewConfig, saveConfig); const persistenceProps = usePersistence(viewConfig, saveConfig);
const rowEditingEvents = useRowTableEditing(tabulatorRef, attributeDetailWidget, notePath); const rowEditingEvents = useRowTableEditing(tabulatorRef, attributeDetailWidget, notePath);
const colEditingEvents = useColTableEditing(tabulatorRef, attributeDetailWidget, note); const { newAttributePosition } = useColTableEditing(tabulatorRef, attributeDetailWidget, note);
const { columnDefs, rowData, movableRows, hasChildren } = useData(note, noteIds, viewConfig, newAttributePosition);
const dataTreeProps = useMemo<Options>(() => { const dataTreeProps = useMemo<Options>(() => {
if (!hasChildren) return {}; if (!hasChildren) return {};
return { return {
@ -92,8 +59,7 @@ export default function TableView({ note, noteIds, notePath, viewConfig, saveCon
footerElement={<TableFooter note={note} />} footerElement={<TableFooter note={note} />}
events={{ events={{
...contextMenuEvents, ...contextMenuEvents,
...rowEditingEvents, ...rowEditingEvents
...colEditingEvents
}} }}
persistence {...persistenceProps} persistence {...persistenceProps}
layout="fitDataFill" layout="fitDataFill"
@ -141,3 +107,44 @@ function usePersistence(initialConfig: TableConfig | null | undefined, saveConfi
}, []); }, []);
return { persistenceReaderFunc, persistenceWriterFunc }; return { persistenceReaderFunc, persistenceWriterFunc };
} }
function useData(note: FNote, noteIds: string[], viewConfig: TableConfig | undefined, newAttributePosition: RefObject<number | undefined>) {
const [ maxDepth ] = useNoteLabelInt(note, "maxNestingDepth") ?? -1;
const [ columnDefs, setColumnDefs ] = useState<ColumnDefinition[]>();
const [ rowData, setRowData ] = useState<TableData[]>();
const [ movableRows, setMovableRows ] = useState<boolean>();
const [ hasChildren, setHasChildren ] = useState<boolean>();
function refresh() {
const info = getAttributeDefinitionInformation(note);
buildRowDefinitions(note, info, maxDepth).then(({ definitions: rowData, hasSubtree: hasChildren, rowNumber }) => {
const movableRows = canReorderRows(note) && !hasChildren;
const columnDefs = buildColumnDefinitions({
info,
movableRows,
existingColumnData: viewConfig?.tableData?.columns,
rowNumberHint: rowNumber,
position: newAttributePosition.current ?? undefined
});
setColumnDefs(columnDefs);
setRowData(rowData);
setMovableRows(movableRows);
setHasChildren(hasChildren);
});
}
useEffect(refresh, [ note, noteIds ]);
// React to column changes.
useTriliumEvent("entitiesReloaded", ({ loadResults}) => {
if (loadResults.getAttributeRows().find(attr =>
attr.type === "label" &&
(attr.name?.startsWith("label:") || attr.name?.startsWith("relation:")) &&
attributes.isAffecting(attr, note))) {
refresh();
}
});
return { columnDefs, rowData, movableRows, hasChildren };
}

View File

@ -0,0 +1,21 @@
import FNote from "../../../entities/fnote";
import { Attribute } from "../../../services/attribute_parser";
export function getFAttributeFromField(parentNote: FNote, field: string) {
const [ type, name ] = field.split(".", 2);
const attrName = `${type.replace("s", "")}:${name}`;
return parentNote.getLabel(attrName);
}
export function getAttributeFromField(parentNote: FNote, field: string): Attribute | undefined {
const fAttribute = getFAttributeFromField(parentNote, field);
if (fAttribute) {
return {
name: fAttribute.name,
value: fAttribute.value,
type: fAttribute.type,
isInheritable: fAttribute.isInheritable
};
}
return undefined;
}

View File

@ -52,23 +52,6 @@ export default class TableColumnEditing extends Component {
this.existingAttributeToEdit = undefined; this.existingAttributeToEdit = undefined;
} }
getFAttributeFromField(field: string) {
const [ type, name ] = field.split(".", 2);
const attrName = `${type.replace("s", "")}:${name}`;
return this.parentNote.getLabel(attrName);
}
getAttributeFromField(field: string): Attribute | undefined {
const fAttribute = this.getFAttributeFromField(field);
if (fAttribute) {
return {
name: fAttribute.name,
value: fAttribute.value,
type: fAttribute.type,
isInheritable: fAttribute.isInheritable
};
}
return undefined;
}
} }

View File

@ -123,11 +123,7 @@ export default class TableView extends ViewMode<StateInfo> {
this.colEditing?.resetNewAttributePosition(); this.colEditing?.resetNewAttributePosition();
} }
addNewRowCommand(e) { this.rowEditing?.addNewRowCommand(e); }
addNewTableColumnCommand(e) { this.colEditing?.addNewTableColumnCommand(e); }
deleteTableColumnCommand(e) { this.colEditing?.deleteTableColumnCommand(e); } deleteTableColumnCommand(e) { this.colEditing?.deleteTableColumnCommand(e); }
updateAttributeListCommand(e) { this.colEditing?.updateAttributeListCommand(e); }
saveAttributesCommand() { this.colEditing?.saveAttributesCommand(); }
async #manageRowsUpdate() { async #manageRowsUpdate() {
if (!this.api) { if (!this.api) {