feat(book/table): store hidden columns

This commit is contained in:
Elian Doran
2025-06-25 16:18:34 +03:00
parent c7b16cd043
commit ccb9b7e5fb
7 changed files with 96 additions and 22 deletions

View File

@@ -109,24 +109,22 @@ const CALENDAR_VIEWS = [
"listMonth"
]
export default class CalendarView extends ViewMode {
export default class CalendarView extends ViewMode<{}> {
private $root: JQuery<HTMLElement>;
private $calendarContainer: JQuery<HTMLElement>;
private noteIds: string[];
private parentNote: FNote;
private calendar?: Calendar;
private isCalendarRoot: boolean;
private lastView?: string;
private debouncedSaveView?: DebouncedFunction<() => void>;
constructor(args: ViewModeArgs) {
super(args);
super(args, "calendar");
this.$root = $(TPL);
this.$calendarContainer = this.$root.find(".calendar-container");
this.noteIds = args.noteIds;
this.parentNote = args.parentNote;
this.isCalendarRoot = false;
args.$parent.append(this.$root);
}

View File

@@ -6,6 +6,7 @@ import treeService from "../../services/tree.js";
import utils from "../../services/utils.js";
import type FNote from "../../entities/fnote.js";
import ViewMode, { type ViewModeArgs } from "./view_mode.js";
import type { ViewTypeOptions } from "../../services/note_list_renderer.js";
const TPL = /*html*/`
<div class="note-list">
@@ -157,26 +158,22 @@ const TPL = /*html*/`
</div>
</div>`;
class ListOrGridView extends ViewMode {
class ListOrGridView extends ViewMode<{}> {
private $noteList: JQuery<HTMLElement>;
private parentNote: FNote;
private noteIds: string[];
private page?: number;
private pageSize?: number;
private viewType?: string | null;
private showNotePath?: boolean;
private highlightRegex?: RegExp | null;
/*
* We're using noteIds so that it's not necessary to load all notes at once when paging
*/
constructor(viewType: string, args: ViewModeArgs) {
super(args);
constructor(viewType: ViewTypeOptions, args: ViewModeArgs) {
super(args, viewType);
this.$noteList = $(TPL);
this.viewType = viewType;
this.parentNote = args.parentNote;
const includedNoteIds = this.getIncludedNoteIds();
this.noteIds = args.noteIds.filter((noteId) => !includedNoteIds.has(noteId) && noteId !== "_hidden");

View File

@@ -1,5 +1,6 @@
import froca from "../../services/froca.js";
import renderTable from "./table_view/renderer.js";
import type { StateInfo } from "./table_view/storage.js";
import ViewMode, { ViewModeArgs } from "./view_mode";
const TPL = /*html*/`
@@ -24,14 +25,14 @@ const TPL = /*html*/`
</div>
`;
export default class TableView extends ViewMode {
export default class TableView extends ViewMode<StateInfo> {
private $root: JQuery<HTMLElement>;
private $container: JQuery<HTMLElement>;
private args: ViewModeArgs;
constructor(args: ViewModeArgs) {
super(args);
super(args, "table");
this.$root = $(TPL);
this.$container = this.$root.find(".table-view-container");
@@ -48,7 +49,7 @@ export default class TableView extends ViewMode {
const notes = await froca.getNotes(noteIds);
this.$container.empty();
renderTable(this.$container[0], parentNote, notes);
renderTable(this.$container[0], parentNote, notes, this.viewStorage);
return this.$root;
}

View File

@@ -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 FNote from "../../../entities/fnote.js";
import getPromotedAttributeInformation, { PromotedAttributeInformation } from "./parser.js";
import getPromotedAttributeInformation from "./parser.js";
import { setLabel } from "../../../services/attributes.js";
import applyHeaderCustomization from "./header-customization.js";
import ViewModeStorage from "../view_mode_storage.js";
import { type StateInfo } from "./storage.js";
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 viewStorage = await storage.restore();
const initialState = viewStorage?.gridState;
createGrid(el, {
...buildData(info, notes),
...setupEditing(info),
onGridReady(event) {
...setupEditing(),
initialState,
async onGridReady(event) {
applyHeaderCustomization(el, event.api);
},
onStateUpdated(event) {
storage.store({
gridState: event.api.getState()
});
}
});
}
function setupEditing(info: PromotedAttributeInformation[]): GridOptions<TableData> {
function setupEditing(): GridOptions<TableData> {
return {
onCellValueChanged(event) {
if (event.type !== "cellValueChanged") {
@@ -37,3 +47,4 @@ function setupEditing(info: PromotedAttributeInformation[]): GridOptions<TableDa
}
}
}

View File

@@ -0,0 +1,6 @@
import { GridState } from "ag-grid-community";
export interface StateInfo {
gridState: GridState;
}

View File

@@ -1,5 +1,7 @@
import type { EventData } from "../../components/app_context.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 {
$parent: JQuery<HTMLElement>;
@@ -8,11 +10,18 @@ export interface ViewModeArgs {
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
args.$parent.empty();
this.viewType = viewType;
}
abstract renderList(): Promise<JQuery<HTMLElement> | undefined>;
@@ -32,4 +41,13 @@ export default abstract class ViewMode {
return false;
}
get viewStorage() {
if (this._viewStorage) {
return this._viewStorage;
}
this._viewStorage = new ViewModeStorage(this.parentNote, this.viewType);
return this._viewStorage;
}
}

View 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 ?? "{}");
}
}