implement view persistence class to prevent junk subscriptions

This commit is contained in:
marlon-erler
2026-04-13 22:11:49 +00:00
parent 79f4a26f23
commit 19b4d51974
8 changed files with 108 additions and 30 deletions
+57 -18
View File
@@ -1,10 +1,9 @@
(() => { (() => {
// node_modules/bloatless-react/index.ts // ../../bloatless-react/index.ts
var State = class { var State = class {
_value;
_bindings = /* @__PURE__ */ new Set();
// init // init
constructor(initialValue) { constructor(initialValue) {
this._bindings = /* @__PURE__ */ new Set();
this._value = initialValue; this._value = initialValue;
} }
// value // value
@@ -32,15 +31,16 @@
} }
}; };
var ListState = class extends State { var ListState = class extends State {
additionHandlers = /* @__PURE__ */ new Set();
removalHandlers = /* @__PURE__ */ new Map();
// init // init
constructor(initialItems) { constructor(initialItems) {
super(new Set(initialItems)); super(new Set(initialItems));
this.additionHandlers = /* @__PURE__ */ new Set();
this.removalHandlers = /* @__PURE__ */ new Map();
} }
// list // list
add(...items) { add(...items) {
items.forEach((item) => { items.forEach((item) => {
if (this.value.has(item)) return;
this.value.add(item); this.value.add(item);
this.additionHandlers.forEach((handler) => handler(item)); this.additionHandlers.forEach((handler) => handler(item));
}); });
@@ -76,11 +76,11 @@
} }
}; };
var MapState = class extends State { var MapState = class extends State {
additionHandlers = /* @__PURE__ */ new Set();
removalHandlers = /* @__PURE__ */ new Map();
// init // init
constructor(initialItems) { constructor(initialItems) {
super(new Map(initialItems)); super(new Map(initialItems));
this.additionHandlers = /* @__PURE__ */ new Set();
this.removalHandlers = /* @__PURE__ */ new Map();
} }
// list // list
set(key, item) { set(key, item) {
@@ -350,7 +350,6 @@
// manage // manage
this.setHandler = (id, handler) => { this.setHandler = (id, handler) => {
this.handlers.set(id, handler); this.handlers.set(id, handler);
console.log(this.handlers.size);
}; };
this.deleteHandler = (id) => { this.deleteHandler = (id) => {
this.handlers.delete(id); this.handlers.delete(id);
@@ -3301,7 +3300,7 @@
this.boardInfo.fileId this.boardInfo.fileId
); );
for (const taskId of taskIds) { for (const taskId of taskIds) {
if (this.taskViewModels.value.has(taskId)) return; if (this.taskViewModels.value.has(taskId)) continue;
const taskFileContent = this.boardsAndTasksModel.getLatestTaskFileContent(taskId); const taskFileContent = this.boardsAndTasksModel.getLatestTaskFileContent(taskId);
if (taskFileContent == null) continue; if (taskFileContent == null) continue;
const taskViewModel = new TaskViewModel( const taskViewModel = new TaskViewModel(
@@ -3481,7 +3480,6 @@
}; };
// load // load
this.loadData = () => { this.loadData = () => {
console.log("LOADING TASK PAGE DATA");
this.closeContext(); this.closeContext();
this.boardViewModels.clear(); this.boardViewModels.clear();
const boardIds = this.boardsAndTasksModel.listBoardIds(); const boardIds = this.boardsAndTasksModel.listBoardIds();
@@ -5189,10 +5187,49 @@
)), /* @__PURE__ */ createElement("button", { "on:click": close }, coreViewModel2.translations.general.closeButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "close")))); )), /* @__PURE__ */ createElement("button", { "on:click": close }, coreViewModel2.translations.general.closeButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "close"))));
} }
// src/View/viewPersistence.ts
var PageTracker = class {
};
var PageTrackerMap = class {
constructor() {
this.trackers = /* @__PURE__ */ new Map();
this.register = (key) => {
if (this.trackers.has(key)) {
return this.trackers.get(key);
}
;
const tracker = new PageTracker();
this.trackers.set(key, tracker);
return tracker;
};
this.setPages = (key, pages) => {
const tracker = this.register(key);
if (tracker.pages != void 0) {
return tracker.pages;
} else {
tracker.pages = pages();
return tracker.pages;
}
};
}
};
var ViewPersistence = class {
static {
this.chatPages = new PageTracker();
}
static {
this.taskPages = new PageTrackerMap();
}
static {
this.boardPages = new PageTrackerMap();
}
};
// src/View/ChatPages/boardPage.tsx // src/View/ChatPages/boardPage.tsx
function BoardPage(coreViewModel2, boardViewModel) { function BoardPage(coreViewModel2, boardViewModel) {
boardViewModel.loadData(); boardViewModel.loadData();
const mainContent = createProxyState( const persistenceId = boardViewModel.boardInfo.fileId;
const pages = ViewPersistence.boardPages.setPages(persistenceId, () => createProxyState(
[boardViewModel.selectedPage], [boardViewModel.selectedPage],
() => { () => {
switch (boardViewModel.selectedPage.value) { switch (boardViewModel.selectedPage.value) {
@@ -5216,7 +5253,7 @@
} }
} }
} }
); ));
const taskSettingsModal = createProxyState( const taskSettingsModal = createProxyState(
[boardViewModel.selectedTaskViewModel], [boardViewModel.selectedTaskViewModel],
() => { () => {
@@ -5288,7 +5325,7 @@
"on:click": boardViewModel.createTask "on:click": boardViewModel.createTask
}, },
/* @__PURE__ */ createElement("span", { class: "icon" }, "add") /* @__PURE__ */ createElement("span", { class: "icon" }, "add")
))), /* @__PURE__ */ createElement("div", { class: "content main-content", "children:set": mainContent }), BoardSettingsModal(coreViewModel2, boardViewModel), SearchModal( ))), /* @__PURE__ */ createElement("div", { class: "content main-content", "children:set": pages }), BoardSettingsModal(coreViewModel2, boardViewModel), SearchModal(
coreViewModel2, coreViewModel2,
boardViewModel.searchViewModel, boardViewModel.searchViewModel,
coreViewModel2.translations.chatPage.task.filterTasksHeadline, coreViewModel2.translations.chatPage.task.filterTasksHeadline,
@@ -5334,7 +5371,8 @@
[taskPageViewModel.selectedBoardId], [taskPageViewModel.selectedBoardId],
() => taskPageViewModel.selectedBoardId.value != void 0 () => taskPageViewModel.selectedBoardId.value != void 0
); );
const paneContent = createProxyState( const persistenceId = taskPageViewModel.chatViewModel.chatModel.id;
const pages = ViewPersistence.taskPages.setPages(persistenceId, () => createProxyState(
[taskPageViewModel.selectedBoardId], [taskPageViewModel.selectedBoardId],
() => { () => {
const selectedBoardId = taskPageViewModel.selectedBoardId.value; const selectedBoardId = taskPageViewModel.selectedBoardId.value;
@@ -5347,9 +5385,10 @@
if (selectedBoard == void 0) { if (selectedBoard == void 0) {
return /* @__PURE__ */ createElement("div", { class: "pane align-center justify-center" }, /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.chatPage.task.boardNotFound)); return /* @__PURE__ */ createElement("div", { class: "pane align-center justify-center" }, /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.chatPage.task.boardNotFound));
} }
console.log("BOARD PAGE");
return BoardPage(coreViewModel2, selectedBoard); return BoardPage(coreViewModel2, selectedBoard);
} }
); ));
return /* @__PURE__ */ createElement( return /* @__PURE__ */ createElement(
"div", "div",
{ {
@@ -5398,7 +5437,7 @@
{ {
id: "board-content", id: "board-content",
class: "pane-wrapper", class: "pane-wrapper",
"children:set": paneContent "children:set": pages
} }
) )
); );
@@ -5406,7 +5445,7 @@
// src/View/chatPage.tsx // src/View/chatPage.tsx
function ChatPage(coreViewModel2, chatViewModel) { function ChatPage(coreViewModel2, chatViewModel) {
const mainContent = createProxyState( ViewPersistence.chatPages.pages = createProxyState(
[chatViewModel.selectedPage], [chatViewModel.selectedPage],
() => { () => {
switch (chatViewModel.selectedPage.value) { switch (chatViewModel.selectedPage.value) {
@@ -5497,7 +5536,7 @@
"settings", "settings",
"settings" /* Settings */, "settings" /* Settings */,
chatViewModel chatViewModel
))), /* @__PURE__ */ createElement("div", { id: "main", "children:set": mainContent })) ))), /* @__PURE__ */ createElement("div", { id: "main", "children:set": ViewPersistence.chatPages.pages }))
); );
} }
+5 -3
View File
@@ -13,6 +13,7 @@ import { TaskSettingsModal } from "../Modals/taskSettingsModal";
import { TaskViewModelToEntry } from "../Components/taskEntry"; import { TaskViewModelToEntry } from "../Components/taskEntry";
import { setFocusWithDelay } from "../utility"; import { setFocusWithDelay } from "../utility";
import CoreViewModel from "../../ViewModel/Global/coreViewModel"; import CoreViewModel from "../../ViewModel/Global/coreViewModel";
import { ViewPersistence } from "../viewPersistence";
export function BoardPage( export function BoardPage(
coreViewModel: CoreViewModel, coreViewModel: CoreViewModel,
@@ -21,7 +22,8 @@ export function BoardPage(
boardViewModel.loadData(); boardViewModel.loadData();
// main content // main content
const mainContent = React.createProxyState( const persistenceId = boardViewModel.boardInfo.fileId;
const pages = ViewPersistence.boardPages.setPages(persistenceId, ()=>React.createProxyState(
[boardViewModel.selectedPage], [boardViewModel.selectedPage],
() => { () => {
switch (boardViewModel.selectedPage.value) { switch (boardViewModel.selectedPage.value) {
@@ -44,7 +46,7 @@ export function BoardPage(
} }
} }
}, },
); ));
// task modal // task modal
const taskSettingsModal = React.createProxyState( const taskSettingsModal = React.createProxyState(
@@ -150,7 +152,7 @@ export function BoardPage(
</button> </button>
</span> </span>
</div> </div>
<div class="content main-content" children:set={mainContent}></div> <div class="content main-content" children:set={pages}></div>
{BoardSettingsModal(coreViewModel, boardViewModel)} {BoardSettingsModal(coreViewModel, boardViewModel)}
{SearchModal( {SearchModal(
+6 -3
View File
@@ -7,6 +7,8 @@ import { BoardViewModelToEntry } from "../Components/boardEntry";
import TaskPageViewModel from "../../ViewModel/Pages/taskPageViewModel"; import TaskPageViewModel from "../../ViewModel/Pages/taskPageViewModel";
import CoreViewModel from "../../ViewModel/Global/coreViewModel"; import CoreViewModel from "../../ViewModel/Global/coreViewModel";
import { PlaceholderView } from "../Components/placeholderView"; import { PlaceholderView } from "../Components/placeholderView";
import { v4 } from "uuid";
import { ViewPersistence } from "../viewPersistence";
export function TaskPage( export function TaskPage(
coreViewModel: CoreViewModel, coreViewModel: CoreViewModel,
@@ -19,7 +21,8 @@ export function TaskPage(
() => taskPageViewModel.selectedBoardId.value != undefined, () => taskPageViewModel.selectedBoardId.value != undefined,
); );
const paneContent = React.createProxyState( const persistenceId = taskPageViewModel.chatViewModel.chatModel.id;
const pages = ViewPersistence.taskPages.setPages(persistenceId, ()=>React.createProxyState(
[taskPageViewModel.selectedBoardId], [taskPageViewModel.selectedBoardId],
() => { () => {
const selectedBoardId = taskPageViewModel.selectedBoardId.value; const selectedBoardId = taskPageViewModel.selectedBoardId.value;
@@ -45,7 +48,7 @@ export function TaskPage(
return BoardPage(coreViewModel, selectedBoard); return BoardPage(coreViewModel, selectedBoard);
}, },
); ));
return ( return (
<div <div
@@ -100,7 +103,7 @@ export function TaskPage(
<div <div
id="board-content" id="board-content"
class="pane-wrapper" class="pane-wrapper"
children:set={paneContent} children:set={pages}
></div> ></div>
</div> </div>
); );
+3 -2
View File
@@ -10,12 +10,13 @@ import { MessagePage } from "./ChatPages/messagePage";
import { SettingsPage } from "./ChatPages/settingsPage"; import { SettingsPage } from "./ChatPages/settingsPage";
import { TaskPage } from "./ChatPages/taskPage"; import { TaskPage } from "./ChatPages/taskPage";
import CoreViewModel from "../ViewModel/Global/coreViewModel"; import CoreViewModel from "../ViewModel/Global/coreViewModel";
import { ViewPersistence } from "./viewPersistence";
export function ChatPage( export function ChatPage(
coreViewModel: CoreViewModel, coreViewModel: CoreViewModel,
chatViewModel: ChatViewModel, chatViewModel: ChatViewModel,
) { ) {
const mainContent = React.createProxyState( ViewPersistence.chatPages.pages = React.createProxyState(
[chatViewModel.selectedPage], [chatViewModel.selectedPage],
() => { () => {
switch (chatViewModel.selectedPage.value) { switch (chatViewModel.selectedPage.value) {
@@ -129,7 +130,7 @@ export function ChatPage(
)} )}
</span> </span>
</div> </div>
<div id="main" children:set={mainContent}></div> <div id="main" children:set={ViewPersistence.chatPages.pages}></div>
</div> </div>
</article> </article>
); );
+35
View File
@@ -0,0 +1,35 @@
import * as React from "bloatless-react";
class PageTracker {
pages: React.State<HTMLElement | undefined> | undefined;
}
class PageTrackerMap {
trackers = new Map<string, PageTracker>();
private register = (key: string): PageTracker => {
if (this.trackers.has(key)) {
return this.trackers.get(key);
};
const tracker = new PageTracker();
this.trackers.set(key, tracker);
return tracker
}
setPages = (key: string, pages: () => React.State<HTMLElement>): React.State<HTMLElement | undefined> | undefined => {
const tracker: PageTracker = this.register(key);
if (tracker.pages != undefined) {
return tracker.pages;
} else {
tracker.pages = pages();
return tracker.pages;
}
}
}
export class ViewPersistence {
static readonly chatPages = new PageTracker();
static readonly taskPages = new PageTrackerMap();
static readonly boardPages = new PageTrackerMap();
}
+1 -2
View File
@@ -100,8 +100,7 @@ export class Context {
this.keystrokes.set(key, fn); this.keystrokes.set(key, fn);
}; };
constructor(public contextDebugDescription: string) { constructor(public contextDebugDescription: string) {}
}
} }
export class ContextHost<T> extends Context { export class ContextHost<T> extends Context {
+1 -1
View File
@@ -204,7 +204,7 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
this.boardInfo.fileId, this.boardInfo.fileId,
); );
for (const taskId of taskIds) { for (const taskId of taskIds) {
if (this.taskViewModels.value.has(taskId)) return; if (this.taskViewModels.value.has(taskId)) continue;
const taskFileContent: TaskFileContent | null = const taskFileContent: TaskFileContent | null =
this.boardsAndTasksModel.getLatestTaskFileContent(taskId); this.boardsAndTasksModel.getLatestTaskFileContent(taskId);
-1
View File
@@ -143,7 +143,6 @@ export default class TaskPageViewModel extends ContextHost<string> {
// load // load
loadData = (): void => { loadData = (): void => {
console.log("LOADING TASK PAGE DATA");
this.closeContext(); this.closeContext();
this.boardViewModels.clear(); this.boardViewModels.clear();