mirror of
https://github.com/zadam/trilium.git
synced 2025-10-27 00:06:30 +01:00
feat(book/table): store hidden columns
This commit is contained in:
@@ -109,24 +109,22 @@ const CALENDAR_VIEWS = [
|
|||||||
"listMonth"
|
"listMonth"
|
||||||
]
|
]
|
||||||
|
|
||||||
export default class CalendarView extends ViewMode {
|
export default class CalendarView extends ViewMode<{}> {
|
||||||
|
|
||||||
private $root: JQuery<HTMLElement>;
|
private $root: JQuery<HTMLElement>;
|
||||||
private $calendarContainer: JQuery<HTMLElement>;
|
private $calendarContainer: JQuery<HTMLElement>;
|
||||||
private noteIds: string[];
|
private noteIds: string[];
|
||||||
private parentNote: FNote;
|
|
||||||
private calendar?: Calendar;
|
private calendar?: Calendar;
|
||||||
private isCalendarRoot: boolean;
|
private isCalendarRoot: boolean;
|
||||||
private lastView?: string;
|
private lastView?: string;
|
||||||
private debouncedSaveView?: DebouncedFunction<() => void>;
|
private debouncedSaveView?: DebouncedFunction<() => void>;
|
||||||
|
|
||||||
constructor(args: ViewModeArgs) {
|
constructor(args: ViewModeArgs) {
|
||||||
super(args);
|
super(args, "calendar");
|
||||||
|
|
||||||
this.$root = $(TPL);
|
this.$root = $(TPL);
|
||||||
this.$calendarContainer = this.$root.find(".calendar-container");
|
this.$calendarContainer = this.$root.find(".calendar-container");
|
||||||
this.noteIds = args.noteIds;
|
this.noteIds = args.noteIds;
|
||||||
this.parentNote = args.parentNote;
|
|
||||||
this.isCalendarRoot = false;
|
this.isCalendarRoot = false;
|
||||||
args.$parent.append(this.$root);
|
args.$parent.append(this.$root);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import treeService from "../../services/tree.js";
|
|||||||
import utils from "../../services/utils.js";
|
import utils from "../../services/utils.js";
|
||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
import ViewMode, { type ViewModeArgs } from "./view_mode.js";
|
import ViewMode, { type ViewModeArgs } from "./view_mode.js";
|
||||||
|
import type { ViewTypeOptions } from "../../services/note_list_renderer.js";
|
||||||
|
|
||||||
const TPL = /*html*/`
|
const TPL = /*html*/`
|
||||||
<div class="note-list">
|
<div class="note-list">
|
||||||
@@ -157,26 +158,22 @@ const TPL = /*html*/`
|
|||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
class ListOrGridView extends ViewMode {
|
class ListOrGridView extends ViewMode<{}> {
|
||||||
private $noteList: JQuery<HTMLElement>;
|
private $noteList: JQuery<HTMLElement>;
|
||||||
|
|
||||||
private parentNote: FNote;
|
|
||||||
private noteIds: string[];
|
private noteIds: string[];
|
||||||
private page?: number;
|
private page?: number;
|
||||||
private pageSize?: number;
|
private pageSize?: number;
|
||||||
private viewType?: string | null;
|
|
||||||
private showNotePath?: boolean;
|
private showNotePath?: boolean;
|
||||||
private highlightRegex?: RegExp | null;
|
private highlightRegex?: RegExp | null;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We're using noteIds so that it's not necessary to load all notes at once when paging
|
* We're using noteIds so that it's not necessary to load all notes at once when paging
|
||||||
*/
|
*/
|
||||||
constructor(viewType: string, args: ViewModeArgs) {
|
constructor(viewType: ViewTypeOptions, args: ViewModeArgs) {
|
||||||
super(args);
|
super(args, viewType);
|
||||||
this.$noteList = $(TPL);
|
this.$noteList = $(TPL);
|
||||||
this.viewType = viewType;
|
|
||||||
|
|
||||||
this.parentNote = args.parentNote;
|
|
||||||
const includedNoteIds = this.getIncludedNoteIds();
|
const includedNoteIds = this.getIncludedNoteIds();
|
||||||
|
|
||||||
this.noteIds = args.noteIds.filter((noteId) => !includedNoteIds.has(noteId) && noteId !== "_hidden");
|
this.noteIds = args.noteIds.filter((noteId) => !includedNoteIds.has(noteId) && noteId !== "_hidden");
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import froca from "../../services/froca.js";
|
import froca from "../../services/froca.js";
|
||||||
import renderTable from "./table_view/renderer.js";
|
import renderTable from "./table_view/renderer.js";
|
||||||
|
import type { StateInfo } from "./table_view/storage.js";
|
||||||
import ViewMode, { ViewModeArgs } from "./view_mode";
|
import ViewMode, { ViewModeArgs } from "./view_mode";
|
||||||
|
|
||||||
const TPL = /*html*/`
|
const TPL = /*html*/`
|
||||||
@@ -24,14 +25,14 @@ const TPL = /*html*/`
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default class TableView extends ViewMode {
|
export default class TableView extends ViewMode<StateInfo> {
|
||||||
|
|
||||||
private $root: JQuery<HTMLElement>;
|
private $root: JQuery<HTMLElement>;
|
||||||
private $container: JQuery<HTMLElement>;
|
private $container: JQuery<HTMLElement>;
|
||||||
private args: ViewModeArgs;
|
private args: ViewModeArgs;
|
||||||
|
|
||||||
constructor(args: ViewModeArgs) {
|
constructor(args: ViewModeArgs) {
|
||||||
super(args);
|
super(args, "table");
|
||||||
|
|
||||||
this.$root = $(TPL);
|
this.$root = $(TPL);
|
||||||
this.$container = this.$root.find(".table-view-container");
|
this.$container = this.$root.find(".table-view-container");
|
||||||
@@ -48,7 +49,7 @@ export default class TableView extends ViewMode {
|
|||||||
const notes = await froca.getNotes(noteIds);
|
const notes = await froca.getNotes(noteIds);
|
||||||
|
|
||||||
this.$container.empty();
|
this.$container.empty();
|
||||||
renderTable(this.$container[0], parentNote, notes);
|
renderTable(this.$container[0], parentNote, notes, this.viewStorage);
|
||||||
return this.$root;
|
return this.$root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,35 @@
|
|||||||
import { createGrid, AllCommunityModule, ModuleRegistry, columnDropStyleBordered, GridOptions } from "ag-grid-community";
|
import { createGrid, AllCommunityModule, ModuleRegistry, GridOptions } from "ag-grid-community";
|
||||||
import { buildData, type TableData } from "./data.js";
|
import { buildData, type TableData } from "./data.js";
|
||||||
import FNote from "../../../entities/fnote.js";
|
import FNote from "../../../entities/fnote.js";
|
||||||
import getPromotedAttributeInformation, { PromotedAttributeInformation } from "./parser.js";
|
import getPromotedAttributeInformation from "./parser.js";
|
||||||
import { setLabel } from "../../../services/attributes.js";
|
import { setLabel } from "../../../services/attributes.js";
|
||||||
import applyHeaderCustomization from "./header-customization.js";
|
import applyHeaderCustomization from "./header-customization.js";
|
||||||
|
import ViewModeStorage from "../view_mode_storage.js";
|
||||||
|
import { type StateInfo } from "./storage.js";
|
||||||
|
|
||||||
ModuleRegistry.registerModules([ AllCommunityModule ]);
|
ModuleRegistry.registerModules([ AllCommunityModule ]);
|
||||||
|
|
||||||
export default function renderTable(el: HTMLElement, parentNote: FNote, notes: FNote[]) {
|
export default async function renderTable(el: HTMLElement, parentNote: FNote, notes: FNote[], storage: ViewModeStorage<StateInfo>) {
|
||||||
const info = getPromotedAttributeInformation(parentNote);
|
const info = getPromotedAttributeInformation(parentNote);
|
||||||
|
const viewStorage = await storage.restore();
|
||||||
|
const initialState = viewStorage?.gridState;
|
||||||
|
|
||||||
createGrid(el, {
|
createGrid(el, {
|
||||||
...buildData(info, notes),
|
...buildData(info, notes),
|
||||||
...setupEditing(info),
|
...setupEditing(),
|
||||||
onGridReady(event) {
|
initialState,
|
||||||
|
async onGridReady(event) {
|
||||||
applyHeaderCustomization(el, event.api);
|
applyHeaderCustomization(el, event.api);
|
||||||
},
|
},
|
||||||
|
onStateUpdated(event) {
|
||||||
|
storage.store({
|
||||||
|
gridState: event.api.getState()
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupEditing(info: PromotedAttributeInformation[]): GridOptions<TableData> {
|
function setupEditing(): GridOptions<TableData> {
|
||||||
return {
|
return {
|
||||||
onCellValueChanged(event) {
|
onCellValueChanged(event) {
|
||||||
if (event.type !== "cellValueChanged") {
|
if (event.type !== "cellValueChanged") {
|
||||||
@@ -37,3 +47,4 @@ function setupEditing(info: PromotedAttributeInformation[]): GridOptions<TableDa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { GridState } from "ag-grid-community";
|
||||||
|
|
||||||
|
export interface StateInfo {
|
||||||
|
gridState: GridState;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { EventData } from "../../components/app_context.js";
|
import type { EventData } from "../../components/app_context.js";
|
||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
|
import type { ViewTypeOptions } from "../../services/note_list_renderer.js";
|
||||||
|
import ViewModeStorage from "./view_mode_storage.js";
|
||||||
|
|
||||||
export interface ViewModeArgs {
|
export interface ViewModeArgs {
|
||||||
$parent: JQuery<HTMLElement>;
|
$parent: JQuery<HTMLElement>;
|
||||||
@@ -8,11 +10,18 @@ export interface ViewModeArgs {
|
|||||||
showNotePath?: boolean;
|
showNotePath?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default abstract class ViewMode {
|
export default abstract class ViewMode<T extends object> {
|
||||||
|
|
||||||
constructor(args: ViewModeArgs) {
|
private _viewStorage: ViewModeStorage<T> | null;
|
||||||
|
protected parentNote: FNote;
|
||||||
|
protected viewType: ViewTypeOptions;
|
||||||
|
|
||||||
|
constructor(args: ViewModeArgs, viewType: ViewTypeOptions) {
|
||||||
|
this.parentNote = args.parentNote;
|
||||||
|
this._viewStorage = null;
|
||||||
// note list must be added to the DOM immediately, otherwise some functionality scripting (canvas) won't work
|
// note list must be added to the DOM immediately, otherwise some functionality scripting (canvas) won't work
|
||||||
args.$parent.empty();
|
args.$parent.empty();
|
||||||
|
this.viewType = viewType;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract renderList(): Promise<JQuery<HTMLElement> | undefined>;
|
abstract renderList(): Promise<JQuery<HTMLElement> | undefined>;
|
||||||
@@ -32,4 +41,13 @@ export default abstract class ViewMode {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get viewStorage() {
|
||||||
|
if (this._viewStorage) {
|
||||||
|
return this._viewStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._viewStorage = new ViewModeStorage(this.parentNote, this.viewType);
|
||||||
|
return this._viewStorage;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
43
apps/client/src/widgets/view_widgets/view_mode_storage.ts
Normal file
43
apps/client/src/widgets/view_widgets/view_mode_storage.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import type FNote from "../../entities/fnote";
|
||||||
|
import type { ViewTypeOptions } from "../../services/note_list_renderer";
|
||||||
|
import server from "../../services/server";
|
||||||
|
|
||||||
|
const ATTACHMENT_ROLE = "viewConfig";
|
||||||
|
|
||||||
|
export default class ViewModeStorage<T extends object> {
|
||||||
|
|
||||||
|
private note: FNote;
|
||||||
|
private attachmentName: string;
|
||||||
|
|
||||||
|
constructor(note: FNote, viewType: ViewTypeOptions) {
|
||||||
|
this.note = note;
|
||||||
|
this.attachmentName = viewType + ".json";
|
||||||
|
}
|
||||||
|
|
||||||
|
async store(data: T) {
|
||||||
|
const payload = {
|
||||||
|
role: ATTACHMENT_ROLE,
|
||||||
|
title: this.attachmentName,
|
||||||
|
mime: "application/json",
|
||||||
|
content: JSON.stringify(data),
|
||||||
|
position: 0
|
||||||
|
};
|
||||||
|
await server.post(`notes/${this.note.noteId}/attachments?matchBy=title`, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
async restore() {
|
||||||
|
const existingAttachments = await this.note.getAttachmentsByRole(ATTACHMENT_ROLE);
|
||||||
|
if (existingAttachments.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachment = existingAttachments
|
||||||
|
.find(a => a.title === this.attachmentName);
|
||||||
|
if (!attachment) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachmentData = await server.get<{ content: string } | null>(`attachments/${attachment.attachmentId}/blob`);
|
||||||
|
return JSON.parse(attachmentData?.content ?? "{}");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user