From 0f2b1d3e14ac92b5150d035f1f28d1d8162042a9 Mon Sep 17 00:00:00 2001 From: 01zulfi <85733202+01zulfi@users.noreply.github.com> Date: Thu, 20 Feb 2025 13:02:49 +0500 Subject: [PATCH] web: fix tags not adding/removing in note header bar (#7623) Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com> --- apps/web/__e2e__/models/editor.model.ts | 10 ++++ apps/web/__e2e__/tabs.test.ts | 66 ++++++++++++++++++++++- apps/web/src/components/editor/header.tsx | 21 +++++--- apps/web/src/stores/editor-store.ts | 20 ++++--- 4 files changed, 103 insertions(+), 14 deletions(-) diff --git a/apps/web/__e2e__/models/editor.model.ts b/apps/web/__e2e__/models/editor.model.ts index 9a7b82e08..ee1a978b0 100644 --- a/apps/web/__e2e__/models/editor.model.ts +++ b/apps/web/__e2e__/models/editor.model.ts @@ -200,6 +200,16 @@ export class EditorModel { return tags; } + async removeTags(tags: string[]) { + for (const tag of tags) { + const item = this.tags + .filter({ hasText: tag }) + .getByTitle("Remove") + .first(); + await item.click(); + } + } + async getTitle() { return this.title.inputValue(); } diff --git a/apps/web/__e2e__/tabs.test.ts b/apps/web/__e2e__/tabs.test.ts index 8beecb028..d6bfa252f 100644 --- a/apps/web/__e2e__/tabs.test.ts +++ b/apps/web/__e2e__/tabs.test.ts @@ -19,7 +19,7 @@ along with this program. If not, see . import { test, expect } from "@playwright/test"; import { AppModel } from "./models/app.model"; -import { createHistorySession } from "./utils"; +import { createHistorySession, NOTE } from "./utils"; test("notes should open in the same tab", async ({ page }) => { const app = new AppModel(page); @@ -295,5 +295,69 @@ test("shouldn't be possible to create a new note in a pinned tab", async ({ expect(await tabs[1].isActive()).toBe(true); }); +test("notes open in multiple tabs should sync tags when tags are added", async ({ + page +}) => { + const tags = ["toAdd", "todo"]; + const app = new AppModel(page); + await app.goto(); + const notes = await app.goToNotes(); + const note = await notes.createNote(NOTE); + await note?.contextMenu.openInNewTab(); + + await notes.editor.setTags(tags); + const tabs = await notes.editor.getTabs(); + await tabs[0].click(); + + const noteTags = await notes.editor.getTags(); + expect(noteTags).toHaveLength(tags.length); + expect(noteTags.every((t, i) => t === tags[i])).toBe(true); +}); + +test("notes open in multiple tabs should sync tags when tags are removed", async ({ + page +}) => { + const tags = ["removeme", "dontremoveme", "removemex2", "todo"]; + const app = new AppModel(page); + await app.goto(); + const notes = await app.goToNotes(); + const note = await notes.createNote(NOTE); + await notes.editor.setTags(tags); + await note?.contextMenu.openInNewTab(); + + await notes.editor.removeTags(["removeme", "removemex2"]); + const tabs = await notes.editor.getTabs(); + await tabs[0].click(); + + const noteTags = await notes.editor.getTags(); + expect(noteTags).toHaveLength(2); + expect(noteTags.every((t, i) => t === ["dontremoveme", "todo"][i])).toBe( + true + ); +}); + +test("notes open in multiple tabs should sync color in note properties when color is changed", async ({ + page +}) => { + const app = new AppModel(page); + await app.goto(); + const notes = await app.goToNotes(); + const note = await notes.createNote(NOTE); + await note?.contextMenu.newColor({ title: "red", color: "#ff0000" }); + await note?.contextMenu.newColor({ title: "blue", color: "#0000ff" }); + await note?.contextMenu.openInNewTab(); + + await notes.editor.waitForLoading(); + const tabs = await notes.editor.getTabs(); + await tabs[0].click(); + + expect(await note?.properties.isColored("blue")).toBe(true); + + await note?.properties.color("red"); + await tabs[1].click(); + + expect(await note?.properties.isColored("red")).toBe(true); +}); + test.skip("TODO: open a locked note, switch to another note and navigate back", () => {}); test.skip("TODO: open a locked note, switch to another note, unlock the note and navigate back", () => {}); diff --git a/apps/web/src/components/editor/header.tsx b/apps/web/src/components/editor/header.tsx index ede441f90..ee5be35a2 100644 --- a/apps/web/src/components/editor/header.tsx +++ b/apps/web/src/components/editor/header.tsx @@ -35,9 +35,11 @@ import { strings } from "@notesnook/intl"; type HeaderProps = { readonly: boolean; id: string }; function Header(props: HeaderProps) { const { readonly, id } = props; - const tags = useEditorStore( - (store) => store.getActiveSession(["default", "readonly"])?.tags + const activeSession = useEditorStore((store) => + store.getActiveSession(["default", "readonly"]) ); + const tags = activeSession?.tags; + const noteId = activeSession?.note.id; const setTag = useCallback(async function ( noteId: string, @@ -59,6 +61,8 @@ function Header(props: HeaderProps) { }, []); + if (!noteId) return null; + return ( <> navigate(`/tags/${tag.id}`)} - onDismiss={readonly ? undefined : () => setTag(id, tags, tag.title)} + onDismiss={ + readonly ? undefined : () => setTag(noteId, tags, tag.title) + } styles={{ container: { mr: 1 }, text: { fontSize: "body" } }} /> ))} @@ -90,7 +96,7 @@ function Header(props: HeaderProps) { key: "new", title: `Create "${query}" tag`, icon: Plus.path, - onClick: () => setTag(id, tags, query).finally(reset) + onClick: () => setTag(noteId, tags, query).finally(reset) }); } @@ -101,17 +107,18 @@ function Header(props: HeaderProps) { key: item.id, title: item.title, icon: TagIcon.path, - onClick: () => setTag(id, tags, item.title).finally(reset) + onClick: () => + setTag(noteId, tags, item.title).finally(reset) })) ); } return items; }} - onAdd={(value) => setTag(id, tags, value)} + onAdd={(value) => setTag(noteId, tags, value)} onRemove={() => { if (tags.length <= 0) return; - setTag(id, tags, tags[tags.length - 1].title); + setTag(noteId, tags, tags[tags.length - 1].title); }} defaultItems={() => db.tags.all.limit(10).items(undefined, { diff --git a/apps/web/src/stores/editor-store.ts b/apps/web/src/stores/editor-store.ts index 39cadf0cb..ce14cd019 100644 --- a/apps/web/src/stores/editor-store.ts +++ b/apps/web/src/stores/editor-store.ts @@ -414,9 +414,13 @@ class EditorStore extends BaseStore { event.item.fromType === "color" && event.item.toType === "note" ) { - updateSession(event.item.toId, undefined, { - color: event.item.fromId - }); + for (const session of sessions) { + if ("color" in session && session.note.id === event.item.toId) { + updateSession(session.id, undefined, { + color: event.item.fromId + }); + } + } } else if ( event.type === "unlink" && ((event.reference.type === "color" && @@ -467,9 +471,13 @@ class EditorStore extends BaseStore { event.item.fromType === "tag" && event.item.toType === "note" ) { - updateSession(event.item.toId, undefined, { - tags: await db.notes.tags(event.item.toId) - }); + for (const session of sessions) { + if ("note" in session && session.note.id === event.item.toId) { + updateSession(session.id, undefined, { + tags: await db.notes.tags(event.item.toId) + }); + } + } } } else if (event.collection === "tags") { if (event.type === "update") {