mirror of
https://github.com/zadam/trilium.git
synced 2025-11-01 03:59:05 +01:00
157 lines
4.5 KiB
TypeScript
157 lines
4.5 KiB
TypeScript
import { RelationEditor } from "./relation_editor.js";
|
|
import { MonospaceFormatter, NoteFormatter, NoteTitleFormatter, RowNumberFormatter } from "./formatters.js";
|
|
import type { ColumnDefinition } from "tabulator-tables";
|
|
import { LabelType } from "../../../services/promoted_attribute_definition_parser.js";
|
|
|
|
type ColumnType = LabelType | "relation";
|
|
|
|
export interface AttributeDefinitionInformation {
|
|
name: string;
|
|
title?: string;
|
|
type?: ColumnType;
|
|
}
|
|
|
|
const labelTypeMappings: Record<ColumnType, Partial<ColumnDefinition>> = {
|
|
text: {
|
|
editor: "input"
|
|
},
|
|
boolean: {
|
|
formatter: "tickCross",
|
|
editor: "tickCross"
|
|
},
|
|
date: {
|
|
editor: "date",
|
|
},
|
|
datetime: {
|
|
editor: "datetime"
|
|
},
|
|
number: {
|
|
editor: "number"
|
|
},
|
|
time: {
|
|
editor: "input"
|
|
},
|
|
url: {
|
|
formatter: "link",
|
|
editor: "input"
|
|
},
|
|
color: {
|
|
editor: "input",
|
|
formatter: "color",
|
|
editorParams: {
|
|
elementAttributes: {
|
|
type: "color"
|
|
}
|
|
}
|
|
},
|
|
relation: {
|
|
editor: RelationEditor,
|
|
formatter: NoteFormatter
|
|
}
|
|
};
|
|
|
|
interface BuildColumnArgs {
|
|
info: AttributeDefinitionInformation[];
|
|
movableRows: boolean;
|
|
existingColumnData: ColumnDefinition[] | undefined;
|
|
rowNumberHint: number;
|
|
position?: number;
|
|
}
|
|
|
|
export function buildColumnDefinitions({ info, movableRows, existingColumnData, rowNumberHint, position }: BuildColumnArgs) {
|
|
let columnDefs: ColumnDefinition[] = [
|
|
{
|
|
title: "#",
|
|
headerSort: false,
|
|
hozAlign: "center",
|
|
resizable: false,
|
|
frozen: true,
|
|
rowHandle: movableRows,
|
|
width: calculateIndexColumnWidth(rowNumberHint, movableRows),
|
|
formatter: RowNumberFormatter(movableRows)
|
|
},
|
|
{
|
|
field: "noteId",
|
|
title: "Note ID",
|
|
formatter: MonospaceFormatter,
|
|
visible: false
|
|
},
|
|
{
|
|
field: "title",
|
|
title: "Title",
|
|
editor: "input",
|
|
formatter: NoteTitleFormatter,
|
|
width: 400
|
|
}
|
|
];
|
|
|
|
const seenFields = new Set<string>();
|
|
for (const { name, title, type } of info) {
|
|
const prefix = (type === "relation" ? "relations" : "labels");
|
|
const field = `${prefix}.${name}`;
|
|
|
|
if (seenFields.has(field)) {
|
|
continue;
|
|
}
|
|
|
|
columnDefs.push({
|
|
field,
|
|
title: title ?? name,
|
|
editor: "input",
|
|
rowHandle: false,
|
|
...labelTypeMappings[type ?? "text"],
|
|
});
|
|
seenFields.add(field);
|
|
}
|
|
|
|
if (existingColumnData) {
|
|
columnDefs = restoreExistingData(columnDefs, existingColumnData, position);
|
|
}
|
|
|
|
return columnDefs;
|
|
}
|
|
|
|
export function restoreExistingData(newDefs: ColumnDefinition[], oldDefs: ColumnDefinition[], position?: number) {
|
|
// 1. Keep existing columns, but restore their properties like width, visibility and order.
|
|
const newItemsByField = new Map<string, ColumnDefinition>(
|
|
newDefs.map(def => [def.field!, def])
|
|
);
|
|
const existingColumns = oldDefs
|
|
.filter(item => (item.field && newItemsByField.has(item.field!)) || item.title === "#")
|
|
.map(oldItem => {
|
|
const data = newItemsByField.get(oldItem.field!)!;
|
|
if (oldItem.resizable !== false && oldItem.width !== undefined) {
|
|
data.width = oldItem.width;
|
|
}
|
|
if (oldItem.visible !== undefined) {
|
|
data.visible = oldItem.visible;
|
|
}
|
|
return data;
|
|
}) as ColumnDefinition[];
|
|
|
|
// 2. Determine new columns.
|
|
const existingFields = new Set(existingColumns.map(item => item.field));
|
|
const newColumns = newDefs
|
|
.filter(item => !existingFields.has(item.field!));
|
|
|
|
// Clamp position to a valid range
|
|
const insertPos = position !== undefined
|
|
? Math.min(Math.max(position, 0), existingColumns.length)
|
|
: existingColumns.length;
|
|
|
|
// 3. Insert new columns at the specified position
|
|
return [
|
|
...existingColumns.slice(0, insertPos),
|
|
...newColumns,
|
|
...existingColumns.slice(insertPos)
|
|
];
|
|
}
|
|
|
|
function calculateIndexColumnWidth(rowNumberHint: number, movableRows: boolean): number {
|
|
let columnWidth = 16 * (rowNumberHint.toString().length || 1);
|
|
if (movableRows) {
|
|
columnWidth += 32;
|
|
}
|
|
return columnWidth;
|
|
}
|