mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-23 19:49:56 +01:00
web: allow saving note from status icon click & tab menu (#8316)
* web: allow saving note from status icon click & tab menu Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com> * web: directly save content instead of using events --------- Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
This commit is contained in:
@@ -415,6 +415,44 @@ test("when autosave is disabled, closing the note should save it", async ({
|
||||
expect(await notes.editor.getContent("text")).toBe(content.trim());
|
||||
});
|
||||
|
||||
test("when autosave is disabled, clicking the not saved icon should save the note", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const content = "a ".repeat(100);
|
||||
await notes.createNote({
|
||||
title: NOTE.title,
|
||||
content
|
||||
});
|
||||
|
||||
await notes.editor.notSavedIcon.waitFor({ state: "visible" });
|
||||
await notes.editor.notSavedIcon.click();
|
||||
|
||||
await expect(notes.editor.savedIcon).toBeVisible();
|
||||
expect(await notes.editor.getContent("text")).toBe(content.trim());
|
||||
});
|
||||
|
||||
test("when autosave is disabled, clicking save from tab menu should save the note", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const content = "a ".repeat(100);
|
||||
await notes.createNote({
|
||||
title: NOTE.title,
|
||||
content
|
||||
});
|
||||
|
||||
const tab = (await notes.editor.getTabs())[0];
|
||||
await tab.contextMenu.save();
|
||||
|
||||
await expect(notes.editor.savedIcon).toBeVisible();
|
||||
expect(await notes.editor.getContent("text")).toBe(content.trim());
|
||||
});
|
||||
|
||||
test("control + alt + right arrow should go to next note", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
|
||||
@@ -74,4 +74,9 @@ class TabContextMenuModel {
|
||||
await this.open();
|
||||
return this.menu.getItem("reveal-in-list");
|
||||
}
|
||||
|
||||
async save() {
|
||||
await this.open();
|
||||
return this.menu.clickOnItem("save");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ import useTablet from "../../hooks/use-tablet";
|
||||
import { isMac } from "../../utils/platform";
|
||||
import { CREATE_BUTTON_MAP } from "../../common";
|
||||
import { getDragData } from "../../utils/data-transfer";
|
||||
import { saveContent } from "./index";
|
||||
|
||||
type ToolButton = {
|
||||
title: string;
|
||||
@@ -406,6 +407,13 @@ const TabStrip = React.memo(function TabStrip() {
|
||||
isLocked={isLockedSession(session)}
|
||||
isRevealInListDisabled={isFocusMode}
|
||||
type={session.type}
|
||||
onSave={() => {
|
||||
const { activeEditorId, getEditor } =
|
||||
useEditorManager.getState();
|
||||
const editor = getEditor(activeEditorId || "")?.editor;
|
||||
if (!editor) return;
|
||||
saveContent(session.id, false, editor.getContent());
|
||||
}}
|
||||
onFocus={() => {
|
||||
if (tab.id !== currentTab) {
|
||||
useEditorStore.getState().activateSession(tab.sessionId);
|
||||
@@ -486,6 +494,7 @@ type TabProps = {
|
||||
onCloseToTheLeft: () => void;
|
||||
onCloseAll: () => void;
|
||||
onPin: () => void;
|
||||
onSave: () => void;
|
||||
onRevealInList?: () => void;
|
||||
};
|
||||
function Tab(props: TabProps) {
|
||||
@@ -505,7 +514,8 @@ function Tab(props: TabProps) {
|
||||
onCloseToTheRight,
|
||||
onCloseToTheLeft,
|
||||
onRevealInList,
|
||||
onPin
|
||||
onPin,
|
||||
onSave
|
||||
} = props;
|
||||
const Icon = isLocked
|
||||
? type === "locked"
|
||||
@@ -580,6 +590,14 @@ function Tab(props: TabProps) {
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
Menu.openMenu([
|
||||
{
|
||||
type: "button",
|
||||
title: strings.save(),
|
||||
key: "save",
|
||||
onClick: onSave,
|
||||
isHidden: !isUnsaved
|
||||
},
|
||||
{ type: "separator", key: "sep0", isHidden: !isUnsaved },
|
||||
{
|
||||
type: "button",
|
||||
title: strings.close(),
|
||||
@@ -610,7 +628,7 @@ function Tab(props: TabProps) {
|
||||
key: "close-all",
|
||||
onClick: onCloseAll
|
||||
},
|
||||
{ type: "separator", key: "sep" },
|
||||
{ type: "separator", key: "sep1" },
|
||||
{
|
||||
type: "button",
|
||||
title: strings.revealInList(),
|
||||
|
||||
@@ -34,7 +34,11 @@ import {
|
||||
NormalMode,
|
||||
Cross
|
||||
} from "../icons";
|
||||
import { useEditorConfig, useNoteStatistics } from "./manager";
|
||||
import {
|
||||
useEditorConfig,
|
||||
useEditorManager,
|
||||
useNoteStatistics
|
||||
} from "./manager";
|
||||
import { getFormattedDate } from "@notesnook/common";
|
||||
import { MAX_AUTO_SAVEABLE_WORDS, NoteStatistics } from "./types";
|
||||
import { strings } from "@notesnook/intl";
|
||||
@@ -43,6 +47,7 @@ import { useWindowControls } from "../../hooks/use-window-controls";
|
||||
import { exitFullscreen } from "../../utils/fullscreen";
|
||||
import { useRef, useState } from "react";
|
||||
import { PopupPresenter } from "@notesnook/ui";
|
||||
import { saveContent } from "./index";
|
||||
|
||||
const SAVE_STATE_ICON_MAP = {
|
||||
"-1": NotSaved,
|
||||
@@ -276,6 +281,24 @@ function EditorFooter() {
|
||||
? "icon-error"
|
||||
: "paragraph"
|
||||
}
|
||||
title={
|
||||
saveState === SaveState.NotSaved ? strings.clickToSave() : undefined
|
||||
}
|
||||
sx={{
|
||||
height: "100%",
|
||||
cursor: saveState === SaveState.NotSaved ? "pointer" : "default",
|
||||
":hover": {
|
||||
bg: saveState === SaveState.NotSaved ? "hover" : "initial"
|
||||
}
|
||||
}}
|
||||
onClick={() => {
|
||||
if (saveState === SaveState.NotSaved) {
|
||||
const { activeEditorId, getEditor } = useEditorManager.getState();
|
||||
const editor = getEditor(activeEditorId || "")?.editor;
|
||||
if (!editor) return;
|
||||
saveContent(session.id, false, editor.getContent());
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
@@ -84,7 +84,7 @@ const PDFPreview = React.lazy(() => import("../pdf-preview"));
|
||||
|
||||
const autoSaveToast = { show: true, hide: () => {} };
|
||||
|
||||
async function saveContent(
|
||||
export async function saveContent(
|
||||
noteId: string,
|
||||
ignoreEdit: boolean,
|
||||
content: string
|
||||
|
||||
@@ -68,6 +68,7 @@ import { showFeatureNotAllowedToast } from "../../common/toasts";
|
||||
import { UpgradeDialog } from "../../dialogs/buy-dialog/upgrade-dialog";
|
||||
import { ConfirmDialog } from "../../dialogs/confirm";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { AppEventManager, AppEvents } from "../../common/app-events";
|
||||
|
||||
export type OnChangeHandler = (
|
||||
content: () => string,
|
||||
|
||||
@@ -1604,6 +1604,10 @@ msgstr "Click to remove"
|
||||
msgid "Click to reset {title}"
|
||||
msgstr "Click to reset {title}"
|
||||
|
||||
#: src/strings.ts:2614
|
||||
msgid "Click to save"
|
||||
msgstr "Click to save"
|
||||
|
||||
#: src/strings.ts:2610
|
||||
msgid "Click to update"
|
||||
msgstr "Click to update"
|
||||
|
||||
@@ -1593,6 +1593,10 @@ msgstr ""
|
||||
msgid "Click to reset {title}"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2614
|
||||
msgid "Click to save"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2610
|
||||
msgid "Click to update"
|
||||
msgstr ""
|
||||
|
||||
@@ -2610,5 +2610,6 @@ Use this if changes from other devices are not appearing on this device. This wi
|
||||
clickToUpdate: () => t`Click to update`,
|
||||
noPassword: () => t`No password`,
|
||||
publishToTheWeb: () => t`Publish to the web`,
|
||||
addToHome: () => t`Add to home`
|
||||
addToHome: () => t`Add to home`,
|
||||
clickToSave: () => t`Click to save`
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user