web: fix tags not adding/removing in note header bar (#7623)

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
This commit is contained in:
01zulfi
2025-02-20 13:02:49 +05:00
committed by GitHub
parent 4abefe63db
commit 0f2b1d3e14
4 changed files with 103 additions and 14 deletions

View File

@@ -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();
}

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
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", () => {});

View File

@@ -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 (
<>
<Flex
@@ -72,7 +76,9 @@ function Header(props: HeaderProps) {
text={tag.title}
icon={TagIcon}
onClick={() => 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, {

View File

@@ -414,9 +414,13 @@ class EditorStore extends BaseStore<EditorStore> {
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<EditorStore> {
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") {