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") {