feat(views/table): basic implementation for inserting columns at position

This commit is contained in:
Elian Doran
2025-07-14 19:14:10 +03:00
parent d4a4f15416
commit 2d4ac93221
3 changed files with 47 additions and 13 deletions

View File

@@ -41,8 +41,8 @@ const labelTypeMappings: Record<ColumnType, Partial<ColumnDefinition>> = {
} }
}; };
export function buildColumnDefinitions(info: AttributeDefinitionInformation[], movableRows: boolean, existingColumnData?: ColumnDefinition[]) { export function buildColumnDefinitions(info: AttributeDefinitionInformation[], movableRows: boolean, existingColumnData?: ColumnDefinition[], position?: number) {
const columnDefs: ColumnDefinition[] = [ let columnDefs: ColumnDefinition[] = [
{ {
title: "#", title: "#",
headerSort: false, headerSort: false,
@@ -86,25 +86,40 @@ export function buildColumnDefinitions(info: AttributeDefinitionInformation[], m
} }
if (existingColumnData) { if (existingColumnData) {
restoreExistingData(columnDefs, existingColumnData); columnDefs = restoreExistingData(columnDefs, existingColumnData, position);
} }
return columnDefs; return columnDefs;
} }
function restoreExistingData(newDefs: ColumnDefinition[], oldDefs: ColumnDefinition[]) { function restoreExistingData(newDefs: ColumnDefinition[], oldDefs: ColumnDefinition[], position?: number) {
const byField = new Map<string, ColumnDefinition>; const byField = new Map<string, ColumnDefinition>;
for (const def of oldDefs) { for (const def of oldDefs) {
byField.set(def.field ?? "", def); byField.set(def.field ?? "", def);
} }
const newColumns: ColumnDefinition[] = [];
const existingColumns: ColumnDefinition[] = []
for (const newDef of newDefs) { for (const newDef of newDefs) {
const oldDef = byField.get(newDef.field ?? ""); const oldDef = byField.get(newDef.field ?? "");
if (!oldDef) { if (!oldDef) {
continue; newColumns.push(newDef);
} } else {
newDef.width = oldDef.width; newDef.width = oldDef.width;
newDef.visible = oldDef.visible; newDef.visible = oldDef.visible;
existingColumns.push(newDef);
} }
}
// Clamp position to a valid range
const insertPos = position !== undefined
? Math.min(Math.max(position, 0), existingColumns.length)
: existingColumns.length;
// Insert new columns at the specified position
return [
...existingColumns.slice(0, insertPos),
...newColumns,
...existingColumns.slice(insertPos)
];
} }

View File

@@ -78,6 +78,16 @@ function showColumnContextMenu(_e: UIEvent, column: ColumnComponent, tabulator:
uiIcon: "bx bx-empty", uiIcon: "bx bx-empty",
items: buildColumnItems() items: buildColumnItems()
}, },
{ title: "----" },
{
title: "Add column to the left",
handler: () => {
getParentComponent(e)?.triggerCommand("addNoteListItem", {
referenceColumn: column
});
console.log("Add col");
}
}
], ],
selectMenuItemHandler() {}, selectMenuItemHandler() {},
x: e.pageX, x: e.pageX,

View File

@@ -6,7 +6,7 @@ import SpacedUpdate from "../../../services/spaced_update.js";
import type { CommandListenerData, EventData } from "../../../components/app_context.js"; import type { CommandListenerData, EventData } from "../../../components/app_context.js";
import type { Attribute } from "../../../services/attribute_parser.js"; import type { Attribute } from "../../../services/attribute_parser.js";
import note_create, { CreateNoteOpts } from "../../../services/note_create.js"; import note_create, { CreateNoteOpts } from "../../../services/note_create.js";
import {Tabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, ColumnDefinition, DataTreeModule, Options, RowComponent} from 'tabulator-tables'; import {Tabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, ColumnDefinition, DataTreeModule, Options, RowComponent, ColumnComponent} from 'tabulator-tables';
import "tabulator-tables/dist/css/tabulator.css"; import "tabulator-tables/dist/css/tabulator.css";
import "../../../../src/stylesheets/table.css"; import "../../../../src/stylesheets/table.css";
import { canReorderRows, configureReorderingRows } from "./dragging.js"; import { canReorderRows, configureReorderingRows } from "./dragging.js";
@@ -105,10 +105,10 @@ export default class TableView extends ViewMode<StateInfo> {
private spacedUpdate: SpacedUpdate; private spacedUpdate: SpacedUpdate;
private api?: Tabulator; private api?: Tabulator;
private newAttribute?: Attribute; private newAttribute?: Attribute;
private newAttributePosition?: number;
private persistentData: StateInfo["tableData"]; private persistentData: StateInfo["tableData"];
private attributeDetailWidget: AttributeDetailWidget; private attributeDetailWidget: AttributeDetailWidget;
constructor(args: ViewModeArgs) { constructor(args: ViewModeArgs) {
super(args, "table"); super(args, "table");
@@ -234,13 +234,20 @@ export default class TableView extends ViewMode<StateInfo> {
console.log("Save attributes", this.newAttribute); console.log("Save attributes", this.newAttribute);
} }
addNoteListItemEvent() { addNoteListItemEvent({ referenceColumn }: { referenceColumn?: ColumnComponent }) {
console.log("Add note list item ", referenceColumn);
const attr: Attribute = { const attr: Attribute = {
type: "label", type: "label",
name: "label:myLabel", name: "label:myLabel",
value: "promoted,single,text" value: "promoted,single,text"
}; };
if (referenceColumn && this.api) {
this.newAttributePosition = this.api.getColumns().indexOf(referenceColumn) - 1;
} else {
this.newAttributePosition = undefined;
}
this.attributeDetailWidget!.showAttributeDetail({ this.attributeDetailWidget!.showAttributeDetail({
attribute: attr, attribute: attr,
allAttributes: [ attr ], allAttributes: [ attr ],
@@ -274,7 +281,7 @@ export default class TableView extends ViewMode<StateInfo> {
} }
// Force a refresh if sorted is changed since we need to disable reordering. // Force a refresh if sorted is changed since we need to disable reordering.
if (loadResults.getAttributeRows().find(a => attributes.isAffecting(a, this.parentNote))) { if (loadResults.getAttributeRows().find(a => a.name === "sorted" && attributes.isAffecting(a, this.parentNote))) {
return true; return true;
} }
@@ -283,6 +290,7 @@ export default class TableView extends ViewMode<StateInfo> {
attr.type === "label" && attr.type === "label" &&
(attr.name?.startsWith("label:") || attr.name?.startsWith("relation:")) && (attr.name?.startsWith("label:") || attr.name?.startsWith("relation:")) &&
attributes.isAffecting(attr, this.parentNote))) { attributes.isAffecting(attr, this.parentNote))) {
console.log("Col update");
this.#manageColumnUpdate(); this.#manageColumnUpdate();
} }
@@ -301,8 +309,9 @@ export default class TableView extends ViewMode<StateInfo> {
} }
const info = getAttributeDefinitionInformation(this.parentNote); const info = getAttributeDefinitionInformation(this.parentNote);
const columnDefs = buildColumnDefinitions(info, !!this.api.options.movableRows, this.persistentData?.columns); const columnDefs = buildColumnDefinitions(info, !!this.api.options.movableRows, this.persistentData?.columns, this.newAttributePosition);
this.api.setColumns(columnDefs); this.api.setColumns(columnDefs);
this.newAttributePosition = undefined;
} }
async #manageRowsUpdate() { async #manageRowsUpdate() {