Files
Trilium/apps/client/src/widgets/view_widgets/table_view/index.ts

163 lines
4.7 KiB
TypeScript
Raw Normal View History

import froca from "../../../services/froca.js";
import ViewMode, { type ViewModeArgs } from "../view_mode.js";
import { createGrid, AllCommunityModule, ModuleRegistry, GridOptions } from "ag-grid-community";
import { setLabel } from "../../../services/attributes.js";
import getPromotedAttributeInformation, { buildData, TableData } from "./data.js";
import applyHeaderCustomization from "./header-customization.js";
import server from "../../../services/server.js";
2025-06-27 17:58:25 +03:00
import type { GridApi, GridState } from "ag-grid-community";
import SpacedUpdate from "../../../services/spaced_update.js";
2025-06-27 19:53:40 +03:00
import branches from "../../../services/branches.js";
2025-06-25 10:31:41 +03:00
const TPL = /*html*/`
<div class="table-view">
2025-06-25 10:40:04 +03:00
<style>
.table-view {
overflow: hidden;
position: relative;
height: 100%;
user-select: none;
padding: 10px;
}
2025-06-25 10:49:33 +03:00
.table-view-container {
height: 100%;
}
2025-06-27 17:18:52 +03:00
.search-result-widget-content .table-view {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
2025-06-25 10:40:04 +03:00
</style>
<div class="table-view-container"></div>
2025-06-25 10:31:41 +03:00
</div>
`;
export interface StateInfo {
gridState: GridState;
}
2025-06-25 16:18:34 +03:00
export default class TableView extends ViewMode<StateInfo> {
2025-06-25 10:31:41 +03:00
private $root: JQuery<HTMLElement>;
2025-06-25 10:49:33 +03:00
private $container: JQuery<HTMLElement>;
private args: ViewModeArgs;
2025-06-27 17:58:25 +03:00
private spacedUpdate: SpacedUpdate;
private api?: GridApi;
2025-06-25 10:31:41 +03:00
constructor(args: ViewModeArgs) {
2025-06-25 16:18:34 +03:00
super(args, "table");
2025-06-25 10:31:41 +03:00
this.$root = $(TPL);
2025-06-25 10:49:33 +03:00
this.$container = this.$root.find(".table-view-container");
this.args = args;
2025-06-27 17:58:25 +03:00
this.spacedUpdate = new SpacedUpdate(() => this.onSave(), 5_000);
2025-06-25 10:31:41 +03:00
args.$parent.append(this.$root);
ModuleRegistry.registerModules([ AllCommunityModule ]);
2025-06-25 10:31:41 +03:00
}
2025-06-25 10:40:04 +03:00
get isFullHeight(): boolean {
return true;
}
2025-06-25 10:31:41 +03:00
async renderList() {
this.$container.empty();
this.renderTable(this.$container[0]);
return this.$root;
}
private async renderTable(el: HTMLElement) {
const { noteIds, parentNote } = this.args;
const notes = await froca.getNotes(noteIds);
2025-06-25 11:03:43 +03:00
const info = getPromotedAttributeInformation(parentNote);
const viewStorage = await this.viewStorage.restore();
const initialState = viewStorage?.gridState;
2025-06-27 17:58:25 +03:00
this.api = createGrid(el, {
2025-06-27 19:53:40 +03:00
...buildData(parentNote, info, notes),
...this.setupEditing(),
...this.setupDragging(),
initialState,
async onGridReady(event) {
applyHeaderCustomization(el, event.api);
},
2025-06-27 17:58:25 +03:00
onStateUpdated: () => this.spacedUpdate.scheduleUpdate()
});
}
private onSave() {
if (!this.api) {
return;
}
this.viewStorage.store({
gridState: this.api.getState()
});
2025-06-25 10:31:41 +03:00
}
private setupEditing(): GridOptions<TableData> {
return {
onCellValueChanged(event) {
if (event.type !== "cellValueChanged") {
return;
}
const noteId = event.data.noteId;
const name = event.colDef.field;
if (!name) {
return;
}
const { newValue } = event;
if (name === "title") {
// TODO: Deduplicate with note_title.
server.put(`notes/${noteId}/title`, { title: newValue });
}
if (name.startsWith("labels.")) {
const labelName = name.split(".", 2)[1];
setLabel(noteId, labelName, newValue);
}
}
}
}
2025-06-27 19:53:40 +03:00
private setupDragging() {
if (this.parentNote.hasLabel("sorted")) {
return {};
}
2025-06-27 19:53:40 +03:00
const config: GridOptions<TableData> = {
rowDragEntireRow: true,
onRowDragEnd(e) {
const fromIndex = e.node.rowIndex;
const toIndex = e.overNode?.rowIndex;
if (fromIndex === null || toIndex === null || toIndex === undefined || fromIndex === toIndex) {
return;
}
const isBelow = (toIndex > fromIndex);
const fromBranchId = e.node.data?.branchId;
const toBranchId = e.overNode?.data?.branchId;
if (fromBranchId === undefined || toBranchId === undefined) {
return;
}
if (isBelow) {
branches.moveAfterBranch([ fromBranchId ], toBranchId);
} else {
branches.moveBeforeBranch([ fromBranchId ], toBranchId);
}
2025-06-27 19:53:40 +03:00
}
};
return config;
}
2025-06-27 19:53:40 +03:00
}