diff --git a/.prettierrc b/.prettierrc index 544138be4..9e74d98a6 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,3 @@ { - "singleQuote": true + "singleQuote": true, } diff --git a/app/assets/javascripts/components/AccountMenu/User.tsx b/app/assets/javascripts/components/AccountMenu/User.tsx index 68f49df1e..7815d4e74 100644 --- a/app/assets/javascripts/components/AccountMenu/User.tsx +++ b/app/assets/javascripts/components/AccountMenu/User.tsx @@ -1,7 +1,7 @@ import { observer } from 'mobx-react-lite'; import { AppState } from '@/ui_models/app_state'; import { WebApplication } from '@/ui_models/application'; -import { User as UserType } from '@standardnotes/responses'; +import { User as UserType } from '@standardnotes/snjs'; type Props = { appState: AppState; diff --git a/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesPopover.tsx b/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesPopover.tsx index 82c1f2c14..770ea0277 100644 --- a/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesPopover.tsx +++ b/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesPopover.tsx @@ -169,20 +169,18 @@ export const AttachedFilesPopover: FunctionComponent = observer( ) : null} {filteredList.length > 0 ? ( - filteredList - .filter((file) => !file.deleted) - .map((file: SNFile) => { - return ( - - ); - }) + filteredList.map((file: SNFile) => { + return ( + + ); + }) ) : (
diff --git a/app/assets/javascripts/components/Footer.tsx b/app/assets/javascripts/components/Footer.tsx index 5965843c4..fa7667602 100644 --- a/app/assets/javascripts/components/Footer.tsx +++ b/app/assets/javascripts/components/Footer.tsx @@ -226,10 +226,7 @@ export class Footer extends PureComponent { this.application.items.setDisplayOptions( ContentType.Theme, CollectionSort.Title, - 'asc', - (theme: ItemInterface) => { - return !theme.errorDecrypting; - } + 'asc' ); } diff --git a/app/assets/javascripts/components/NoteView/NoteView.tsx b/app/assets/javascripts/components/NoteView/NoteView.tsx index e90eebcb1..6db18d81a 100644 --- a/app/assets/javascripts/components/NoteView/NoteView.tsx +++ b/app/assets/javascripts/components/NoteView/NoteView.tsx @@ -281,7 +281,7 @@ export class NoteView extends PureComponent { }); } - if (!note.deleted && note.locked !== this.state.noteLocked) { + if (note.locked !== this.state.noteLocked) { this.setState({ noteLocked: note.locked, }); @@ -421,7 +421,7 @@ export class NoteView extends PureComponent { streamItems() { this.removeComponentStreamObserver = this.application.streamItems( ContentType.Component, - async (_items, source) => { + async ({ source }) => { if ( isPayloadSourceInternalChange(source) || source === PayloadSource.InitialObserverRegistrationPush @@ -1003,7 +1003,7 @@ export class NoteView extends PureComponent { )}
- {this.note && !this.note.errorDecrypting && ( + {this.note && (
{
)} - {!this.note.errorDecrypting && ( -
- {this.state.marginResizersEnabled && - this.editorContentRef.current ? ( - - ) : null} +
+ {this.state.marginResizersEnabled && + this.editorContentRef.current ? ( + + ) : null} - {this.state.editorComponentViewer && ( -
- -
+ {this.state.editorComponentViewer && ( +
+ +
+ )} + + {this.state.editorStateDidLoad && + !this.state.editorComponentViewer && + !this.state.textareaUnloading && ( + )} - {this.state.editorStateDidLoad && - !this.state.editorComponentViewer && - !this.state.textareaUnloading && ( - - )} + {this.state.marginResizersEnabled && + this.editorContentRef.current ? ( + + ) : null} +
- {this.state.marginResizersEnabled && - this.editorContentRef.current ? ( - - ) : null} -
- )} - - {this.note.errorDecrypting && ( -
-
-
-
-
- {this.note.waitingForKey - ? 'Waiting for Key' - : 'Unable to Decrypt'} -
-
-
-
- {this.note.waitingForKey && ( -

- This note is awaiting its encryption key to be ready. - Please wait for syncing to complete for this note to - be decrypted. -

- )} - {!this.note.waitingForKey && ( -

- There was an error decrypting this item. Ensure you - are running the latest version of this app, then sign - out and sign back in to try again. -

- )} -
-
-
-
-
- )} - - {!this.note.errorDecrypting && ( -
- {this.state.availableStackComponents.length > 0 && ( -
-
- {this.state.availableStackComponents.map((component) => { - return ( -
{ - this.toggleStackComponent(component); - }} - className="sk-app-bar-item" - > -
-
-
-
-
{component.name}
-
+
+ {this.state.availableStackComponents.length > 0 && ( +
+
+ {this.state.availableStackComponents.map((component) => { + return ( +
{ + this.toggleStackComponent(component); + }} + className="sk-app-bar-item" + > +
+
- ); - })} -
+
+
{component.name}
+
+
+ ); + })}
- )} - -
- {this.state.stackComponentViewers.map((viewer) => { - return ( -
- -
- ); - })}
+ )} + +
+ {this.state.stackComponentViewers.map((viewer) => { + return ( +
+ +
+ ); + })}
- )} +
); diff --git a/app/assets/javascripts/components/NotesListItem.tsx b/app/assets/javascripts/components/NotesListItem.tsx index 1928308bd..cd11880ca 100644 --- a/app/assets/javascripts/components/NotesListItem.tsx +++ b/app/assets/javascripts/components/NotesListItem.tsx @@ -1,6 +1,7 @@ import { WebApplication } from '@/ui_models/application'; import { CollectionSort, + CollectionSortProperty, sanitizeHtmlString, SNNote, } from '@standardnotes/snjs'; @@ -18,7 +19,7 @@ type Props = { onClick: () => void; onContextMenu: (e: MouseEvent) => void; selected: boolean; - sortedBy?: CollectionSort; + sortedBy?: CollectionSortProperty; }; type NoteFlag = { @@ -34,25 +35,7 @@ const flagsForNote = (note: SNNote) => { class: 'danger', }); } - if (note.errorDecrypting) { - if (note.waitingForKey) { - flags.push({ - text: 'Waiting For Keys', - class: 'info', - }); - } else { - flags.push({ - text: 'Missing Keys', - class: 'danger', - }); - } - } - if (note.deleted) { - flags.push({ - text: 'Deletion Pending Sync', - class: 'danger', - }); - } + return flags; }; diff --git a/app/assets/javascripts/components/NotesListOptionsMenu.tsx b/app/assets/javascripts/components/NotesListOptionsMenu.tsx index a701d6df0..9002ab7ee 100644 --- a/app/assets/javascripts/components/NotesListOptionsMenu.tsx +++ b/app/assets/javascripts/components/NotesListOptionsMenu.tsx @@ -1,5 +1,9 @@ import { WebApplication } from '@/ui_models/application'; -import { CollectionSort, PrefKey } from '@standardnotes/snjs'; +import { + CollectionSort, + CollectionSortProperty, + PrefKey, +} from '@standardnotes/snjs'; import { observer } from 'mobx-react-lite'; import { FunctionComponent } from 'preact'; import { useState } from 'preact/hooks'; @@ -52,7 +56,7 @@ export const NotesListOptionsMenu: FunctionComponent = observer( setSortReverse(!sortReverse); }; - const toggleSortBy = (sort: CollectionSort) => { + const toggleSortBy = (sort: CollectionSortProperty) => { if (sortBy === sort) { toggleSortReverse(); } else { diff --git a/app/assets/javascripts/components/NotesOptions/ListedActionsOption.tsx b/app/assets/javascripts/components/NotesOptions/ListedActionsOption.tsx index 5fc9bef1a..f9cdf0c49 100644 --- a/app/assets/javascripts/components/NotesOptions/ListedActionsOption.tsx +++ b/app/assets/javascripts/components/NotesOptions/ListedActionsOption.tsx @@ -104,7 +104,7 @@ const ListedActionsMenu: FunctionComponent = ({ const updatedGroup: ListedMenuGroup = { name: updatedAccountInfo.display_name, account: group.account, - actions: updatedAccountInfo.actions, + actions: updatedAccountInfo.actions as Action[], }; const updatedGroups = menuGroups.map((group) => { @@ -145,7 +145,7 @@ const ListedActionsMenu: FunctionComponent = ({ menuGroups.push({ name: accountInfo.display_name, account, - actions: accountInfo.actions, + actions: accountInfo.actions as Action[], }); } else { menuGroups.push({ diff --git a/app/assets/javascripts/components/NotesOptions/NotesOptions.tsx b/app/assets/javascripts/components/NotesOptions/NotesOptions.tsx index 3fb22b7a0..3c0c8da56 100644 --- a/app/assets/javascripts/components/NotesOptions/NotesOptions.tsx +++ b/app/assets/javascripts/components/NotesOptions/NotesOptions.tsx @@ -219,7 +219,6 @@ export const NotesOptions = observer( const notTrashed = notes.some((note) => !note.trashed); const pinned = notes.some((note) => note.pinned); const unpinned = notes.some((note) => !note.pinned); - const errored = notes.some((note) => note.errorDecrypting); useEffect(() => { const removeAltKeyObserver = application.io.addKeyObserver({ @@ -278,26 +277,6 @@ export const NotesOptions = observer( }); }; - if (errored) { - return ( - <> - {notes.length === 1 ? ( -
-
- Note ID: {notes[0].uuid} -
-
- ) : null} - { - await appState.notes.deleteNotesPermanently(); - }} - /> - - ); - } - const openRevisionHistoryModal = () => { appState.notes.setShowRevisionHistoryModal(true); }; diff --git a/app/assets/javascripts/components/NotesOptions/changeEditor/ChangeEditorMenu.tsx b/app/assets/javascripts/components/NotesOptions/changeEditor/ChangeEditorMenu.tsx index 7a6f217c2..cd35f31b5 100644 --- a/app/assets/javascripts/components/NotesOptions/changeEditor/ChangeEditorMenu.tsx +++ b/app/assets/javascripts/components/NotesOptions/changeEditor/ChangeEditorMenu.tsx @@ -86,7 +86,7 @@ export const ChangeEditorMenu: FunctionComponent = ({ ) => { if (component) { if (component.conflictOf) { - application.mutator.changeAndSaveItem(component.uuid, (mutator) => { + application.mutator.changeAndSaveItem(component, (mutator) => { mutator.conflictOf = undefined; }); } diff --git a/app/assets/javascripts/components/NotesOptions/changeEditor/createEditorMenuGroups.ts b/app/assets/javascripts/components/NotesOptions/changeEditor/createEditorMenuGroups.ts index 1b59c6358..d69be1d46 100644 --- a/app/assets/javascripts/components/NotesOptions/changeEditor/createEditorMenuGroups.ts +++ b/app/assets/javascripts/components/NotesOptions/changeEditor/createEditorMenuGroups.ts @@ -1,11 +1,13 @@ import { WebApplication } from '@/ui_models/application'; import { + ContentType, + FeatureStatus, + SNComponent, ComponentArea, FeatureDescription, GetFeatures, NoteType, -} from '@standardnotes/features'; -import { ContentType, FeatureStatus, SNComponent } from '@standardnotes/snjs'; +} from '@standardnotes/snjs'; import { EditorMenuItem, EditorMenuGroup } from '../ChangeEditorOption'; export const PLAIN_EDITOR_NAME = 'Plain Editor'; diff --git a/app/assets/javascripts/components/Preferences/PreferencesMenu.ts b/app/assets/javascripts/components/Preferences/PreferencesMenu.ts index b9b474f63..f2a2843fb 100644 --- a/app/assets/javascripts/components/Preferences/PreferencesMenu.ts +++ b/app/assets/javascripts/components/Preferences/PreferencesMenu.ts @@ -1,12 +1,6 @@ import { action, makeAutoObservable, observable } from 'mobx'; import { ExtensionsLatestVersions } from '@/components/Preferences/panes/extensions-segments'; -import { - ComponentArea, - ContentType, - FeatureIdentifier, - SNComponent, - IconType, -} from '@standardnotes/snjs'; +import { FeatureIdentifier, IconType } from '@standardnotes/snjs'; import { WebApplication } from '@/ui_models/application'; const PREFERENCE_IDS = [ @@ -61,7 +55,6 @@ const READY_PREFERENCES_MENU_ITEMS: PreferencesMenuItem[] = [ export class PreferencesMenu { private _selectedPane: PreferenceId | FeatureIdentifier = 'account'; - private _extensionPanes: SNComponent[] = []; private _menu: PreferencesMenuItem[]; private _extensionLatestVersions: ExtensionsLatestVersions = new ExtensionsLatestVersions(new Map()); @@ -74,7 +67,6 @@ export class PreferencesMenu { ? PREFERENCES_MENU_ITEMS : READY_PREFERENCES_MENU_ITEMS; - this.loadExtensionsPanes(); this.loadLatestVersions(); makeAutoObservable< @@ -105,64 +97,24 @@ export class PreferencesMenu { return this._extensionLatestVersions; } - loadExtensionsPanes(): void { - const excludedComponents = [ - FeatureIdentifier.TwoFactorAuthManager, - 'org.standardnotes.batch-manager', - 'org.standardnotes.extensions-manager', - FeatureIdentifier.CloudLink, - ]; - this._extensionPanes = ( - this.application.items.getItems([ - ContentType.ActionsExtension, - ContentType.Component, - ContentType.Theme, - ]) as SNComponent[] - ).filter( - (extension) => - extension.area === ComponentArea.Modal && - !excludedComponents.includes(extension.package_info.identifier) - ); - } - get menuItems(): SelectableMenuItem[] { const menuItems = this._menu.map((preference) => ({ ...preference, selected: preference.id === this._selectedPane, })); - const extensionsMenuItems: SelectableMenuItem[] = this._extensionPanes.map( - (extension) => { - return { - icon: 'window', - id: extension.package_info.identifier, - label: extension.name, - selected: extension.package_info.identifier === this._selectedPane, - }; - } - ); - return menuItems.concat(extensionsMenuItems); + return menuItems; } get selectedMenuItem(): PreferencesMenuItem | undefined { return this._menu.find((item) => item.id === this._selectedPane); } - get selectedExtension(): SNComponent | undefined { - return this._extensionPanes.find( - (extension) => extension.package_info.identifier === this._selectedPane - ); - } - get selectedPaneId(): PreferenceId | FeatureIdentifier { if (this.selectedMenuItem != undefined) { return this.selectedMenuItem.id; } - if (this.selectedExtension != undefined) { - return this.selectedExtension.package_info.identifier; - } - return 'account'; } diff --git a/app/assets/javascripts/components/Preferences/PreferencesView.tsx b/app/assets/javascripts/components/Preferences/PreferencesView.tsx index dd615570a..f808c6458 100644 --- a/app/assets/javascripts/components/Preferences/PreferencesView.tsx +++ b/app/assets/javascripts/components/Preferences/PreferencesView.tsx @@ -1,6 +1,8 @@ import { RoundIconButton } from '@/components/RoundIconButton'; import { TitleBar, Title } from '@/components/TitleBar'; import { FunctionComponent } from 'preact'; +import { observer } from 'mobx-react-lite'; + import { AccountPreferences, HelpAndFeedback, @@ -8,15 +10,12 @@ import { General, Security, } from './panes'; -import { observer } from 'mobx-react-lite'; - import { PreferencesMenu } from './PreferencesMenu'; import { PreferencesMenuView } from './PreferencesMenuView'; import { WebApplication } from '@/ui_models/application'; import { MfaProps } from './panes/two-factor-auth/MfaProps'; import { AppState } from '@/ui_models/app_state'; import { useEffect, useMemo } from 'preact/hooks'; -import { ExtensionPane } from './panes/ExtensionPane'; import { Backups } from '@/components/Preferences/panes/Backups'; import { Appearance } from './panes/Appearance'; @@ -66,24 +65,13 @@ const PaneSelector: FunctionComponent< case 'help-feedback': return ; default: - if (menu.selectedExtension != undefined) { - return ( - - ); - } else { - return ( - - ); - } + return ( + + ); } }); diff --git a/app/assets/javascripts/components/Preferences/panes/Appearance.tsx b/app/assets/javascripts/components/Preferences/panes/Appearance.tsx index 3ca731a9b..5f7f16259 100644 --- a/app/assets/javascripts/components/Preferences/panes/Appearance.tsx +++ b/app/assets/javascripts/components/Preferences/panes/Appearance.tsx @@ -4,12 +4,12 @@ import { sortThemes } from '@/components/QuickSettingsMenu/QuickSettingsMenu'; import { HorizontalSeparator } from '@/components/Shared/HorizontalSeparator'; import { Switch } from '@/components/Switch'; import { WebApplication } from '@/ui_models/application'; -import { GetFeatures } from '@standardnotes/features'; import { ContentType, FeatureIdentifier, FeatureStatus, PrefKey, + GetFeatures, SNTheme, } from '@standardnotes/snjs'; import { observer } from 'mobx-react-lite'; @@ -61,9 +61,8 @@ export const Appearance: FunctionComponent = observer( ); useEffect(() => { - const themesAsItems: DropdownItem[] = ( - application.items.getDisplayableItems(ContentType.Theme) as SNTheme[] - ) + const themesAsItems: DropdownItem[] = application.items + .getDisplayableItems(ContentType.Theme) .filter((theme) => !theme.isLayerable()) .sort(sortThemes) .map((theme) => { diff --git a/app/assets/javascripts/components/Preferences/panes/ExtensionPane.tsx b/app/assets/javascripts/components/Preferences/panes/ExtensionPane.tsx deleted file mode 100644 index cac365104..000000000 --- a/app/assets/javascripts/components/Preferences/panes/ExtensionPane.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { - PreferencesGroup, - PreferencesSegment, -} from '@/components/Preferences/components'; -import { WebApplication } from '@/ui_models/application'; -import { ComponentViewer, SNComponent } from '@standardnotes/snjs'; -import { FeatureIdentifier } from '@standardnotes/features'; -import { observer } from 'mobx-react-lite'; -import { FunctionComponent } from 'preact'; -import { ExtensionItem } from './extensions-segments'; -import { ComponentView } from '@/components/ComponentView'; -import { AppState } from '@/ui_models/app_state'; -import { PreferencesMenu } from '@/components/Preferences/PreferencesMenu'; -import { useEffect, useState } from 'preact/hooks'; - -interface IProps { - application: WebApplication; - appState: AppState; - extension: SNComponent; - preferencesMenu: PreferencesMenu; -} - -const urlOverrideForExtension = (extension: SNComponent) => { - if (extension.identifier === FeatureIdentifier.CloudLink) { - return 'https://extensions.standardnotes.org/components/cloudlink'; - } else { - return undefined; - } -}; - -export const ExtensionPane: FunctionComponent = observer( - ({ extension, application, appState, preferencesMenu }) => { - const [componentViewer] = useState( - application.componentManager.createComponentViewer( - extension, - undefined, - undefined, - urlOverrideForExtension(extension) - ) - ); - const latestVersion = - preferencesMenu.extensionsLatestVersions.getVersion(extension); - - useEffect(() => { - return () => { - application.componentManager.destroyComponentViewer(componentViewer); - }; - }, [application, componentViewer]); - - return ( -
-
-
- - - application.mutator - .deleteItem(extension) - .then(() => preferencesMenu.loadExtensionsPanes()) - } - latestVersion={latestVersion} - /> - - - - -
-
-
- ); - } -); diff --git a/app/assets/javascripts/components/Preferences/panes/Extensions.tsx b/app/assets/javascripts/components/Preferences/panes/Extensions.tsx index 8c7c9a8e0..99ef28307 100644 --- a/app/assets/javascripts/components/Preferences/panes/Extensions.tsx +++ b/app/assets/javascripts/components/Preferences/panes/Extensions.tsx @@ -13,10 +13,11 @@ import { useEffect, useRef, useState } from 'preact/hooks'; import { observer } from 'mobx-react-lite'; const loadExtensions = (application: WebApplication) => - application.items.getItems( - [ContentType.ActionsExtension, ContentType.Component, ContentType.Theme], - true - ) as SNComponent[]; + application.items.getItems([ + ContentType.ActionsExtension, + ContentType.Component, + ContentType.Theme, + ]) as SNComponent[]; export const Extensions: FunctionComponent<{ application: WebApplication; diff --git a/app/assets/javascripts/components/Preferences/panes/backups-segments/EmailBackups.tsx b/app/assets/javascripts/components/Preferences/panes/backups-segments/EmailBackups.tsx index b3286718c..16d634bcd 100644 --- a/app/assets/javascripts/components/Preferences/panes/backups-segments/EmailBackups.tsx +++ b/app/assets/javascripts/components/Preferences/panes/backups-segments/EmailBackups.tsx @@ -13,16 +13,16 @@ import { Text, Title, } from '../../components'; -import { - EmailBackupFrequency, - MuteFailedBackupsEmailsOption, - SettingName, -} from '@standardnotes/settings'; import { Dropdown, DropdownItem } from '@/components/Dropdown'; import { Switch } from '@/components/Switch'; import { HorizontalSeparator } from '@/components/Shared/HorizontalSeparator'; -import { FeatureIdentifier } from '@standardnotes/features'; -import { FeatureStatus } from '@standardnotes/snjs'; +import { + FeatureStatus, + FeatureIdentifier, + EmailBackupFrequency, + MuteFailedBackupsEmailsOption, + SettingName, +} from '@standardnotes/snjs'; type Props = { application: WebApplication; diff --git a/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/CloudBackupProvider.tsx b/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/CloudBackupProvider.tsx index 64806d0ec..938c73911 100644 --- a/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/CloudBackupProvider.tsx +++ b/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/CloudBackupProvider.tsx @@ -1,11 +1,12 @@ import { useCallback, useEffect, useState } from 'preact/hooks'; -import { ButtonType, SettingName } from '@standardnotes/snjs'; import { + ButtonType, + SettingName, CloudProvider, DropboxBackupFrequency, GoogleDriveBackupFrequency, OneDriveBackupFrequency, -} from '@standardnotes/settings'; +} from '@standardnotes/snjs'; import { WebApplication } from '@/ui_models/application'; import { Button } from '@/components/Button'; import { isDev, openInNewTab } from '@/utils'; diff --git a/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/index.tsx b/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/index.tsx index 1ce07b1cb..a19b481fd 100644 --- a/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/index.tsx +++ b/app/assets/javascripts/components/Preferences/panes/backups-segments/cloud-backups/index.tsx @@ -9,14 +9,15 @@ import { Title, } from '@/components/Preferences/components'; import { HorizontalSeparator } from '@/components/Shared/HorizontalSeparator'; -import { FeatureIdentifier } from '@standardnotes/features'; -import { FeatureStatus } from '@standardnotes/snjs'; -import { FunctionComponent } from 'preact'; import { + FeatureStatus, + FeatureIdentifier, CloudProvider, MuteFailedCloudBackupsEmailsOption, SettingName, -} from '@standardnotes/settings'; +} from '@standardnotes/snjs'; +import { FunctionComponent } from 'preact'; + import { Switch } from '@/components/Switch'; import { convertStringifiedBooleanToBoolean } from '@/utils'; import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/strings'; diff --git a/app/assets/javascripts/components/Preferences/panes/extensions-segments/ConfirmCustomExtension.tsx b/app/assets/javascripts/components/Preferences/panes/extensions-segments/ConfirmCustomExtension.tsx index 362d3d24c..60333b60d 100644 --- a/app/assets/javascripts/components/Preferences/panes/extensions-segments/ConfirmCustomExtension.tsx +++ b/app/assets/javascripts/components/Preferences/panes/extensions-segments/ConfirmCustomExtension.tsx @@ -1,4 +1,4 @@ -import { displayStringForContentType, SNComponent } from '@standardnotes/snjs'; +import { DisplayStringForContentType, SNComponent } from '@standardnotes/snjs'; import { Button } from '@/components/Button'; import { FunctionComponent } from 'preact'; import { Title, Text, Subtitle, PreferencesSegment } from '../../components'; @@ -30,7 +30,7 @@ export const ConfirmCustomExtension: FunctionComponent<{ }, { label: 'Extension Type', - value: displayStringForContentType(component.content_type), + value: DisplayStringForContentType(component.content_type), }, ]; diff --git a/app/assets/javascripts/components/Preferences/panes/extensions-segments/ExtensionItem.tsx b/app/assets/javascripts/components/Preferences/panes/extensions-segments/ExtensionItem.tsx index 4dab16adb..316ee59a7 100644 --- a/app/assets/javascripts/components/Preferences/panes/extensions-segments/ExtensionItem.tsx +++ b/app/assets/javascripts/components/Preferences/panes/extensions-segments/ExtensionItem.tsx @@ -47,7 +47,7 @@ export const ExtensionItem: FunctionComponent = ({ const newOfflineOnly = !offlineOnly; setOfflineOnly(newOfflineOnly); application.mutator - .changeAndSaveItem(extension.uuid, (m: any) => { + .changeAndSaveItem(extension, (m: any) => { if (m.content == undefined) m.content = {}; m.content.offlineOnly = newOfflineOnly; }) @@ -63,7 +63,7 @@ export const ExtensionItem: FunctionComponent = ({ const changeExtensionName = (newName: string) => { setExtensionName(newName); application.mutator - .changeAndSaveItem(extension.uuid, (m: any) => { + .changeAndSaveItem(extension, (m: any) => { if (m.content == undefined) m.content = {}; m.content.name = newName; }) diff --git a/app/assets/javascripts/components/Preferences/panes/extensions-segments/ExtensionsLatestVersions.ts b/app/assets/javascripts/components/Preferences/panes/extensions-segments/ExtensionsLatestVersions.ts index 5ac51a842..6757dd813 100644 --- a/app/assets/javascripts/components/Preferences/panes/extensions-segments/ExtensionsLatestVersions.ts +++ b/app/assets/javascripts/components/Preferences/panes/extensions-segments/ExtensionsLatestVersions.ts @@ -1,6 +1,9 @@ import { WebApplication } from '@/ui_models/application'; -import { FeatureDescription } from '@standardnotes/features'; -import { SNComponent, ClientDisplayableError } from '@standardnotes/snjs'; +import { + SNComponent, + ClientDisplayableError, + FeatureDescription, +} from '@standardnotes/snjs'; import { makeAutoObservable, observable } from 'mobx'; export class ExtensionsLatestVersions { diff --git a/app/assets/javascripts/components/Preferences/panes/general-segments/Defaults.tsx b/app/assets/javascripts/components/Preferences/panes/general-segments/Defaults.tsx index 003cc9a39..fa5bd6c4e 100644 --- a/app/assets/javascripts/components/Preferences/panes/general-segments/Defaults.tsx +++ b/app/assets/javascripts/components/Preferences/panes/general-segments/Defaults.tsx @@ -34,7 +34,7 @@ const makeEditorDefault = ( if (currentDefault) { removeEditorDefault(application, currentDefault); } - application.mutator.changeAndSaveItem(component.uuid, (m) => { + application.mutator.changeAndSaveItem(component, (m) => { const mutator = m as ComponentMutator; mutator.defaultEditor = true; }); @@ -44,7 +44,7 @@ const removeEditorDefault = ( application: WebApplication, component: SNComponent ) => { - application.mutator.changeAndSaveItem(component.uuid, (m) => { + application.mutator.changeAndSaveItem(component, (m) => { const mutator = m as ComponentMutator; mutator.defaultEditor = false; }); diff --git a/app/assets/javascripts/components/Preferences/panes/general-segments/Labs.tsx b/app/assets/javascripts/components/Preferences/panes/general-segments/Labs.tsx index 9c36f06ba..0c14f55fb 100644 --- a/app/assets/javascripts/components/Preferences/panes/general-segments/Labs.tsx +++ b/app/assets/javascripts/components/Preferences/panes/general-segments/Labs.tsx @@ -1,4 +1,3 @@ -import { FindNativeFeature } from '@standardnotes/features'; import { Switch } from '@/components/Switch'; import { PreferencesGroup, @@ -8,7 +7,11 @@ import { Title, } from '@/components/Preferences/components'; import { WebApplication } from '@/ui_models/application'; -import { FeatureIdentifier, FeatureStatus } from '@standardnotes/snjs'; +import { + FeatureIdentifier, + FeatureStatus, + FindNativeFeature, +} from '@standardnotes/snjs'; import { FunctionComponent } from 'preact'; import { useCallback, useEffect, useState } from 'preact/hooks'; import { usePremiumModal } from '@/components/Premium'; diff --git a/app/assets/javascripts/components/Preferences/panes/security-segments/Privacy.tsx b/app/assets/javascripts/components/Preferences/panes/security-segments/Privacy.tsx index 78277a96a..5ae3843e2 100644 --- a/app/assets/javascripts/components/Preferences/panes/security-segments/Privacy.tsx +++ b/app/assets/javascripts/components/Preferences/panes/security-segments/Privacy.tsx @@ -12,7 +12,7 @@ import { MuteSignInEmailsOption, LogSessionUserAgentOption, SettingName, -} from '@standardnotes/settings'; +} from '@standardnotes/snjs'; import { observer } from 'mobx-react-lite'; import { FunctionalComponent } from 'preact'; import { useCallback, useEffect, useState } from 'preact/hooks'; diff --git a/app/assets/javascripts/components/QuickSettingsMenu/QuickSettingsMenu.tsx b/app/assets/javascripts/components/QuickSettingsMenu/QuickSettingsMenu.tsx index d2cbdcf52..daf69a3b2 100644 --- a/app/assets/javascripts/components/QuickSettingsMenu/QuickSettingsMenu.tsx +++ b/app/assets/javascripts/components/QuickSettingsMenu/QuickSettingsMenu.tsx @@ -103,15 +103,15 @@ export const QuickSettingsMenu: FunctionComponent = observer( }, [focusModeEnabled]); const reloadThemes = useCallback(() => { - const themes = ( - application.items.getDisplayableItems(ContentType.Theme) as SNTheme[] - ).map((item) => { - return { - name: item.name, - identifier: item.identifier, - component: item, - }; - }) as ThemeItem[]; + const themes = application.items + .getDisplayableItems(ContentType.Theme) + .map((item) => { + return { + name: item.name, + identifier: item.identifier, + component: item, + }; + }) as ThemeItem[]; GetFeatures() .filter( @@ -140,17 +140,15 @@ export const QuickSettingsMenu: FunctionComponent = observer( }, [application]); const reloadToggleableComponents = useCallback(() => { - const toggleableComponents = ( - application.items.getDisplayableItems( - ContentType.Component - ) as SNComponent[] - ).filter( - (component) => - [ComponentArea.EditorStack, ComponentArea.TagsList].includes( - component.area - ) && - component.identifier !== FeatureIdentifier.DeprecatedFoldersComponent - ); + const toggleableComponents = application.items + .getDisplayableItems(ContentType.Component) + .filter( + (component) => + [ComponentArea.EditorStack].includes(component.area) && + component.identifier !== + FeatureIdentifier.DeprecatedFoldersComponent + ); + setToggleableComponents(toggleableComponents); }, [application]); diff --git a/app/assets/javascripts/components/RevisionHistoryModal/HistoryListContainer.tsx b/app/assets/javascripts/components/RevisionHistoryModal/HistoryListContainer.tsx index 55748187a..6f16c6a21 100644 --- a/app/assets/javascripts/components/RevisionHistoryModal/HistoryListContainer.tsx +++ b/app/assets/javascripts/components/RevisionHistoryModal/HistoryListContainer.tsx @@ -134,7 +134,7 @@ export const HistoryListContainer: FunctionComponent = observer( throw new Error('Could not fetch revision'); } - setSelectedRevision(response.item as HistoryEntry); + setSelectedRevision(response.item as unknown as HistoryEntry); } catch (error) { console.error(error); setSelectedRevision(undefined); @@ -165,7 +165,7 @@ export const HistoryListContainer: FunctionComponent = observer( try { const remoteRevision = await application.historyManager.fetchRemoteRevision( - note.uuid, + note, revisionListEntry ); setSelectedRevision(remoteRevision); @@ -182,7 +182,7 @@ export const HistoryListContainer: FunctionComponent = observer( }, [ application, - note.uuid, + note, setIsFetchingSelectedRevision, setSelectedRemoteEntry, setSelectedRevision, diff --git a/app/assets/javascripts/components/RevisionHistoryModal/RevisionHistoryModalWrapper.tsx b/app/assets/javascripts/components/RevisionHistoryModal/RevisionHistoryModalWrapper.tsx index 2ec440528..78ddfc537 100644 --- a/app/assets/javascripts/components/RevisionHistoryModal/RevisionHistoryModalWrapper.tsx +++ b/app/assets/javascripts/components/RevisionHistoryModal/RevisionHistoryModalWrapper.tsx @@ -8,7 +8,6 @@ import { ButtonType, ContentType, HistoryEntry, - PayloadContent, PayloadSource, RevisionListEntry, SNNote, @@ -148,7 +147,7 @@ export const RevisionHistoryModal: FunctionComponent }).then((confirmed) => { if (confirmed) { application.mutator.changeAndSaveItem( - selectedRevision.payload.uuid, + originalNote, (mutator) => { mutator.unsafe_setCustomContent( selectedRevision.payload.content @@ -165,14 +164,14 @@ export const RevisionHistoryModal: FunctionComponent const restoreAsCopy = async () => { if (selectedRevision) { - const originalNote = application.items.findItem( + const originalNote = application.items.findSureItem( selectedRevision.payload.uuid - ) as SNNote; + ); const duplicatedItem = await application.mutator.duplicateItem( originalNote, { - ...(selectedRevision.payload.content as PayloadContent), + ...selectedRevision.payload.content, title: selectedRevision.payload.content.title ? selectedRevision.payload.content.title + ' (copy)' : undefined, @@ -188,10 +187,10 @@ export const RevisionHistoryModal: FunctionComponent useEffect(() => { const fetchTemplateNote = async () => { if (selectedRevision) { - const newTemplateNote = (await application.mutator.createTemplateItem( + const newTemplateNote = application.mutator.createTemplateItem( ContentType.Note, selectedRevision.payload.content - )) as SNNote; + ) as SNNote; setTemplateNoteForRevision(newTemplateNote); } @@ -218,7 +217,7 @@ export const RevisionHistoryModal: FunctionComponent setIsDeletingRevision(true); application.historyManager - .deleteRemoteRevision(note.uuid, selectedRemoteEntry) + .deleteRemoteRevision(note, selectedRemoteEntry) .then((res) => { if (res.error?.message) { throw new Error(res.error.message); diff --git a/app/assets/javascripts/components/RevisionPreviewModal.tsx b/app/assets/javascripts/components/RevisionPreviewModal.tsx index 2889e1498..204f65e1a 100644 --- a/app/assets/javascripts/components/RevisionPreviewModal.tsx +++ b/app/assets/javascripts/components/RevisionPreviewModal.tsx @@ -4,7 +4,7 @@ import { PayloadSource, SNNote, ComponentViewer, - PayloadContent, + NoteContent, } from '@standardnotes/snjs'; import { confirmDialog } from '@/services/alertService'; import { STRING_RESTORE_LOCKED_ATTEMPT } from '@/strings'; @@ -13,7 +13,7 @@ import { ComponentView } from './ComponentView'; interface Props { application: WebApplication; - content: PayloadContent; + content: NoteContent; title?: string; uuid: string; } @@ -74,7 +74,7 @@ export class RevisionPreviewModal extends PureComponent { }); } else { this.application.mutator.changeAndSaveItem( - this.props.uuid, + this.originalNote, (mutator) => { mutator.unsafe_setCustomContent(this.props.content); }, diff --git a/app/assets/javascripts/components/Tags/SmartViewsListItem.tsx b/app/assets/javascripts/components/Tags/SmartViewsListItem.tsx index 841c7c540..0b8f22c3e 100644 --- a/app/assets/javascripts/components/Tags/SmartViewsListItem.tsx +++ b/app/assets/javascripts/components/Tags/SmartViewsListItem.tsx @@ -110,30 +110,29 @@ export const SmartViewsListItem: FunctionComponent = observer( paddingLeft: `${level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`, }} > - {!view.errorDecrypting ? ( -
-
- -
- +
+ -
- {view.uuid === SystemViewId.AllNotes && tagsState.allNotesCount} -
- ) : null} + +
+ {view.uuid === SystemViewId.AllNotes && tagsState.allNotesCount} +
+
+ {!isSystemView(view) && (
{view.conflictOf && ( @@ -141,14 +140,7 @@ export const SmartViewsListItem: FunctionComponent = observer( Conflicted Copy {view.conflictOf}
)} - {view.errorDecrypting && !view.waitingForKey && ( -
Missing Keys
- )} - {view.errorDecrypting && view.waitingForKey && ( -
- Waiting For Keys -
- )} + {isSelected && (
{!isEditing && ( diff --git a/app/assets/javascripts/components/Tags/TagsListItem.tsx b/app/assets/javascripts/components/Tags/TagsListItem.tsx index 5e3cf1018..93b44e5d1 100644 --- a/app/assets/javascripts/components/Tags/TagsListItem.tsx +++ b/app/assets/javascripts/components/Tags/TagsListItem.tsx @@ -152,7 +152,7 @@ export const TagsListItem: FunctionComponent = observer( () => ({ accept: ItemTypes.TAG, canDrop: (item) => { - return tagsState.isValidTagParent(tag.uuid, item.uuid); + return tagsState.isValidTagParent(tag, item as SNTag); }, drop: (item) => { if (!hasFolders) { @@ -202,70 +202,61 @@ export const TagsListItem: FunctionComponent = observer( onContextMenu(tag, e.clientX, e.clientY); }} > - {!tag.errorDecrypting ? ( -
- {hasAtLeastOneFolder && ( -
- -
- )} -
- -
- -
+
+ {hasAtLeastOneFolder && ( +
-
{noteCounts.get()}
+ )} +
+
- ) : null} + +
+ +
{noteCounts.get()}
+
+
+
{tag.conflictOf && (
Conflicted Copy {tag.conflictOf}
)} - {tag.errorDecrypting && !tag.waitingForKey && ( -
Missing Keys
- )} - {tag.errorDecrypting && tag.waitingForKey && ( -
Waiting For Keys
- )}
{isAddingSubtag && ( diff --git a/app/assets/javascripts/services/archiveManager.ts b/app/assets/javascripts/services/archiveManager.ts index 78d31e2f9..bc9ca5438 100644 --- a/app/assets/javascripts/services/archiveManager.ts +++ b/app/assets/javascripts/services/archiveManager.ts @@ -1,11 +1,10 @@ import { WebApplication } from '@/ui_models/application'; import { parseFileName } from '@standardnotes/filepicker'; import { - EncryptionIntent, ContentType, - SNNote, BackupFile, - PayloadContent, + BackupFileDecryptedContextualPayload, + NoteContent, } from '@standardnotes/snjs'; function sanitizeFileName(name: string): string { @@ -79,6 +78,7 @@ export class ArchiveManager { const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'text/plain', }); + const fileName = zippableFileName('Standard Notes Backup and Import File'); await zipWriter.add(fileName, new zip.BlobReader(blob)); @@ -88,9 +88,9 @@ export class ArchiveManager { let name, contents; if (item.content_type === ContentType.Note) { - const note = item as SNNote; - name = (note.content as PayloadContent).title; - contents = (note.content as PayloadContent).text; + const note = item as BackupFileDecryptedContextualPayload; + name = note.content.title; + contents = note.content.text; } else { name = item.content_type; contents = JSON.stringify(item.content, null, 2); diff --git a/app/assets/javascripts/services/desktopManager.ts b/app/assets/javascripts/services/desktopManager.ts index c32ae85dd..412cba298 100644 --- a/app/assets/javascripts/services/desktopManager.ts +++ b/app/assets/javascripts/services/desktopManager.ts @@ -8,13 +8,11 @@ import { removeFromArray, DesktopManagerInterface, PayloadSource, - EncryptionIntent, - CreateIntentPayloadFromObject, + InternalEventBus, } from '@standardnotes/snjs'; import { WebAppEvent, WebApplication } from '@/ui_models/application'; import { isDesktopApplication } from '@/utils'; import { Bridge, ElectronDesktopCallbacks } from './bridge'; -import { InternalEventBus } from '@standardnotes/services'; /** * An interface used by the Desktop application to interact with SN @@ -68,10 +66,7 @@ export class DesktopManager * Keys are not passed into ItemParams, so the result is not encrypted */ convertComponentForTransmission(component: SNComponent) { - return CreateIntentPayloadFromObject( - component.payloadRepresentation(), - EncryptionIntent.FileDecrypted - ); + return component.payloadRepresentation().ejected(); } // All `components` should be installed @@ -84,11 +79,7 @@ export class DesktopManager return this.convertComponentForTransmission(component); }) ).then((payloads) => { - this.bridge.syncComponents( - payloads.filter( - (payload) => !payload.errorDecrypting && !payload.waitingForKey - ) - ); + this.bridge.syncComponents(payloads); }); } @@ -137,7 +128,7 @@ export class DesktopManager return; } const updatedComponent = await this.application.mutator.changeAndSaveItem( - component.uuid, + component, (m) => { const mutator = m as ComponentMutator; if (error) { diff --git a/app/assets/javascripts/services/themeManager.ts b/app/assets/javascripts/services/themeManager.ts index b598499d0..68031c36b 100644 --- a/app/assets/javascripts/services/themeManager.ts +++ b/app/assets/javascripts/services/themeManager.ts @@ -1,7 +1,6 @@ import { WebApplication } from '@/ui_models/application'; import { StorageValueModes, - EncryptionIntent, ApplicationService, SNTheme, removeFromArray, @@ -11,9 +10,9 @@ import { FeatureStatus, PayloadSource, PrefKey, - CreateIntentPayloadFromObject, + CreateDecryptedLocalStorageContextPayload, + InternalEventBus, } from '@standardnotes/snjs'; -import { InternalEventBus } from '@standardnotes/services'; const CACHED_THEMES_KEY = 'cachedThemes'; @@ -156,9 +155,9 @@ export class ThemeManager extends ApplicationService { const preference = prefersDarkColorScheme ? PrefKey.AutoDarkThemeIdentifier : PrefKey.AutoLightThemeIdentifier; - const themes = this.application.items.getDisplayableItems( + const themes = this.application.items.getDisplayableItems( ContentType.Theme - ) as SNTheme[]; + ); const enableDefaultTheme = () => { const activeTheme = themes.find( @@ -206,7 +205,8 @@ export class ThemeManager extends ApplicationService { this.unregisterStream = this.application.streamItems( ContentType.Theme, - (items, source) => { + ({ changed, inserted, source }) => { + const items = changed.concat(inserted); const themes = items as SNTheme[]; for (const theme of themes) { if (theme.active) { @@ -275,10 +275,7 @@ export class ThemeManager extends ApplicationService { const mapped = themes.map((theme) => { const payload = theme.payloadRepresentation(); - return CreateIntentPayloadFromObject( - payload, - EncryptionIntent.LocalStorageDecrypted - ); + return CreateDecryptedLocalStorageContextPayload(payload); }); return this.application.setValue( diff --git a/app/assets/javascripts/ui_models/app_state/account_menu_state.ts b/app/assets/javascripts/ui_models/app_state/account_menu_state.ts index ce9064880..5bb879a6b 100644 --- a/app/assets/javascripts/ui_models/app_state/account_menu_state.ts +++ b/app/assets/javascripts/ui_models/app_state/account_menu_state.ts @@ -6,7 +6,12 @@ import { observable, runInAction, } from 'mobx'; -import { ApplicationEvent, ContentType, SNItem } from '@standardnotes/snjs'; +import { + ApplicationEvent, + ContentType, + SNNote, + SNTag, +} from '@standardnotes/snjs'; import { WebApplication } from '@/ui_models/application'; import { AccountMenuPane } from '@/components/AccountMenu'; @@ -23,7 +28,7 @@ export class AccountMenuState { otherSessionsSignOut = false; server: string | undefined = undefined; enableServerOption = false; - notesAndTags: SNItem[] = []; + notesAndTags: (SNNote | SNTag)[] = []; isEncryptionEnabled = false; encryptionStatusString = ''; isBackupEncrypted = false; diff --git a/app/assets/javascripts/ui_models/app_state/app_state.ts b/app/assets/javascripts/ui_models/app_state/app_state.ts index 8c6dc4e27..ac1e97623 100644 --- a/app/assets/javascripts/ui_models/app_state/app_state.ts +++ b/app/assets/javascripts/ui_models/app_state/app_state.ts @@ -8,13 +8,14 @@ import { ContentType, DeinitSource, NoteViewController, - PayloadSource, PrefKey, SNNote, SmartView, SNTag, SystemViewId, removeFromArray, + PayloadSource, + Uuid, } from '@standardnotes/snjs'; import { action, @@ -276,9 +277,9 @@ export class AppState { this.application.noteControllerGroup.closeAllNoteViews(); } - noteControllerForNote(note: SNNote) { + noteControllerForNote(uuid: Uuid) { for (const controller of this.getNoteControllers()) { - if (controller.note.uuid === note.uuid) { + if (controller.note.uuid === uuid) { return controller; } } @@ -328,43 +329,61 @@ export class AppState { } streamNotesAndTags() { - this.application.streamItems( + this.application.streamItems( [ContentType.Note, ContentType.Tag], - async (items, source) => { + async ({ changed, inserted, removed, source }) => { + if ( + ![PayloadSource.PreSyncSave, PayloadSource.RemoteRetrieved].includes( + source + ) + ) { + return; + } + + const removedNotes = removed.filter( + (i) => i.content_type === ContentType.Note + ); + + for (const removedNote of removedNotes) { + const noteController = this.noteControllerForNote(removedNote.uuid); + if (noteController) { + this.closeNoteController(noteController); + } + } + + const changedOrInserted = [...changed, ...inserted].filter( + (i) => i.content_type === ContentType.Note + ); + const selectedTag = this.tags.selected; - /** Close any note controllers for deleted/trashed/archived notes */ - if (source === PayloadSource.PreSyncSave) { - const notes = items.filter( - (candidate) => candidate.content_type === ContentType.Note - ) as SNNote[]; - for (const note of notes) { - const noteController = this.noteControllerForNote(note); - if (!noteController) { - continue; - } - if (note.deleted) { - this.closeNoteController(noteController); - } else if ( - note.trashed && - !( - selectedTag instanceof SmartView && - selectedTag.uuid === SystemViewId.TrashedNotes - ) && - !this.searchOptions.includeTrashed - ) { - this.closeNoteController(noteController); - } else if ( - note.archived && - !( - selectedTag instanceof SmartView && - selectedTag.uuid === SystemViewId.ArchivedNotes - ) && - !this.searchOptions.includeArchived && - !this.application.getPreference(PrefKey.NotesShowArchived, false) - ) { - this.closeNoteController(noteController); - } + for (const note of changedOrInserted) { + const noteController = this.noteControllerForNote(note.uuid); + if (!noteController) { + continue; + } + + const isBrowswingTrashedNotes = + selectedTag instanceof SmartView && + selectedTag.uuid === SystemViewId.TrashedNotes; + + const isBrowsingArchivedNotes = + selectedTag instanceof SmartView && + selectedTag.uuid === SystemViewId.ArchivedNotes; + + if ( + note.trashed && + !isBrowswingTrashedNotes && + !this.searchOptions.includeTrashed + ) { + this.closeNoteController(noteController); + } else if ( + note.archived && + !isBrowsingArchivedNotes && + !this.searchOptions.includeArchived && + !this.application.getPreference(PrefKey.NotesShowArchived, false) + ) { + this.closeNoteController(noteController); } } } @@ -436,11 +455,9 @@ export class AppState { /** Returns the tags that are referncing this note */ public getNoteTags(note: SNNote) { - return this.application.items - .itemsReferencingItem(note.uuid) - .filter((ref) => { - return ref.content_type === ContentType.Tag; - }) as SNTag[]; + return this.application.items.itemsReferencingItem(note).filter((ref) => { + return ref.content_type === ContentType.Tag; + }) as SNTag[]; } panelDidResize(name: string, collapsed: boolean) { diff --git a/app/assets/javascripts/ui_models/app_state/note_tags_state.ts b/app/assets/javascripts/ui_models/app_state/note_tags_state.ts index 238da65aa..a5f26c786 100644 --- a/app/assets/javascripts/ui_models/app_state/note_tags_state.ts +++ b/app/assets/javascripts/ui_models/app_state/note_tags_state.ts @@ -215,7 +215,7 @@ export class NoteTagsState { async removeTagFromActiveNote(tag: SNTag): Promise { const { activeNote } = this; if (activeNote) { - await this.application.mutator.changeItem(tag.uuid, (mutator) => { + await this.application.mutator.changeItem(tag, (mutator) => { mutator.removeItemAsRelationship(activeNote); }); this.application.sync.sync(); diff --git a/app/assets/javascripts/ui_models/app_state/notes_state.ts b/app/assets/javascripts/ui_models/app_state/notes_state.ts index 0dec3b8d0..c01ecc378 100644 --- a/app/assets/javascripts/ui_models/app_state/notes_state.ts +++ b/app/assets/javascripts/ui_models/app_state/notes_state.ts @@ -60,15 +60,22 @@ export class NotesState { }); appEventListeners.push( - application.streamItems(ContentType.Note, (notes) => { - runInAction(() => { - for (const note of notes) { - if (this.selectedNotes[note.uuid]) { - this.selectedNotes[note.uuid] = note as SNNote; + application.streamItems( + ContentType.Note, + ({ changed, inserted, removed }) => { + runInAction(() => { + for (const removedNote of removed) { + delete this.selectedNotes[removedNote.uuid]; } - } - }); - }) + + for (const note of [...changed, ...inserted]) { + if (this.selectedNotes[note.uuid]) { + this.selectedNotes[note.uuid] = note; + } + } + }); + } + ) ); } @@ -85,9 +92,8 @@ export class NotesState { } private async selectNotesRange(selectedNote: SNNote): Promise { - const notes = this.application.items.getDisplayableItems( - ContentType.Note - ) as SNNote[]; + const notes = this.application.items.getDisplayableNotes(); + const lastSelectedNoteIndex = notes.findIndex( (note) => note.uuid == this.lastSelectedNote?.uuid ); @@ -179,10 +185,6 @@ export class NotesState { this.appState.noteTags.reloadTags(); await this.onActiveEditorChanged(); - - if (note.waitingForKey) { - this.application.presentKeyRecoveryWizard(); - } } setContextMenuOpen(open: boolean): void { @@ -263,7 +265,7 @@ export class NotesState { mutate: (mutator: NoteMutator) => void ): Promise { await this.application.mutator.changeItems( - Object.keys(this.selectedNotes), + Object.values(this.selectedNotes), mutate, false ); @@ -399,7 +401,7 @@ export class NotesState { async toggleGlobalSpellcheckForNote(note: SNNote) { await this.application.mutator.changeItem( - note.uuid, + note, (mutator) => { mutator.toggleSpellcheck(); }, @@ -410,11 +412,11 @@ export class NotesState { async addTagToSelectedNotes(tag: SNTag): Promise { const selectedNotes = Object.values(this.selectedNotes); - const parentChainTags = this.application.items.getTagParentChain(tag.uuid); + const parentChainTags = this.application.items.getTagParentChain(tag); const tagsToAdd = [...parentChainTags, tag]; await Promise.all( tagsToAdd.map(async (tag) => { - await this.application.mutator.changeItem(tag.uuid, (mutator) => { + await this.application.mutator.changeItem(tag, (mutator) => { for (const note of selectedNotes) { mutator.addItemAsRelationship(note); } @@ -426,7 +428,7 @@ export class NotesState { async removeTagFromSelectedNotes(tag: SNTag): Promise { const selectedNotes = Object.values(this.selectedNotes); - await this.application.mutator.changeItem(tag.uuid, (mutator) => { + await this.application.mutator.changeItem(tag, (mutator) => { for (const note of selectedNotes) { mutator.removeItemAsRelationship(note); } diff --git a/app/assets/javascripts/ui_models/app_state/notes_view_state.ts b/app/assets/javascripts/ui_models/app_state/notes_view_state.ts index f2dd350c8..1130d3534 100644 --- a/app/assets/javascripts/ui_models/app_state/notes_view_state.ts +++ b/app/assets/javascripts/ui_models/app_state/notes_view_state.ts @@ -1,6 +1,7 @@ import { ApplicationEvent, CollectionSort, + CollectionSortProperty, ContentType, findInArray, NotesDisplayCriteria, @@ -28,7 +29,7 @@ const ELEMENT_ID_SEARCH_BAR = 'search-bar'; const ELEMENT_ID_SCROLL_CONTAINER = 'notes-scrollable'; export type DisplayOptions = { - sortBy: CollectionSort; + sortBy: CollectionSortProperty; sortReverse: boolean; hidePinned: boolean; showArchived: boolean; @@ -73,18 +74,20 @@ export class NotesViewState { this.resetPagination(); appObservers.push( - application.streamItems(ContentType.Note, () => { + application.streamItems(ContentType.Note, () => { this.reloadNotes(); + const activeNote = this.appState.notes.activeNoteController?.note; + if (this.application.getAppState().notes.selectedNotesCount < 2) { if (activeNote) { - const discarded = activeNote.deleted || activeNote.trashed; + const browsingTrashedNotes = + this.appState.selectedTag instanceof SmartView && + this.appState.selectedTag?.uuid === SystemViewId.TrashedNotes; + if ( - discarded && - !( - this.appState.selectedTag instanceof SmartView && - this.appState.selectedTag?.uuid === SystemViewId.TrashedNotes - ) && + activeNote.trashed && + !browsingTrashedNotes && !this.appState?.searchOptions.includeTrashed ) { this.selectNextOrCreateNew(); @@ -96,19 +99,24 @@ export class NotesViewState { } } }), - application.streamItems([ContentType.Tag], async (items) => { - const tags = items as SNTag[]; - /** A tag could have changed its relationships, so we need to reload the filter */ - this.reloadNotesDisplayOptions(); - this.reloadNotes(); - if ( - this.appState.selectedTag && - findInArray(tags, 'uuid', this.appState.selectedTag.uuid) - ) { - /** Tag title could have changed */ - this.reloadPanelTitle(); + + application.streamItems( + [ContentType.Tag], + async ({ changed, inserted }) => { + const tags = [...changed, ...inserted]; + /** A tag could have changed its relationships, so we need to reload the filter */ + this.reloadNotesDisplayOptions(); + this.reloadNotes(); + + if ( + this.appState.selectedTag && + findInArray(tags, 'uuid', this.appState.selectedTag.uuid) + ) { + /** Tag title could have changed */ + this.reloadPanelTitle(); + } } - }), + ), application.addEventObserver(async () => { this.reloadPreferences(); }, ApplicationEvent.PreferencesChanged), @@ -223,9 +231,7 @@ export class NotesViewState { if (!tag) { return; } - const notes = this.application.items.getDisplayableItems( - ContentType.Note - ) as SNNote[]; + const notes = this.application.items.getDisplayableNotes(); const renderedNotes = notes.slice(0, this.notesToDisplay); this.notes = notes; @@ -250,7 +256,7 @@ export class NotesViewState { } const criteria = NotesDisplayCriteria.Create({ - sortProperty: this.displayOptions.sortBy as CollectionSort, + sortProperty: this.displayOptions.sortBy, sortDirection: this.displayOptions.sortReverse ? 'asc' : 'dsc', tags: tag instanceof SNTag ? [tag] : [], views: tag instanceof SmartView ? [tag] : [], @@ -498,7 +504,7 @@ export class NotesViewState { handleEditorChange = async () => { const activeNote = this.appState.getActiveNoteController()?.note; if (activeNote && activeNote.conflictOf) { - this.application.mutator.changeAndSaveItem(activeNote.uuid, (mutator) => { + this.application.mutator.changeAndSaveItem(activeNote, (mutator) => { mutator.conflictOf = undefined; }); } diff --git a/app/assets/javascripts/ui_models/app_state/tags_state.ts b/app/assets/javascripts/ui_models/app_state/tags_state.ts index e03dc419c..acf1fee80 100644 --- a/app/assets/javascripts/ui_models/app_state/tags_state.ts +++ b/app/assets/javascripts/ui_models/app_state/tags_state.ts @@ -14,6 +14,7 @@ import { TagMutator, UuidString, isSystemView, + FindItem, } from '@standardnotes/snjs'; import { action, @@ -29,11 +30,9 @@ import { FeaturesState, SMART_TAGS_FEATURE_NAME } from './features_state'; type AnyTag = SNTag | SmartView; const rootTags = (application: SNApplication): SNTag[] => { - const hasNoParent = (tag: SNTag) => !application.items.getTagParent(tag.uuid); + const hasNoParent = (tag: SNTag) => !application.items.getTagParent(tag); - const allTags = application.items.getDisplayableItems( - ContentType.Tag - ) as SNTag[]; + const allTags = application.items.getDisplayableItems(ContentType.Tag); const rootTags = allTags.filter(hasNoParent); return rootTags; @@ -44,10 +43,10 @@ const tagSiblings = (application: SNApplication, tag: SNTag): SNTag[] => { tags.filter((other) => other.uuid !== tag.uuid); const isTemplateTag = application.items.isTemplateItem(tag); - const parentTag = !isTemplateTag && application.items.getTagParent(tag.uuid); + const parentTag = !isTemplateTag && application.items.getTagParent(tag); if (parentTag) { - const siblingsAndTag = application.items.getTagChildren(parentTag.uuid); + const siblingsAndTag = application.items.getTagChildren(parentTag); return withoutCurrentTag(siblingsAndTag); } @@ -148,24 +147,24 @@ export class TagsState { appEventListeners.push( this.application.streamItems( [ContentType.Tag, ContentType.SmartView], - (items) => { + ({ changed, removed }) => { runInAction(() => { this.tags = this.application.items.getDisplayableItems( ContentType.Tag ); + this.smartViews = this.application.items.getSmartViews(); const selectedTag = this.selected_; + if (selectedTag && !isSystemView(selectedTag as SmartView)) { - const matchingTag = items.find( - (candidate) => candidate.uuid === selectedTag.uuid - ) as AnyTag; - if (matchingTag) { - if (matchingTag.deleted) { - this.selected_ = this.smartViews[0]; - } else { - this.selected_ = matchingTag; - } + if (FindItem(removed, selectedTag.uuid)) { + this.selected_ = this.smartViews[0]; + } + + const updated = FindItem(changed, selectedTag.uuid); + if (updated) { + this.selected_ = updated as AnyTag; } } else { this.selected_ = this.smartViews[0]; @@ -202,7 +201,7 @@ export class TagsState { title )) as SNTag; - const futureSiblings = this.application.items.getTagChildren(parent.uuid); + const futureSiblings = this.application.items.getTagChildren(parent); if (!isValidFutureSiblings(this.application, futureSiblings, createdTag)) { this.setAddingSubtagTo(undefined); @@ -319,7 +318,7 @@ export class TagsState { return []; } - const children = this.application.items.getTagChildren(tag.uuid); + const children = this.application.items.getTagChildren(tag); const childrenUuids = children.map((childTag) => childTag.uuid); const childrenTags = this.tags.filter((tag) => @@ -328,8 +327,8 @@ export class TagsState { return childrenTags; } - isValidTagParent(parentUuid: UuidString, tagUuid: UuidString): boolean { - return this.application.items.isValidTagParent(parentUuid, tagUuid); + isValidTagParent(parent: SNTag, tag: SNTag): boolean { + return this.application.items.isValidTagParent(parent, tag); } public hasParent(tagUuid: UuidString): boolean { @@ -343,7 +342,7 @@ export class TagsState { ): Promise { const tag = this.application.items.findItem(tagUuid) as SNTag; - const currentParent = this.application.items.getTagParent(tag.uuid); + const currentParent = this.application.items.getTagParent(tag); const currentParentUuid = currentParent?.uuid; if (currentParentUuid === futureParentUuid) { @@ -361,9 +360,8 @@ export class TagsState { } await this.application.mutator.unsetTagParent(tag); } else { - const futureSiblings = this.application.items.getTagChildren( - futureParent.uuid - ); + const futureSiblings = + this.application.items.getTagChildren(futureParent); if (!isValidFutureSiblings(this.application, futureSiblings, tag)) { return; } @@ -374,9 +372,7 @@ export class TagsState { } get rootTags(): SNTag[] { - return this.tags.filter( - (tag) => !this.application.items.getTagParent(tag.uuid) - ); + return this.tags.filter((tag) => !this.application.items.getTagParent(tag)); } get tagsCount(): number { @@ -401,7 +397,7 @@ export class TagsState { public set selected(tag: AnyTag | undefined) { if (tag && tag.conflictOf) { - this.application.mutator.changeAndSaveItem(tag.uuid, (mutator) => { + this.application.mutator.changeAndSaveItem(tag, (mutator) => { mutator.conflictOf = undefined; }); } @@ -417,12 +413,9 @@ export class TagsState { } public setExpanded(tag: SNTag, expanded: boolean) { - this.application.mutator.changeAndSaveItem( - tag.uuid, - (mutator) => { - mutator.expanded = expanded; - } - ); + this.application.mutator.changeAndSaveItem(tag, (mutator) => { + mutator.expanded = expanded; + }); } public get selectedUuid(): UuidString | undefined { @@ -527,7 +520,7 @@ export class TagsState { }); } else { await this.application.mutator.changeAndSaveItem( - tag.uuid, + tag, (mutator) => { mutator.title = newTitle; } @@ -563,9 +556,7 @@ export class TagsState { } public get hasAtLeastOneFolder(): boolean { - return this.tags.some( - (tag) => !!this.application.items.getTagParent(tag.uuid) - ); + return this.tags.some((tag) => !!this.application.items.getTagParent(tag)); } } diff --git a/app/assets/javascripts/ui_models/application.ts b/app/assets/javascripts/ui_models/application.ts index 8d06cd055..e51ca5cfa 100644 --- a/app/assets/javascripts/ui_models/application.ts +++ b/app/assets/javascripts/ui_models/application.ts @@ -75,15 +75,16 @@ export class WebApplication extends SNApplication { if (source === DeinitSource.AppGroupUnload) { this.getThemeService().deactivateAllThemes(); } + for (const service of Object.values(this.webServices)) { if ('deinit' in service) { service.deinit?.(source); } (service as any).application = undefined; } + this.webServices = {} as WebServices; this.noteControllerGroup.deinit(); - this.iconsController.deinit(); this.webEventObservers.length = 0; if (source === DeinitSource.SignOut) { diff --git a/app/assets/javascripts/ui_models/application_group.ts b/app/assets/javascripts/ui_models/application_group.ts index 8feb4c7c4..f391b333b 100644 --- a/app/assets/javascripts/ui_models/application_group.ts +++ b/app/assets/javascripts/ui_models/application_group.ts @@ -6,6 +6,7 @@ import { DeviceInterface, Platform, Runtime, + InternalEventBus, } from '@standardnotes/snjs'; import { AppState } from '@/ui_models/app_state'; import { Bridge } from '@/services/bridge'; @@ -16,7 +17,6 @@ import { IOService } from '@/services/ioService'; import { AutolockService } from '@/services/autolock_service'; import { StatusManager } from '@/services/statusManager'; import { ThemeManager } from '@/services/themeManager'; -import { InternalEventBus } from '@standardnotes/services'; export class ApplicationGroup extends SNApplicationGroup { constructor( diff --git a/package.json b/package.json index ae404118b..f26895e8f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "standard-notes-web", - "version": "3.14.0", + "version": "3.15.0", "license": "AGPL-3.0-or-later", "repository": { "type": "git", @@ -26,11 +26,6 @@ "@babel/plugin-transform-react-jsx": "^7.17.3", "@babel/preset-env": "^7.16.11", "@babel/preset-typescript": "^7.16.7", - "@reach/disclosure": "^0.16.2", - "@reach/visually-hidden": "^0.16.0", - "@standardnotes/responses": "1.5.1", - "@standardnotes/services": "1.7.1", - "@standardnotes/stylekit": "5.20.0", "@svgr/webpack": "^6.2.1", "@types/jest": "^27.4.1", "@types/react": "^17.0.42", @@ -65,26 +60,27 @@ "webpack-merge": "^5.8.0" }, "dependencies": { - "@reach/alert": "^0.16.0", "@reach/alert-dialog": "^0.16.2", + "@reach/alert": "^0.16.0", "@reach/checkbox": "^0.16.0", "@reach/dialog": "^0.16.2", + "@reach/disclosure": "^0.16.2", "@reach/listbox": "^0.16.2", "@reach/tooltip": "^0.16.2", + "@reach/visually-hidden": "^0.16.0", "@standardnotes/components": "1.7.14", - "@standardnotes/features": "1.36.3", - "@standardnotes/filepicker": "1.10.4", - "@standardnotes/settings": "1.13.2", - "@standardnotes/sncrypto-web": "1.8.1", - "@standardnotes/snjs": "2.93.3", + "@standardnotes/filepicker": "1.10.5", + "@standardnotes/sncrypto-web": "1.8.2", + "@standardnotes/snjs": "2.94.3", + "@standardnotes/stylekit": "5.21.3", "@zip.js/zip.js": "^2.4.7", - "mobx": "^6.5.0", "mobx-react-lite": "^3.3.0", + "mobx": "^6.5.0", "preact": "^10.6.6", "qrcode.react": "^2.0.0", - "react-dnd": "^15.1.1", "react-dnd-html5-backend": "^15.1.2", - "react-dnd-touch-backend": "^15.1.1" + "react-dnd-touch-backend": "^15.1.1", + "react-dnd": "^15.1.1" }, "lint-staged": { "app/**/*.{js,ts,jsx,tsx}": "eslint --cache --fix", diff --git a/yarn.lock b/yarn.lock index 771c0a0db..b457e95f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2388,132 +2388,122 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@standardnotes/auth@^3.18.3": - version "3.18.3" - resolved "https://registry.yarnpkg.com/@standardnotes/auth/-/auth-3.18.3.tgz#2c2aa19ad56fc5f3f286dbef56bd8496d1e5380f" - integrity sha512-crdpVHJpnY574IIwBM1QcqNMULyvQ8nOnkH4DhFNcfWF7R+A+S4lMg2KxN9bR+j2gM/WWhbfcU8owJrz1+vsqA== +"@standardnotes/auth@^3.18.5": + version "3.18.5" + resolved "https://registry.yarnpkg.com/@standardnotes/auth/-/auth-3.18.5.tgz#11087e0bc31c42e489a7f546d317bbbcbd48d573" + integrity sha512-NSeU3A9iDyZFLLfv6jOyaweykMbjUUe0XoZo6lVifQucsRW0VJ4R6m3aeXqx6/zDwmHIBqVVzrX2bqQ7r2s9SA== dependencies: - "@standardnotes/common" "^1.19.1" + "@standardnotes/common" "^1.19.3" jsonwebtoken "^8.5.1" -"@standardnotes/common@^1.19.1": - version "1.19.1" - resolved "https://registry.yarnpkg.com/@standardnotes/common/-/common-1.19.1.tgz#45f0837b40bc1c583c22552a53429fe26c5ef498" - integrity sha512-O114ZdOvur6U1mmiPfvEo/TZjKRxHWBsAAAn+XTtS70E+2VqgvCwgiYT6bG1oUcoyrIiCdRPPyiTC/UPF4gkXg== +"@standardnotes/common@^1.19.3": + version "1.19.3" + resolved "https://registry.yarnpkg.com/@standardnotes/common/-/common-1.19.3.tgz#ae2ca493492eb5e0d9663abf736a9d7a26365c52" + integrity sha512-nMqH+grkIgnODr5EncbG9yHqIxSBHLVTiAb+NZ2EvkhLBiuVhP2UEDNs8KcZKfgNVGGDIHQbjEXZKGog9J6gZw== "@standardnotes/components@1.7.14": version "1.7.14" resolved "https://registry.yarnpkg.com/@standardnotes/components/-/components-1.7.14.tgz#ddd5b4d5787d3f90a4e1a88cfd95995f9267b1d1" integrity sha512-NDzP8/lmzgFBjxfmaE3OSOjPfozs3vednFfrjmjri5kCXlfClEISL6b/kh6B6wv/x9DIFveOsRj2Lrov+5IXdw== -"@standardnotes/domain-events@^2.26.6": - version "2.26.6" - resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.26.6.tgz#6d19099b147f60dfe69a458463aa81759846507a" - integrity sha512-CiF7MlFlZgwzMbOkcHGOy8FL1iGlSff9s7eUOlgOcYoidolFOF8HHJJn+d8+iwEvwANDwMJmrrGcFf5X9f0wzA== +"@standardnotes/domain-events@^2.26.9": + version "2.26.9" + resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.26.9.tgz#09d3ac547e263ff957a9a645a6c1f0039aa85ccd" + integrity sha512-iQCiCdLpMw3Yp3Z9q7GU9Z48tK2jAMI32VjsQtbyqOmjR+aVmo4e2oGyshm/2+5ymKUiG7xlx3Hl63RlQbGf1A== dependencies: - "@standardnotes/auth" "^3.18.3" - "@standardnotes/features" "^1.36.3" + "@standardnotes/auth" "^3.18.5" + "@standardnotes/features" "^1.37.2" -"@standardnotes/encryption@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@standardnotes/encryption/-/encryption-1.1.3.tgz#7554a6268d8f274c59bb9dd55117ba7dffefb5cd" - integrity sha512-0oelxlDMCR8I6l33R/CsdU9z25R+kCvYLt0FbypPCRaDOMTcjITR1R+VsnKznw/GbcMxcD1TTnDGRRQyLVmDmw== +"@standardnotes/encryption@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@standardnotes/encryption/-/encryption-1.2.2.tgz#27325dff46875871c26e208d77651532573a7afc" + integrity sha512-B9RjWltLuURg6qUdFTQZeQRKX2DoP6VL/6kS2Ay3ZkrEEcCNvxeuqr9yvXbZn2kKS0dUDfzfbYWOvoVxyyUwYA== dependencies: - "@standardnotes/models" "^1.1.1" - "@standardnotes/payloads" "^1.5.1" - "@standardnotes/responses" "^1.5.1" - "@standardnotes/services" "^1.7.1" + "@standardnotes/models" "^1.2.2" + "@standardnotes/responses" "^1.6.2" + "@standardnotes/services" "^1.8.2" -"@standardnotes/features@1.36.3", "@standardnotes/features@^1.36.3": - version "1.36.3" - resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.36.3.tgz#c3a2c2451fe2f036c5c94e51e86c804872028763" - integrity sha512-/38iTb22NULjtL8MitUeqsZdGwZgyP6t8p2LPc5sLFmeyU/CgZ22sh55GKAW5P/fm/oWyBqK6zjsVvtIH6AQug== +"@standardnotes/features@^1.37.2": + version "1.37.2" + resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.37.2.tgz#bedae2935a5659aa1fd30849e47ed167d45a7d3a" + integrity sha512-kNUCRMuLPmjjxWvE/OjHAewGZzv5/NAsqw/cHj+O4sbhRBWSv1dq+UzLzUxnj2kUsKObPjKqYeqo6WrXOnl3BQ== dependencies: - "@standardnotes/auth" "^3.18.3" - "@standardnotes/common" "^1.19.1" + "@standardnotes/auth" "^3.18.5" + "@standardnotes/common" "^1.19.3" -"@standardnotes/filepicker@1.10.4": - version "1.10.4" - resolved "https://registry.yarnpkg.com/@standardnotes/filepicker/-/filepicker-1.10.4.tgz#a69822381dcb7910ce7ce9040bb0466b3b950985" - integrity sha512-BnfKi+HFXX1e/fprZ2awvcrBSQkVZs1VN/hk7e9hH8qhQtbktfURKEEyOZoQnDu14BMa1tSdAVTjhXpxlbRRcA== +"@standardnotes/filepicker@1.10.5": + version "1.10.5" + resolved "https://registry.yarnpkg.com/@standardnotes/filepicker/-/filepicker-1.10.5.tgz#28c7cc68cb3337940a52e19b1dea76af343f2852" + integrity sha512-Tl9mCW/qAzupOtQAYlbPHgZU16ljtRGV0awOHT7+uulPYoyKJJ4cqlKRzFaaONTAN6GpICEeSqidcB/lb5e5uQ== -"@standardnotes/models@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@standardnotes/models/-/models-1.1.1.tgz#1a54253ded5c759ac8eeb1cb2878da73da2bd8a3" - integrity sha512-tl6Yjv/hlPd1xARF4o8vHNPyfoV0d5V/IkdlPA0I2GQh7pLPxHirwD5E2+rRnv59HPiV4ws+XwLtnnPZaZ38bg== +"@standardnotes/models@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@standardnotes/models/-/models-1.2.2.tgz#d67086319ad12ec5f6d267f77d353a0bd3740983" + integrity sha512-o762wf4pOobk4GcHJR0+lFVJeP/TifiP4OCM9ko23wkE6d6tWpM5SyvOUyZga2NNp5He8Pkm06Oo1ObxBYaWIw== dependencies: - "@standardnotes/payloads" "^1.5.1" + "@standardnotes/features" "^1.37.2" + "@standardnotes/responses" "^1.6.2" + "@standardnotes/utils" "^1.4.8" -"@standardnotes/payloads@^1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@standardnotes/payloads/-/payloads-1.5.1.tgz#f0cbe309721a14811d4b11cfce9a66d6fb9c2171" - integrity sha512-wqL31WPGFAQPMXICCf5Kxh3UOiaGbMu6ZE8cYmuZsMhti2h8FgIE04rcrzAh0/dSYtufrfHUnjhMmkPXZQAV2g== +"@standardnotes/responses@^1.6.2": + version "1.6.2" + resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.6.2.tgz#665702c01bd25f10763ef0230fe9df775996c424" + integrity sha512-w/SNFITk7aipmN1nahH456xe/xKGPp+/dqpKF+LDoSl6C+UZ17NOtSVP/Q4nVIvGy57QOD8OvN7inCpSrLCEyw== dependencies: - "@standardnotes/common" "^1.19.1" - "@standardnotes/features" "^1.36.3" - "@standardnotes/utils" "^1.4.6" + "@standardnotes/auth" "^3.18.5" + "@standardnotes/common" "^1.19.3" + "@standardnotes/features" "^1.37.2" -"@standardnotes/responses@1.5.1", "@standardnotes/responses@^1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.5.1.tgz#a88171e0834ad363ce2284256f8630f8adee4ae3" - integrity sha512-8BodIxtIfSG9IEzCSQy2dmB9RR1FeoKYBwOrO4MKyX1TpvVPlr0dtGUxWtbt20kI49FSLU9QDeWeexNiXcDSrA== +"@standardnotes/services@^1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.8.2.tgz#3a95af1573636dc288dc4efd52de8568c2cd68fe" + integrity sha512-+iLVngtw0avyoUM4Sn0Kpmh99KTWYbhX/HiJLbnFoW5LJrqA2FarZRPUqYpiKuEcfcdZ4brmm5ipts45n1DXXw== dependencies: - "@standardnotes/auth" "^3.18.3" - "@standardnotes/common" "^1.19.1" - "@standardnotes/features" "^1.36.3" - "@standardnotes/payloads" "^1.5.1" + "@standardnotes/common" "^1.19.3" + "@standardnotes/models" "^1.2.2" + "@standardnotes/responses" "^1.6.2" + "@standardnotes/utils" "^1.4.8" -"@standardnotes/services@1.7.1", "@standardnotes/services@^1.7.1": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.7.1.tgz#7c3f8f379478dfeeec3b9c87868a380213947533" - integrity sha512-xW5C/nqUomwxnN2zSS22t845PPRceevUNqtwFtPzodeaDNZpCMwLvHPqJhbXW6cYuPeVbPGn4ify8EnrGqu+/w== +"@standardnotes/settings@^1.13.3": + version "1.13.3" + resolved "https://registry.yarnpkg.com/@standardnotes/settings/-/settings-1.13.3.tgz#6f46927f5cb85e3070ccd2bc6a91deadf1b9ef9f" + integrity sha512-hLb5ba8qFgKdhSYqJLX+7L5K2ZPwoqGlMrDDQTph+rQe08FnDoupCzz+uFOO1EJITI3XzrbvSW79GQYV0/5AkA== + +"@standardnotes/sncrypto-common@^1.7.5": + version "1.7.5" + resolved "https://registry.yarnpkg.com/@standardnotes/sncrypto-common/-/sncrypto-common-1.7.5.tgz#2c4ca3923970f5360f8ae01d40e2eaa957b75c12" + integrity sha512-VfGNDAlju4h7Ai7Z7shds41Lvl7JQruYc4pemkAzcmYgrXLHy/wHMUA0kanGTW7fVr3AYmbYCqO6lycldAmrwQ== + +"@standardnotes/sncrypto-web@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@standardnotes/sncrypto-web/-/sncrypto-web-1.8.2.tgz#cf60a2ad85240e3ef56ccd5d1b45c29d16300966" + integrity sha512-C/2EkZrYBKTgnW4uluhJ3+GOnbbOL6ixg/c9pa2LZ9zT1vBRaS3vFIHC5hIMwrOsPE1QmIaJyiGtdzMA7A3VMw== dependencies: - "@standardnotes/common" "^1.19.1" - "@standardnotes/models" "^1.1.1" - "@standardnotes/responses" "^1.5.1" - "@standardnotes/utils" "^1.4.6" - -"@standardnotes/settings@1.13.2", "@standardnotes/settings@^1.13.2": - version "1.13.2" - resolved "https://registry.yarnpkg.com/@standardnotes/settings/-/settings-1.13.2.tgz#32509823e9f1b885282d5f6e82a6fed5178e5ec2" - integrity sha512-kA2K2/xfS3dlPF//yy2GitH6bfFf4EmvNQ77OWMn1qZdLlTl4HTGps1Q5mX/BrLfC9HNutxqnLFr1N94vxdWlQ== - -"@standardnotes/sncrypto-common@^1.7.4": - version "1.7.4" - resolved "https://registry.yarnpkg.com/@standardnotes/sncrypto-common/-/sncrypto-common-1.7.4.tgz#970fbe84edbdc9d632c8774ec201f1e140f693d6" - integrity sha512-6O4RjyfNyCFV32sYCO7jxDt/UelPfbvaMQXYPJ3F58r5gyFdc9K/PxjWmKhzRVxTprNLr+4uWbf1FUERTdTuhg== - -"@standardnotes/sncrypto-web@1.8.1": - version "1.8.1" - resolved "https://registry.yarnpkg.com/@standardnotes/sncrypto-web/-/sncrypto-web-1.8.1.tgz#4e8192be81c2b6da2d39d4119ea95ceeb24c49a0" - integrity sha512-lTuFu8WNmUh/9+OApgBj0IU55svXEK5gQRpE9Wdn49mzPZUQx7FrrkQ8piKDBrkpxFoaeQXXgNNWk3CwGQ8WCQ== - dependencies: - "@standardnotes/sncrypto-common" "^1.7.4" + "@standardnotes/sncrypto-common" "^1.7.5" buffer "^6.0.3" libsodium-wrappers "^0.7.9" -"@standardnotes/snjs@2.93.3": - version "2.93.3" - resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.93.3.tgz#528c257994b8602666af0d80930e55421d9d5946" - integrity sha512-XZS8vBDqc80lEYKndyNIiyZSPme1DU7H6XNCUBH5mt41CF8qvxv76eTFSxmi2oZNrNNujl/Ez1jb23F7oUEMrw== +"@standardnotes/snjs@2.94.3": + version "2.94.3" + resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.94.3.tgz#93918769025f4883f80555df61c88a838de1c4c3" + integrity sha512-wfJg8n/p1QisPlxWSyW9dYqN79/Zr16lugryHG0Tc1vXRyLcDNbaYxvo5XR3gGjsml8zARn5NdXJEkBBdPN2xA== dependencies: - "@standardnotes/auth" "^3.18.3" - "@standardnotes/common" "^1.19.1" - "@standardnotes/domain-events" "^2.26.6" - "@standardnotes/encryption" "^1.1.3" - "@standardnotes/features" "^1.36.3" - "@standardnotes/models" "^1.1.1" - "@standardnotes/payloads" "^1.5.1" - "@standardnotes/responses" "^1.5.1" - "@standardnotes/services" "^1.7.1" - "@standardnotes/settings" "^1.13.2" - "@standardnotes/sncrypto-common" "^1.7.4" - "@standardnotes/utils" "^1.4.6" + "@standardnotes/auth" "^3.18.5" + "@standardnotes/common" "^1.19.3" + "@standardnotes/domain-events" "^2.26.9" + "@standardnotes/encryption" "^1.2.2" + "@standardnotes/features" "^1.37.2" + "@standardnotes/models" "^1.2.2" + "@standardnotes/responses" "^1.6.2" + "@standardnotes/services" "^1.8.2" + "@standardnotes/settings" "^1.13.3" + "@standardnotes/sncrypto-common" "^1.7.5" + "@standardnotes/utils" "^1.4.8" -"@standardnotes/stylekit@5.20.0": - version "5.20.0" - resolved "https://registry.yarnpkg.com/@standardnotes/stylekit/-/stylekit-5.20.0.tgz#84ad262b39cbe307a9e06ffa8eb05119db8a7adb" - integrity sha512-R926S0NlzB97wq6PyX978s1g21KSymX3CjQCmbM3tfV7KFXfNjjDdWSTVetC8exZj/BPvsudfOtNA5bVsJ8RkA== +"@standardnotes/stylekit@5.21.3": + version "5.21.3" + resolved "https://registry.yarnpkg.com/@standardnotes/stylekit/-/stylekit-5.21.3.tgz#32d136328e7ec04f983fe635ec507a05084f3aac" + integrity sha512-0ILhE/xtuGBbBuMRurdWDuHrtMvIoJoMwu/2wp+2WNlYzWbSzq/TQ3MYYBUUS76K/nerxJwr7kBtZeJpCdWccg== dependencies: "@nanostores/preact" "^0.1.3" "@reach/listbox" "^0.16.2" @@ -2524,12 +2514,12 @@ nanostores "^0.5.10" prop-types "^15.8.1" -"@standardnotes/utils@^1.4.6": - version "1.4.6" - resolved "https://registry.yarnpkg.com/@standardnotes/utils/-/utils-1.4.6.tgz#19fadae46b594e301731989a836e1e9025ec4749" - integrity sha512-8k/ucqtfZd/tl7zBA5E988Kbo+9RiGq70ZNiXjvGhud8hX2JUfUtVqnpjTCIEChKyJhOJR3uVQZBHq9H9S0+lg== +"@standardnotes/utils@^1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@standardnotes/utils/-/utils-1.4.8.tgz#4c984220903bf64733961c50633de6adf62cb78f" + integrity sha512-sGROUIUdDncSyAb4w1O+qadJOTp18+9XO8MX08jOEPEMTfmVNFV1xYu6ZWe/0Ae4wCghBr8XeCCfVeE1XNyjTg== dependencies: - "@standardnotes/common" "^1.19.1" + "@standardnotes/common" "^1.19.3" dompurify "^2.3.6" lodash "^4.17.21"