diff --git a/.eslintignore b/.eslintignore index ac0b10883c..2f07c76402 100644 --- a/.eslintignore +++ b/.eslintignore @@ -753,6 +753,8 @@ packages/lib/services/database/addMigrationFile.js packages/lib/services/database/migrations/42.js packages/lib/services/database/migrations/43.js packages/lib/services/database/migrations/44.js +packages/lib/services/database/migrations/45.js +packages/lib/services/database/sqlStringToLines.js packages/lib/services/database/types.js packages/lib/services/debug/populateDatabase.js packages/lib/services/e2ee/EncryptionService.test.js @@ -799,6 +801,13 @@ packages/lib/services/keychain/KeychainServiceDriverBase.js packages/lib/services/noteList/defaultLeftToRightListRenderer.js packages/lib/services/noteList/defaultListRenderer.js packages/lib/services/noteList/renderers.js +packages/lib/services/ocr/OcrDriverBase.js +packages/lib/services/ocr/OcrService.test.js +packages/lib/services/ocr/OcrService.js +packages/lib/services/ocr/drivers/OcrDriverTesseract.js +packages/lib/services/ocr/utils/filterOcrText.test.js +packages/lib/services/ocr/utils/filterOcrText.js +packages/lib/services/ocr/utils/types.js packages/lib/services/plugins/BasePlatformImplementation.js packages/lib/services/plugins/BasePluginRunner.js packages/lib/services/plugins/MenuController.js @@ -876,6 +885,7 @@ packages/lib/services/rest/utils/paginatedResults.js packages/lib/services/rest/utils/readonlyProperties.js packages/lib/services/rest/utils/requestFields.js packages/lib/services/rest/utils/requestPaginationOptions.js +packages/lib/services/searchengine/SearchEngine.resources.test.js packages/lib/services/searchengine/SearchEngine.js packages/lib/services/searchengine/SearchEngineUtils.test.js packages/lib/services/searchengine/SearchEngineUtils.js @@ -923,6 +933,7 @@ packages/lib/services/synchronizer/utils/handleSyncStartupOperation.js packages/lib/services/synchronizer/utils/resourceRemotePath.js packages/lib/services/synchronizer/utils/syncDeleteStep.js packages/lib/services/synchronizer/utils/types.js +packages/lib/shim-init-node.js packages/lib/shim.js packages/lib/testing/syncTargetUtils.js packages/lib/testing/test-utils-synchronizer.js diff --git a/.github/workflows/build-macos-m1.yml b/.github/workflows/build-macos-m1.yml index 369b5c7147..d0f978f797 100644 --- a/.github/workflows/build-macos-m1.yml +++ b/.github/workflows/build-macos-m1.yml @@ -33,6 +33,12 @@ jobs: # https://yarnpkg.com/getting-started/install corepack enable + - name: Install macOs dependencies + if: runner.os == 'macOS' + run: | + # Required for building the canvas package + brew install pango + # See github-action-main.yml for explanation - uses: actions/setup-python@v4 with: diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index c0d73b0a5d..36bd40b5d5 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -59,6 +59,12 @@ jobs: # testing. sudo apt-get install -y xvfb + - name: Install macOs dependencies + if: runner.os == 'macOS' + run: | + # Required for building the canvas package + brew install pango + - name: Install Docker Engine # if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v') if: runner.os == 'Linux' diff --git a/.gitignore b/.gitignore index e5c289eec8..326613482f 100644 --- a/.gitignore +++ b/.gitignore @@ -733,6 +733,8 @@ packages/lib/services/database/addMigrationFile.js packages/lib/services/database/migrations/42.js packages/lib/services/database/migrations/43.js packages/lib/services/database/migrations/44.js +packages/lib/services/database/migrations/45.js +packages/lib/services/database/sqlStringToLines.js packages/lib/services/database/types.js packages/lib/services/debug/populateDatabase.js packages/lib/services/e2ee/EncryptionService.test.js @@ -779,6 +781,13 @@ packages/lib/services/keychain/KeychainServiceDriverBase.js packages/lib/services/noteList/defaultLeftToRightListRenderer.js packages/lib/services/noteList/defaultListRenderer.js packages/lib/services/noteList/renderers.js +packages/lib/services/ocr/OcrDriverBase.js +packages/lib/services/ocr/OcrService.test.js +packages/lib/services/ocr/OcrService.js +packages/lib/services/ocr/drivers/OcrDriverTesseract.js +packages/lib/services/ocr/utils/filterOcrText.test.js +packages/lib/services/ocr/utils/filterOcrText.js +packages/lib/services/ocr/utils/types.js packages/lib/services/plugins/BasePlatformImplementation.js packages/lib/services/plugins/BasePluginRunner.js packages/lib/services/plugins/MenuController.js @@ -856,6 +865,7 @@ packages/lib/services/rest/utils/paginatedResults.js packages/lib/services/rest/utils/readonlyProperties.js packages/lib/services/rest/utils/requestFields.js packages/lib/services/rest/utils/requestPaginationOptions.js +packages/lib/services/searchengine/SearchEngine.resources.test.js packages/lib/services/searchengine/SearchEngine.js packages/lib/services/searchengine/SearchEngineUtils.test.js packages/lib/services/searchengine/SearchEngineUtils.js @@ -903,6 +913,7 @@ packages/lib/services/synchronizer/utils/handleSyncStartupOperation.js packages/lib/services/synchronizer/utils/resourceRemotePath.js packages/lib/services/synchronizer/utils/syncDeleteStep.js packages/lib/services/synchronizer/utils/types.js +packages/lib/shim-init-node.js packages/lib/shim.js packages/lib/testing/syncTargetUtils.js packages/lib/testing/test-utils-synchronizer.js diff --git a/.yarn/patches/pdfjs-dist-npm-3.11.174-67f2fee6d6.patch b/.yarn/patches/pdfjs-dist-npm-3.11.174-67f2fee6d6.patch new file mode 100644 index 0000000000..f51b0c4a92 --- /dev/null +++ b/.yarn/patches/pdfjs-dist-npm-3.11.174-67f2fee6d6.patch @@ -0,0 +1,15 @@ + +# We remove the `canvas` optional dependency because electron-rebuild fails to build it, and +# the `canvas` API is already part of Electron +diff --git a/package.json b/package.json +index 105811f53d508486e08a60dc1b6e437cd24d7427..dea6a4e6612c4a4006cc482e46ff5270dcfda1e5 100644 +--- a/package.json ++++ b/package.json +@@ -13,7 +13,6 @@ + "bugs": "https://github.com/mozilla/pdf.js/issues", + "license": "Apache-2.0", + "optionalDependencies": { +- "canvas": "^2.11.2", + "path2d-polyfill": "^2.0.1" + }, + "browser": { diff --git a/package.json b/package.json index d611707423..00990831fc 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "crowdinUpload": "crowdin upload", "cspell": "cspell", "dependencyTree": "madge", - "generateDatabaseTypes": "node packages/tools/generate-database-types", + "generateTypes": "node packages/tools/generate-database-types", "linkChecker": "linkchecker https://joplinapp.org/ && linkchecker --check-extern https://joplinapp.org/api/references/plugin_api/classes/joplin.html", "linter-ci": "eslint --resolve-plugins-relative-to . --quiet --ext .js --ext .jsx --ext .ts --ext .tsx", "linter-interactive": "eslint-interactive --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx", @@ -105,6 +105,7 @@ "react-native-vosk@0.1.12": "patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch", "eslint": "patch:eslint@8.52.0#./.yarn/patches/eslint-npm-8.39.0-d92bace04d.patch", "app-builder-lib@24.4.0": "patch:app-builder-lib@npm%3A24.4.0#./.yarn/patches/app-builder-lib-npm-24.4.0-05322ff057.patch", - "react-native@0.71.10": "patch:react-native@npm%3A0.71.10#./.yarn/patches/react-native-animation-fix/react-native-npm-0.71.10-f9c32562d8.patch" + "react-native@0.71.10": "patch:react-native@npm%3A0.71.10#./.yarn/patches/react-native-animation-fix/react-native-npm-0.71.10-f9c32562d8.patch", + "pdfjs-dist": "patch:pdfjs-dist@npm%3A3.11.174#./.yarn/patches/pdfjs-dist-npm-3.11.174-67f2fee6d6.patch" } } diff --git a/packages/app-cli/tests/ocr_samples/dummy.pdf b/packages/app-cli/tests/ocr_samples/dummy.pdf new file mode 100644 index 0000000000..774c2ea70c Binary files /dev/null and b/packages/app-cli/tests/ocr_samples/dummy.pdf differ diff --git a/packages/app-cli/tests/ocr_samples/testocr.png b/packages/app-cli/tests/ocr_samples/testocr.png new file mode 100644 index 0000000000..ce8d0e78b5 Binary files /dev/null and b/packages/app-cli/tests/ocr_samples/testocr.png differ diff --git a/packages/app-cli/tests/ocr_samples/with_bullets.png b/packages/app-cli/tests/ocr_samples/with_bullets.png new file mode 100644 index 0000000000..1046eae755 Binary files /dev/null and b/packages/app-cli/tests/ocr_samples/with_bullets.png differ diff --git a/packages/app-desktop/.gitignore b/packages/app-desktop/.gitignore index 5ab3baf156..4e7efbe35e 100644 --- a/packages/app-desktop/.gitignore +++ b/packages/app-desktop/.gitignore @@ -14,6 +14,8 @@ style.min.css build/lib/ vendor/* !vendor/loadEmojiLib.js +build/pdf.worker.min.js +build/tesseract.js* test-results/ playwright-report/ playwright/.cache/ diff --git a/packages/app-desktop/app.ts b/packages/app-desktop/app.ts index 87a885e3cb..829a0431ed 100644 --- a/packages/app-desktop/app.ts +++ b/packages/app-desktop/app.ts @@ -63,11 +63,14 @@ import ShareService from '@joplin/lib/services/share/ShareService'; import checkForUpdates from './checkForUpdates'; import { AppState } from './app.reducer'; import syncDebugLog from '@joplin/lib/services/synchronizer/syncDebugLog'; -import eventManager from '@joplin/lib/eventManager'; +import eventManager, { EventName } from '@joplin/lib/eventManager'; import path = require('path'); import { checkPreInstalledDefaultPlugins, installDefaultPlugins, setSettingsForDefaultPlugins } from '@joplin/lib/services/plugins/defaultPlugins/defaultPluginsUtils'; import userFetcher, { initializeUserFetcher } from '@joplin/lib/utils/userFetcher'; import { parseNotesParent } from '@joplin/lib/reducer'; +import OcrService from '@joplin/lib/services/ocr/OcrService'; +import OcrDriverTesseract from '@joplin/lib/services/ocr/drivers/OcrDriverTesseract'; +import SearchEngine from '@joplin/lib/services/searchengine/SearchEngine'; import { PackageInfo } from '@joplin/lib/versionInfo'; const pluginClasses = [ @@ -83,6 +86,7 @@ class Application extends BaseApplication { private checkAllPluginStartedIID_: any = null; private initPluginServiceDone_ = false; + private ocrService_: OcrService; public constructor() { super(); @@ -121,6 +125,10 @@ class Application extends BaseApplication { this.updateTray(); } + if (action.type === 'SETTING_UPDATE_ONE' && action.key === 'ocr.enabled' || action.type === 'SETTING_UPDATE_ALL') { + this.setupOcrService(); + } + if (action.type === 'SETTING_UPDATE_ONE' && action.key === 'style.editor.fontFamily' || action.type === 'SETTING_UPDATE_ALL') { this.updateEditorFont(); } @@ -355,6 +363,34 @@ class Application extends BaseApplication { Setting.setValue('wasClosedSuccessfully', false); } + private setupOcrService() { + if (Setting.value('ocr.enabled')) { + if (!this.ocrService_) { + const Tesseract = (window as any).Tesseract; + + const driver = new OcrDriverTesseract( + { createWorker: Tesseract.createWorker }, + `${bridge().buildDir()}/tesseract.js/worker.min.js`, + `${bridge().buildDir()}/tesseract.js-core`, + ); + + this.ocrService_ = new OcrService(driver); + } + + void this.ocrService_.runInBackground(); + } else { + if (!this.ocrService_) return; + void this.ocrService_.stopRunInBackground(); + } + + const handleResourceChange = () => { + void this.ocrService_.maintenance(); + }; + + eventManager.on(EventName.ResourceCreate, handleResourceChange); + eventManager.on(EventName.ResourceChange, handleResourceChange); + } + public async start(argv: string[]): Promise { // If running inside a package, the command line, instead of being "node.exe " is "joplin.exe " so // insert an extra argument so that they can be processed in a consistent way everywhere. @@ -571,7 +607,7 @@ class Application extends BaseApplication { // Forwards the local event to the global event manager, so that it can // be picked up by the plugin manager. ResourceEditWatcher.instance().on('resourceChange', (event: any) => { - eventManager.emit('resourceChange', event); + eventManager.emit(EventName.ResourceChange, event); }); RevisionService.instance().runInBackground(); @@ -587,6 +623,8 @@ class Application extends BaseApplication { bridge: bridge(), debug: new DebugService(reg.db()), resourceService: ResourceService.instance(), + searchEngine: SearchEngine.instance(), + ocrService: () => this.ocrService_, }; } @@ -600,6 +638,12 @@ class Application extends BaseApplication { this.startRotatingLogMaintenance(Setting.value('profileDir')); + await this.setupOcrService(); + + eventManager.on(EventName.OcrServiceResourcesProcessed, () => { + SearchEngine.instance().scheduleSyncTables(); + }); + // await populateDatabase(reg.db(), { // clearDatabase: true, // folderCount: 1000, diff --git a/packages/app-desktop/gui/MainScreen/commands/editAlarm.ts b/packages/app-desktop/gui/MainScreen/commands/editAlarm.ts index 40cff368a0..9eb05a175c 100644 --- a/packages/app-desktop/gui/MainScreen/commands/editAlarm.ts +++ b/packages/app-desktop/gui/MainScreen/commands/editAlarm.ts @@ -1,5 +1,5 @@ import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService'; -import eventManager from '@joplin/lib/eventManager'; +import eventManager, { EventName } from '@joplin/lib/eventManager'; import { _ } from '@joplin/lib/locale'; import { stateUtils } from '@joplin/lib/reducer'; import Note from '@joplin/lib/models/Note'; @@ -45,7 +45,7 @@ export const runtime = (comp: any): CommandRuntime => { if (newNote) { await Note.save(newNote); - eventManager.emit('alarmChange', { noteId: note.id, note: newNote }); + eventManager.emit(EventName.AlarmChange, { noteId: note.id, note: newNote }); } comp.setState({ promptOptions: null }); diff --git a/packages/app-desktop/gui/MainScreen/commands/toggleNoteType.ts b/packages/app-desktop/gui/MainScreen/commands/toggleNoteType.ts index 83df6ef4fa..42f76970b4 100644 --- a/packages/app-desktop/gui/MainScreen/commands/toggleNoteType.ts +++ b/packages/app-desktop/gui/MainScreen/commands/toggleNoteType.ts @@ -1,7 +1,7 @@ import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService'; import { _ } from '@joplin/lib/locale'; import Note from '@joplin/lib/models/Note'; -import eventManager from '@joplin/lib/eventManager'; +import eventManager, { EventName } from '@joplin/lib/eventManager'; export const declaration: CommandDeclaration = { name: 'toggleNoteType', @@ -22,7 +22,7 @@ export const runtime = (): CommandRuntime => { todo_due: newNote.todo_due, todo_completed: newNote.todo_completed, }; - eventManager.emit('noteTypeToggle', { noteId: note.id, note: eventNote }); + eventManager.emit(EventName.NoteTypeToggle, { noteId: note.id, note: eventNote }); } }, enabledCondition: '!noteIsReadOnly', diff --git a/packages/app-desktop/gui/MenuBar.tsx b/packages/app-desktop/gui/MenuBar.tsx index d879bd2db7..dd7d216c14 100644 --- a/packages/app-desktop/gui/MenuBar.tsx +++ b/packages/app-desktop/gui/MenuBar.tsx @@ -25,6 +25,7 @@ import { ProfileConfig } from '@joplin/lib/services/profileConfig/types'; import PluginService, { PluginSettings } from '@joplin/lib/services/plugins/PluginService'; import { getListRendererById, getListRendererIds } from '@joplin/lib/services/noteList/renderers'; import useAsyncEffect from '@joplin/lib/hooks/useAsyncEffect'; +import { EventName } from '@joplin/lib/eventManager'; const packageInfo: PackageInfo = require('../packageInfo.js'); const { clipboard } = require('electron'); const Menu = bridge().Menu; @@ -1011,10 +1012,10 @@ function useMenu(props: Props) { setKeymapLastChangeTime(Date.now()); } - KeymapService.instance().on('keymapChange', onKeymapChange); + KeymapService.instance().on(EventName.KeymapChange, onKeymapChange); return () => { - KeymapService.instance().off('keymapChange', onKeymapChange); + KeymapService.instance().off(EventName.KeymapChange, onKeymapChange); }; }, []); diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useKeymap.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useKeymap.ts index 09869a012f..0e13ef3189 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useKeymap.ts +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useKeymap.ts @@ -5,6 +5,7 @@ import { EditorCommand } from '../../../utils/types'; import shim from '@joplin/lib/shim'; import { reg } from '@joplin/lib/registry'; import setupVim from './setupVim'; +import { EventName } from '@joplin/lib/eventManager'; export default function useKeymap(CodeMirror: any) { @@ -174,7 +175,7 @@ export default function useKeymap(CodeMirror: any) { const keymapService = KeymapService.instance(); registerKeymap(); - keymapService.on('keymapChange', registerKeymap); + keymapService.on(EventName.KeymapChange, registerKeymap); setupEmacs(); setupVim(CodeMirror); diff --git a/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx b/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx index 32666b2d82..f0035e9481 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx @@ -19,10 +19,10 @@ import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index' import CommandService from '@joplin/lib/services/CommandService'; import ToolbarButton from '../ToolbarButton/ToolbarButton'; import Button, { ButtonLevel } from '../Button/Button'; -import eventManager from '@joplin/lib/eventManager'; +import eventManager, { EventName } from '@joplin/lib/eventManager'; import { AppState } from '../../app.reducer'; import ToolbarButtonUtils from '@joplin/lib/services/commands/ToolbarButtonUtils'; -import { _ } from '@joplin/lib/locale'; +import { _, _n } from '@joplin/lib/locale'; import TagList from '../TagList'; import NoteTitleBar from './NoteTitle/NoteTitleBar'; import markupLanguageUtils from '../../utils/markupLanguageUtils'; @@ -48,6 +48,7 @@ import ItemChange from '@joplin/lib/models/ItemChange'; import PlainEditor from './NoteBody/PlainEditor/PlainEditor'; import CodeMirror6 from './NoteBody/CodeMirror/v6/CodeMirror'; import CodeMirror5 from './NoteBody/CodeMirror/v5/CodeMirror'; +import { openItemById } from './utils/contextMenu'; import { namespacedKey } from '@joplin/lib/services/plugins/api/JoplinSettings'; const commands = [ @@ -135,7 +136,7 @@ function NoteEditor(props: NoteEditorProps) { id: formNote.id, }); - eventManager.emit('noteContentChange', { note: savedNote }); + eventManager.emit(EventName.NoteContentChange, { note: savedNote }); }; }; @@ -367,11 +368,11 @@ function NoteEditor(props: NoteEditorProps) { }, []); useEffect(() => { - eventManager.on('alarmChange', onNotePropertyChange); + eventManager.on(EventName.AlarmChange, onNotePropertyChange); ExternalEditWatcher.instance().on('noteChange', externalEditWatcher_noteChange); return () => { - eventManager.off('alarmChange', onNotePropertyChange); + eventManager.off(EventName.AlarmChange, onNotePropertyChange); ExternalEditWatcher.instance().off('noteChange', externalEditWatcher_noteChange); }; }, [externalEditWatcher_noteChange, onNotePropertyChange]); @@ -499,6 +500,12 @@ function NoteEditor(props: NoteEditorProps) { setShowRevisions(false); }, []); + const onBannerResourceClick = useCallback(async (event: React.MouseEvent) => { + event.preventDefault(); + const resourceId = event.currentTarget.getAttribute('data-resource-id'); + await openItemById(resourceId, props.dispatch); + }, [props.dispatch]); + if (showRevisions) { const theme = themeStyle(props.themeId); @@ -568,6 +575,24 @@ function NoteEditor(props: NoteEditorProps) { ); } + const renderResourceInSearchResultsNotification = () => { + const resourceResults = props.searchResults.filter(r => r.id === props.noteId && r.item_type === ModelType.Resource); + if (!resourceResults.length) return null; + + const renderResource = (id: string, title: string) => { + return
  • {title}
  • ; + }; + + return ( +
    +

    {_n('The following attachment matches your search query:', 'The following attachments match your search query:', resourceResults.length)}

    +
      + {resourceResults.map(r => renderResource(r.item_id, r.title))} +
    +
    + ); + }; + function renderSearchInfo() { const theme = themeStyle(props.themeId); if (formNoteFolder && ['Search', 'Tag', 'SmartFilter'].includes(props.notesParentType)) { @@ -603,6 +628,7 @@ function NoteEditor(props: NoteEditorProps) {
    {renderResourceWatchingNotification()} + {renderResourceInSearchResultsNotification()} { useCustomPdfViewer: false, syncUserId: state.settings['sync.userId'], shareCacheSetting: state.settings['sync.shareCache'], + searchResults: state.searchResults, }; }; diff --git a/packages/app-desktop/gui/NoteEditor/utils/types.ts b/packages/app-desktop/gui/NoteEditor/utils/types.ts index 4a266b55fd..31d6feb70d 100644 --- a/packages/app-desktop/gui/NoteEditor/utils/types.ts +++ b/packages/app-desktop/gui/NoteEditor/utils/types.ts @@ -5,6 +5,7 @@ import { MarkupLanguage } from '@joplin/renderer'; import { RenderResult, RenderResultPluginAsset } from '@joplin/renderer/MarkupToHtml'; import { MarkupToHtmlOptions } from './useMarkupToHtml'; import { Dispatch } from 'redux'; +import { ProcessResultsRow } from '@joplin/lib/services/searchengine/SearchEngine'; export interface AllAssetsOptions { contentMaxWidthTarget?: string; @@ -46,6 +47,7 @@ export interface NoteEditorProps { useCustomPdfViewer: boolean; shareCacheSetting: string; syncUserId: string; + searchResults: ProcessResultsRow[]; } export interface NoteBodyEditorRef { diff --git a/packages/app-desktop/gui/NoteList/NoteList.tsx b/packages/app-desktop/gui/NoteList/NoteList.tsx index 247644c98c..8558943adf 100644 --- a/packages/app-desktop/gui/NoteList/NoteList.tsx +++ b/packages/app-desktop/gui/NoteList/NoteList.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { useMemo, useEffect, useState, useRef, useCallback } from 'react'; import { AppState } from '../../app.reducer'; -import eventManager from '@joplin/lib/eventManager'; +import eventManager, { EventName } from '@joplin/lib/eventManager'; import NoteListUtils from '../utils/NoteListUtils'; import { _ } from '@joplin/lib/locale'; import time from '@joplin/lib/time'; @@ -202,7 +202,7 @@ const NoteListComponent = (props: Props) => { todo_completed: checked ? time.unixMs() : 0, }; await Note.save(newNote, { userSideValidation: true }); - eventManager.emit('todoToggle', { noteId: item.id, note: newNote }); + eventManager.emit(EventName.TodoToggle, { noteId: item.id, note: newNote }); }; const noteItem_titleClick = async (event: any, item: any) => { diff --git a/packages/app-desktop/gui/utils/NoteListUtils.ts b/packages/app-desktop/gui/utils/NoteListUtils.ts index 68011f8927..0036d6611b 100644 --- a/packages/app-desktop/gui/utils/NoteListUtils.ts +++ b/packages/app-desktop/gui/utils/NoteListUtils.ts @@ -1,6 +1,6 @@ import { utils as pluginUtils, PluginStates } from '@joplin/lib/services/plugins/reducer'; import CommandService from '@joplin/lib/services/CommandService'; -import eventManager from '@joplin/lib/eventManager'; +import eventManager, { EventName } from '@joplin/lib/eventManager'; import InteropService from '@joplin/lib/services/interop/InteropService'; import MenuUtils from '@joplin/lib/services/commands/MenuUtils'; import InteropServiceHelper from '../../InteropServiceHelper'; @@ -74,7 +74,7 @@ export default class NoteListUtils { const newNote = Note.changeNoteType(note, type); if (newNote === note) continue; await Note.save(newNote, { userSideValidation: true }); - eventManager.emit('noteTypeToggle', { noteId: note.id }); + eventManager.emit(EventName.NoteTypeToggle, { noteId: note.id }); } }; diff --git a/packages/app-desktop/index.html b/packages/app-desktop/index.html index 582e4380b4..a1704e9327 100644 --- a/packages/app-desktop/index.html +++ b/packages/app-desktop/index.html @@ -15,6 +15,7 @@ +