refactor: component manager usecases (#2354)

This commit is contained in:
Mo
2023-07-13 05:46:52 -05:00
committed by GitHub
parent ecc5b5e503
commit 2c68ea1d76
52 changed files with 1454 additions and 1078 deletions

View File

@@ -33,7 +33,7 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
const noteType = noteViewController?.isTemplateNote
? noteTypeForEditorIdentifier(
application.geDefaultEditorIdentifier(
application.componentManager.getDefaultEditorIdentifier(
noteViewController.templateNoteOptions?.tag
? application.items.findItem(noteViewController.templateNoteOptions.tag)
: undefined,

View File

@@ -4,7 +4,7 @@ import { usePremiumModal } from '@/Hooks/usePremiumModal'
import { STRING_EDIT_LOCKED_ATTEMPT } from '@/Constants/Strings'
import { WebApplication } from '@/Application/WebApplication'
import {
ComponentOrNativeFeature,
UIFeature,
EditorFeatureDescription,
FeatureIdentifier,
IframeComponentFeatureDescription,
@@ -30,7 +30,7 @@ type ChangeEditorMenuProps = {
closeMenu: () => void
isVisible: boolean
note: SNNote | undefined
onSelect?: (component: ComponentOrNativeFeature<EditorFeatureDescription | IframeComponentFeatureDescription>) => void
onSelect?: (component: UIFeature<EditorFeatureDescription | IframeComponentFeatureDescription>) => void
setDisableClickOutside?: (value: boolean) => void
}
@@ -46,7 +46,7 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
}) => {
const groups = useMemo(() => createEditorMenuGroups(application), [application])
const [currentFeature, setCurrentFeature] =
useState<ComponentOrNativeFeature<EditorFeatureDescription | IframeComponentFeatureDescription>>()
useState<UIFeature<EditorFeatureDescription | IframeComponentFeatureDescription>>()
const [pendingConversionItem, setPendingConversionItem] = useState<EditorMenuItem | null>(null)
const showSuperNoteImporter =
@@ -83,10 +83,7 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
)
const selectComponent = useCallback(
async (
uiFeature: ComponentOrNativeFeature<EditorFeatureDescription | IframeComponentFeatureDescription>,
note: SNNote,
) => {
async (uiFeature: UIFeature<EditorFeatureDescription | IframeComponentFeatureDescription>, note: SNNote) => {
if (uiFeature.isComponent && uiFeature.asComponent.conflictOf) {
void application.changeAndSaveItem(uiFeature.asComponent, (mutator) => {
mutator.conflictOf = undefined

View File

@@ -3,7 +3,7 @@ import { STRING_EDIT_LOCKED_ATTEMPT } from '@/Constants/Strings'
import { usePremiumModal } from '@/Hooks/usePremiumModal'
import { createEditorMenuGroups } from '@/Utils/createEditorMenuGroups'
import {
ComponentOrNativeFeature,
UIFeature,
EditorFeatureDescription,
IframeComponentFeatureDescription,
NoteMutator,
@@ -40,10 +40,7 @@ const ChangeEditorMultipleMenu = ({ application, notes, setDisableClickOutside }
const groups = useMemo(() => createEditorMenuGroups(application), [application])
const selectComponent = useCallback(
async (
uiFeature: ComponentOrNativeFeature<EditorFeatureDescription | IframeComponentFeatureDescription>,
note: SNNote,
) => {
async (uiFeature: UIFeature<EditorFeatureDescription | IframeComponentFeatureDescription>, note: SNNote) => {
if (uiFeature.isComponent && uiFeature.asComponent.conflictOf) {
void application.changeAndSaveItem(uiFeature.asComponent, (mutator) => {
mutator.conflictOf = undefined

View File

@@ -66,7 +66,7 @@ const NewNotePreferences: FunctionComponent<Props> = ({
const [customNoteTitleFormat, setCustomNoteTitleFormat] = useState('')
const getGlobalEditorDefaultIdentifier = useCallback((): string => {
return application.geDefaultEditorIdentifier()
return application.componentManager.getDefaultEditorIdentifier()
}, [application])
const reloadPreferences = useCallback(() => {

View File

@@ -1,6 +1,6 @@
import { WebApplication } from '@/Application/WebApplication'
import { QuickSettingsController } from '@/Controllers/QuickSettingsController'
import { ComponentOrNativeFeature, GetDarkThemeFeature } from '@standardnotes/snjs'
import { UIFeature, GetDarkThemeFeature } from '@standardnotes/snjs'
import { TOGGLE_DARK_MODE_COMMAND } from '@standardnotes/ui-services'
import { classNames } from '@standardnotes/utils'
import { useEffect, useRef } from 'react'
@@ -25,7 +25,7 @@ const QuickSettingsButton = ({ application, isOpen, toggleMenu, quickSettingsMen
return commandService.addCommandHandler({
command: TOGGLE_DARK_MODE_COMMAND,
onKeyDown: () => {
void application.componentManager.toggleTheme(new ComponentOrNativeFeature(GetDarkThemeFeature()))
void application.componentManager.toggleTheme(new UIFeature(GetDarkThemeFeature()))
},
})
}, [application, commandService])

View File

@@ -33,7 +33,6 @@ describe('note view controller', () => {
application.sync.sync = jest.fn().mockReturnValue(Promise.resolve())
componentManager = {} as jest.Mocked<SNComponentManager>
componentManager.legacyGetDefaultEditor = jest.fn()
Object.defineProperty(application, 'componentManager', { value: componentManager })
const mutator = {} as jest.Mocked<MutatorClientInterface>
@@ -41,7 +40,7 @@ describe('note view controller', () => {
})
it('should create notes with plaintext note type', async () => {
application.geDefaultEditorIdentifier = jest.fn().mockReturnValue(FeatureIdentifier.PlainEditor)
application.componentManager.getDefaultEditorIdentifier = jest.fn().mockReturnValue(FeatureIdentifier.PlainEditor)
const controller = new NoteViewController(application)
await controller.initialize()
@@ -54,15 +53,15 @@ describe('note view controller', () => {
})
it('should create notes with markdown note type', async () => {
componentManager.legacyGetDefaultEditor = jest.fn().mockReturnValue({
identifier: FeatureIdentifier.MarkdownProEditor,
} as SNComponent)
application.items.getDisplayableComponents = jest.fn().mockReturnValue([
{
identifier: FeatureIdentifier.MarkdownProEditor,
} as SNComponent,
])
componentManager.componentOrNativeFeatureForIdentifier = jest.fn().mockReturnValue({
identifier: FeatureIdentifier.MarkdownProEditor,
} as SNComponent)
application.geDefaultEditorIdentifier = jest.fn().mockReturnValue(FeatureIdentifier.MarkdownProEditor)
application.componentManager.getDefaultEditorIdentifier = jest
.fn()
.mockReturnValue(FeatureIdentifier.MarkdownProEditor)
const controller = new NoteViewController(application)
await controller.initialize()
@@ -75,7 +74,7 @@ describe('note view controller', () => {
})
it('should add tag to note if default tag is set', async () => {
application.geDefaultEditorIdentifier = jest.fn().mockReturnValue(FeatureIdentifier.PlainEditor)
application.componentManager.getDefaultEditorIdentifier = jest.fn().mockReturnValue(FeatureIdentifier.PlainEditor)
const tag = {
uuid: 'tag-uuid',

View File

@@ -94,7 +94,7 @@ export class NoteViewController implements ItemViewControllerInterface {
if (!this.item) {
log(LoggingDomain.NoteView, 'Initializing as template note')
const editorIdentifier = this.application.geDefaultEditorIdentifier(this.defaultTag)
const editorIdentifier = this.application.componentManager.getDefaultEditorIdentifier(this.defaultTag)
const noteType = noteTypeForEditorIdentifier(editorIdentifier)

View File

@@ -13,12 +13,12 @@ import {
ApplicationEvent,
ComponentArea,
ComponentInterface,
ComponentOrNativeFeature,
UIFeature,
ComponentViewerInterface,
ContentType,
EditorLineWidth,
IframeComponentFeatureDescription,
isIframeUIFeature,
isUIFeatureAnIframeFeature,
isPayloadSourceInternalChange,
isPayloadSourceRetrieved,
NoteType,
@@ -456,7 +456,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
})
}
private createComponentViewer(component: ComponentOrNativeFeature<IframeComponentFeatureDescription>) {
private createComponentViewer(component: UIFeature<IframeComponentFeatureDescription>) {
if (!component) {
throw Error('Cannot create component viewer for undefined component')
}
@@ -516,7 +516,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
const newUIFeature = this.application.componentManager.editorForNote(this.note)
/** Component editors cannot interact with template notes so the note must be inserted */
if (isIframeUIFeature(newUIFeature) && this.controller.isTemplateNote) {
if (isUIFeatureAnIframeFeature(newUIFeature) && this.controller.isTemplateNote) {
await this.controller.insertTemplatedNote()
}
@@ -529,7 +529,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
}
}
if (isIframeUIFeature(newUIFeature)) {
if (isUIFeatureAnIframeFeature(newUIFeature)) {
this.setState({
editorComponentViewer: this.createComponentViewer(newUIFeature),
editorStateDidLoad: true,
@@ -767,7 +767,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
for (const component of needsNewViewer) {
newViewers.push(
this.application.componentManager.createComponentViewer(
new ComponentOrNativeFeature<IframeComponentFeatureDescription>(component),
new UIFeature<IframeComponentFeatureDescription>(component),
{
uuid: this.note.uuid,
},

View File

@@ -1,4 +1,4 @@
import { ContentType, NoteContent, NoteType, SNNote, classNames, isIframeUIFeature } from '@standardnotes/snjs'
import { ContentType, NoteContent, NoteType, SNNote, classNames, isUIFeatureAnIframeFeature } from '@standardnotes/snjs'
import { UIEventHandler, useEffect, useMemo, useRef } from 'react'
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
import { useApplication } from '../ApplicationProvider'
@@ -31,7 +31,7 @@ export const ReadonlyNoteContent = ({
const componentViewer = useMemo(() => {
const editorForCurrentNote = application.componentManager.editorForNote(note)
if (!isIframeUIFeature(editorForCurrentNote)) {
if (!isUIFeatureAnIframeFeature(editorForCurrentNote)) {
return undefined
}

View File

@@ -1,11 +1,7 @@
import {
ComponentOrNativeFeature,
EditorFeatureDescription,
IframeComponentFeatureDescription,
} from '@standardnotes/snjs'
import { UIFeature, EditorFeatureDescription, IframeComponentFeatureDescription } from '@standardnotes/snjs'
export type EditorMenuItem = {
uiFeature: ComponentOrNativeFeature<EditorFeatureDescription | IframeComponentFeatureDescription>
uiFeature: UIFeature<EditorFeatureDescription | IframeComponentFeatureDescription>
isEntitled: boolean
isLabs?: boolean
}

View File

@@ -1,17 +1,12 @@
import Icon from '@/Components/Icon/Icon'
import { FunctionComponent } from 'react'
import {
ComponentOrNativeFeature,
EditorFeatureDescription,
IframeComponentFeatureDescription,
SNNote,
} from '@standardnotes/snjs'
import { UIFeature, EditorFeatureDescription, IframeComponentFeatureDescription, SNNote } from '@standardnotes/snjs'
import { NotesController } from '@/Controllers/NotesController/NotesController'
import { iconClass } from './ClassNames'
import MenuSwitchButtonItem from '../Menu/MenuSwitchButtonItem'
export const SpellcheckOptions: FunctionComponent<{
editorForNote: ComponentOrNativeFeature<EditorFeatureDescription | IframeComponentFeatureDescription>
editorForNote: UIFeature<EditorFeatureDescription | IframeComponentFeatureDescription>
notesController: NotesController
note: SNNote
}> = ({ editorForNote, notesController, note }) => {

View File

@@ -24,7 +24,7 @@ const PermissionsModal = ({ callback, component, dismiss, permissionsString }: P
return (
<Modal
title="Activate Component"
title="Activate Plugin"
close={deny}
actions={[
{ label: 'Cancel', onClick: deny, type: 'cancel', mobileSlot: 'left' },
@@ -52,10 +52,7 @@ const PermissionsModal = ({ callback, component, dismiss, permissionsString }: P
</div>
<div className="sk-panel-row [word-break:break-word]">
<p className="sk-p">
Components use an offline messaging system to communicate. Learn more at{' '}
<a href="https://standardnotes.com/permissions" rel="noopener" target="_blank" className="sk-a info">
https://standardnotes.com/permissions.
</a>
Plugins use an offline messaging system to communicate and can only access the current note.
</p>
</div>
</div>

View File

@@ -20,11 +20,7 @@ const PermissionsModalWrapper: FunctionComponent<Props> = ({ application }) => {
}, [])
const onAppStart = useCallback(() => {
application.componentManager.presentPermissionsDialog = presentPermissionsDialog
return () => {
;(application.componentManager.presentPermissionsDialog as unknown) = undefined
}
application.componentManager.setPermissionDialogUIHandler(presentPermissionsDialog)
}, [application, presentPermissionsDialog])
useEffect(() => {

View File

@@ -1,7 +1,7 @@
import {
ComponentArea,
ComponentInterface,
ComponentOrNativeFeature,
UIFeature,
ContentType,
FeatureIdentifier,
PreferencesServiceEvent,
@@ -31,7 +31,7 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ quickSettingsMenuCont
const { focusModeEnabled, setFocusModeEnabled } = application.paneController
const { closeQuickSettingsMenu } = quickSettingsMenuController
const [themes, setThemes] = useState<ComponentOrNativeFeature<ThemeFeatureDescription>[]>([])
const [themes, setThemes] = useState<UIFeature<ThemeFeatureDescription>[]>([])
const [editorStackComponents, setEditorStackComponents] = useState<ComponentInterface[]>([])
const activeThemes = application.componentManager.getActiveThemes()

View File

@@ -1,9 +1,4 @@
import {
ComponentOrNativeFeature,
FeatureIdentifier,
FeatureStatus,
ThemeFeatureDescription,
} from '@standardnotes/snjs'
import { UIFeature, FeatureIdentifier, FeatureStatus, ThemeFeatureDescription } from '@standardnotes/snjs'
import { FunctionComponent, MouseEventHandler, useCallback, useMemo } from 'react'
import Icon from '@/Components/Icon/Icon'
import { usePremiumModal } from '@/Hooks/usePremiumModal'
@@ -18,7 +13,7 @@ import { KeyboardShortcutIndicator } from '../KeyboardShortcutIndicator/Keyboard
import { useApplication } from '../ApplicationProvider'
type Props = {
uiFeature: ComponentOrNativeFeature<ThemeFeatureDescription>
uiFeature: UIFeature<ThemeFeatureDescription>
}
const ThemesMenuButton: FunctionComponent<Props> = ({ uiFeature }) => {

View File

@@ -3,7 +3,7 @@ import {
NoteContent,
NoteType,
SNNote,
isIframeUIFeature,
isUIFeatureAnIframeFeature,
spaceSeparatedStrings,
} from '@standardnotes/snjs'
import { useCallback, useEffect, useMemo } from 'react'
@@ -61,7 +61,7 @@ const SuperNoteConverter = ({
}, [format, note])
const componentViewer = useMemo(() => {
if (!uiFeature || !isIframeUIFeature(uiFeature)) {
if (!uiFeature || !isUIFeatureAnIframeFeature(uiFeature)) {
return undefined
}