fix: handle retrieving deleted components

This commit is contained in:
Baptiste Grob
2020-07-15 12:21:18 +02:00
parent 9a02dd623b
commit c6a25d6ae4
4 changed files with 68 additions and 124 deletions

View File

@@ -7,7 +7,7 @@ import {
SNTheme, SNTheme,
ComponentArea, ComponentArea,
removeFromArray, removeFromArray,
ApplicationEvent, ApplicationEvent
} from 'snjs'; } from 'snjs';
import { AppStateEvent } from '@/ui_models/app_state'; import { AppStateEvent } from '@/ui_models/app_state';
@@ -85,11 +85,11 @@ export class ThemeManager extends ApplicationService {
this.unregisterComponent = this.application!.componentManager!.registerHandler({ this.unregisterComponent = this.application!.componentManager!.registerHandler({
identifier: 'themeManager', identifier: 'themeManager',
areas: [ComponentArea.Themes], areas: [ComponentArea.Themes],
activationHandler: (component) => { activationHandler: (uuid, component) => {
if (component.active) { if (component?.active) {
this.activateTheme(component as SNTheme); this.activateTheme(component as SNTheme);
} else { } else {
this.deactivateTheme(component.uuid); this.deactivateTheme(uuid);
} }
} }
}); });

View File

@@ -59,8 +59,8 @@ type NoteStatus = {
type EditorState = { type EditorState = {
stackComponents: SNComponent[] stackComponents: SNComponent[]
activeEditorComponent?: SNComponent editorComponent?: SNComponent
activeTagsComponent?: SNComponent tagsComponent?: SNComponent
saveError?: any saveError?: any
noteStatus?: NoteStatus noteStatus?: NoteStatus
tagsAsStrings?: string tagsAsStrings?: string
@@ -74,9 +74,11 @@ type EditorState = {
showSessionHistory: boolean showSessionHistory: boolean
altKeyDown: boolean altKeyDown: boolean
spellcheck: boolean spellcheck: boolean
/** Setting to false then true will allow the current editor component-view to be destroyed /**
* then re-initialized. Used when changing between component editors. */ * Setting to false then true will allow the current editor component-view to be destroyed
editorComponentUnloading: boolean * then re-initialized. Used when changing between component editors.
*/
editorUnloading: boolean
/** Setting to true then false will allow the main content textarea to be destroyed /** Setting to true then false will allow the main content textarea to be destroyed
* then re-initialized. Used when reloading spellcheck status. */ * then re-initialized. Used when reloading spellcheck status. */
textareaUnloading: boolean textareaUnloading: boolean
@@ -112,7 +114,6 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
private removeTrashKeyObserver?: any private removeTrashKeyObserver?: any
private removeDeleteKeyObserver?: any private removeDeleteKeyObserver?: any
private removeTabObserver?: any private removeTabObserver?: any
private removeComponentGroupObserver: any
private removeTagsObserver!: () => void private removeTagsObserver!: () => void
private removeComponentsObserver!: () => void private removeComponentsObserver!: () => void
@@ -148,8 +149,6 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
this.removeComponentsObserver(); this.removeComponentsObserver();
(this.removeTagsObserver as any) = undefined; (this.removeTagsObserver as any) = undefined;
(this.removeComponentsObserver as any) = undefined; (this.removeComponentsObserver as any) = undefined;
this.removeComponentGroupObserver();
this.removeComponentGroupObserver = undefined;
this.removeAltKeyObserver(); this.removeAltKeyObserver();
this.removeAltKeyObserver = undefined; this.removeAltKeyObserver = undefined;
this.removeTrashKeyObserver(); this.removeTrashKeyObserver();
@@ -204,25 +203,6 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
} }
} }
}); });
this.removeComponentGroupObserver = this.componentGroup.addChangeObserver(
async () => {
const currentEditor = this.activeEditorComponent;
const newEditor = this.componentGroup.activeComponentForArea(ComponentArea.Editor);
if (currentEditor && newEditor && currentEditor.uuid !== newEditor.uuid) {
/** Unload current component view so that we create a new one,
* then change the active editor */
await this.setState({
editorComponentUnloading: true
});
}
this.setState({
activeEditorComponent: newEditor,
activeTagsComponent: this.componentGroup.activeComponentForArea(ComponentArea.NoteTags),
/** Stop unloading, if we were already unloading */
editorComponentUnloading: false
});
}
)
} }
/** @override */ /** @override */
@@ -239,7 +219,7 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
showSessionHistory: false, showSessionHistory: false,
altKeyDown: false, altKeyDown: false,
noteStatus: undefined, noteStatus: undefined,
editorComponentUnloading: false, editorUnloading: false,
textareaUnloading: false, textareaUnloading: false,
mutable: { mutable: {
tagsString: '' tagsString: ''
@@ -288,18 +268,6 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
} }
} }
get activeEditorComponent() {
return this.state.activeEditorComponent;
}
get activeTagsComponent() {
return this.state.activeTagsComponent;
}
get componentGroup() {
return this.application.componentGroup;
}
async handleEditorNoteChange() { async handleEditorNoteChange() {
this.cancelPendingSetStatus(); this.cancelPendingSetStatus();
await this.setState({ await this.setState({
@@ -313,37 +281,15 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
const note = this.editor.note; const note = this.editor.note;
this.editorValues.title = note.title; this.editorValues.title = note.title;
this.editorValues.text = note.text; this.editorValues.text = note.text;
await this.reloadComponentEditorState(); this.reloadEditor();
this.reloadTagsString(); this.reloadTagsString();
this.reloadPreferences(); this.reloadPreferences();
this.reloadComponentContext(); this.reloadStackComponents();
if (note.safeText().length === 0) { if (note.safeText().length === 0) {
this.focusTitle(); this.focusTitle();
} }
} }
async reloadComponentEditorState(): Promise<{ editor?: SNComponent, changed: boolean }> {
const editor = this.application.componentManager!.editorForNote(this.note);
if (!editor) {
let changed: boolean;
if (this.activeEditorComponent) {
await this.componentGroup.deactivateComponentForArea(ComponentArea.Editor);
changed = true;
} else {
changed = false;
}
return { editor, changed };
}
if (editor.uuid === this.activeEditorComponent?.uuid) {
/** Same editor, no change */
return { editor, changed: false };
}
await this.componentGroup.activateComponent(editor);
return { editor, changed: true };
}
/** /**
* Because note.locked accesses note.content.appData, * Because note.locked accesses note.content.appData,
* we do not want to expose the template to direct access to note.locked, * we do not want to expose the template to direct access to note.locked,
@@ -383,30 +329,34 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
ContentType.Component, ContentType.Component,
async (items) => { async (items) => {
if (!this.note) return; if (!this.note) return;
this.setState({ this.reloadStackComponents();
stackComponents: sortAlphabetically(
this.application.componentManager!.componentsForArea(ComponentArea.EditorStack)
.filter(component => component.active)
)
});
this.reloadComponentContext();
this.reloadNoteTagsComponent(); this.reloadNoteTagsComponent();
/** Observe editor changes to see if the current note should update its editor */ this.reloadEditor();
const components = items as SNComponent[];
const editors = components.filter((component) => {
return component.isEditor();
});
if (editors.length) {
/** Find the most recent editor for note */
const { editor, changed } = await this.reloadComponentEditorState();
if (!editor && changed) {
this.reloadFont();
}
}
} }
); );
} }
private async reloadEditor() {
const newEditor = this.application.componentManager!.editorForNote(this.note);
const currentEditor = this.state.editorComponent;
if (currentEditor?.uuid !== newEditor?.uuid) {
await this.setState({
editorComponent: newEditor,
/** Unload current component view so that we create a new one */
editorUnloading: true
});
if (newEditor && !newEditor.active) {
await this.application.componentManager?.activateComponent(newEditor.uuid);
}
await this.setState({
/** Reload component view */
editorUnloading: false
});
this.reloadFont();
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.Editor);
}
}
setMenuState(menu: string, state: boolean) { setMenuState(menu: string, state: boolean) {
this.setState({ this.setState({
[menu]: state [menu]: state
@@ -443,14 +393,13 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
noteMutator.prefersPlainEditor = true; noteMutator.prefersPlainEditor = true;
}) })
} }
if (this.activeEditorComponent?.isExplicitlyEnabledForItem(this.note.uuid)) { if (this.state.editorComponent?.isExplicitlyEnabledForItem(this.note.uuid)) {
await this.disassociateComponentWithCurrentNote(this.activeEditorComponent); await this.disassociateComponentWithCurrentNote(this.state.editorComponent);
} }
await this.reloadComponentEditorState();
this.reloadFont(); this.reloadFont();
} }
else if (component.area === ComponentArea.Editor) { else if (component.area === ComponentArea.Editor) {
const currentEditor = this.activeEditorComponent; const currentEditor = this.state.editorComponent;
if (currentEditor && component !== currentEditor) { if (currentEditor && component !== currentEditor) {
await this.disassociateComponentWithCurrentNote(currentEditor); await this.disassociateComponentWithCurrentNote(currentEditor);
} }
@@ -462,7 +411,6 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
}) })
} }
await this.associateComponentWithCurrentNote(component); await this.associateComponentWithCurrentNote(component);
await this.reloadComponentEditorState();
} }
else if (component.area === ComponentArea.EditorStack) { else if (component.area === ComponentArea.EditorStack) {
await this.toggleStackComponentForCurrentItem(component); await this.toggleStackComponentForCurrentItem(component);
@@ -1048,10 +996,10 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
ComponentArea.Editor ComponentArea.Editor
], ],
contextRequestHandler: (componentUuid) => { contextRequestHandler: (componentUuid) => {
const currentEditor = this.activeEditorComponent; const currentEditor = this.state.editorComponent;
if ( if (
componentUuid === currentEditor?.uuid || componentUuid === currentEditor?.uuid ||
componentUuid === this.activeTagsComponent?.uuid || componentUuid === this.state.tagsComponent?.uuid ||
Uuids(this.state.stackComponents).includes(componentUuid) Uuids(this.state.stackComponents).includes(componentUuid)
) { ) {
return this.note; return this.note;
@@ -1103,20 +1051,25 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
} }
reloadNoteTagsComponent() { reloadNoteTagsComponent() {
const components = this.application.componentManager! const [tagsComponent] =
.componentsForArea(ComponentArea.NoteTags); this.application.componentManager!.componentsForArea(ComponentArea.NoteTags);
for (const component of components) { if (tagsComponent?.uuid !== this.state.tagsComponent?.uuid) {
if (component.active) { this.setState({
this.componentGroup.activateComponent(component); tagsComponent: tagsComponent?.active ? tagsComponent : undefined
} else { });
this.componentGroup.deactivateComponent(component);
}
} }
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.NoteTags);
} }
reloadComponentContext() { reloadStackComponents() {
this.setState({
stackComponents: sortAlphabetically(
this.application.componentManager!.componentsForArea(ComponentArea.EditorStack)
.filter(component => component.active)
)
});
if (this.note) { if (this.note) {
for (const component of this.state.stackComponents!) { for (const component of this.state.stackComponents) {
if (component.active) { if (component.active) {
this.application.componentManager!.setComponentHidden( this.application.componentManager!.setComponentHidden(
component, component,
@@ -1125,9 +1078,7 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
} }
} }
} }
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.NoteTags);
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.EditorStack); this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.EditorStack);
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.Editor);
} }
@@ -1140,9 +1091,6 @@ class EditorViewCtrl extends PureViewCtrl<{}, EditorState> {
if (hidden || !component.active) { if (hidden || !component.active) {
this.application.componentManager!.setComponentHidden(component, false); this.application.componentManager!.setComponentHidden(component, false);
await this.associateComponentWithCurrentNote(component); await this.associateComponentWithCurrentNote(component);
if (!component.active) {
this.componentGroup!.activateComponent(component);
}
this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.EditorStack); this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.EditorStack);
} else { } else {
this.application.componentManager!.setComponentHidden(component, true); this.application.componentManager!.setComponentHidden(component, true);

View File

@@ -10,7 +10,8 @@ import {
ComponentArea, ComponentArea,
ComponentAction, ComponentAction,
topLevelCompare, topLevelCompare,
CollectionSort CollectionSort,
ComponentMutator,
} from 'snjs'; } from 'snjs';
import template from './footer-view.pug'; import template from './footer-view.pug';
import { AppStateEvent, EventSource } from '@/ui_models/app_state'; import { AppStateEvent, EventSource } from '@/ui_models/app_state';
@@ -20,7 +21,6 @@ import {
STRING_CONFIRM_APP_QUIT_DURING_UPGRADE STRING_CONFIRM_APP_QUIT_DURING_UPGRADE
} from '@/strings'; } from '@/strings';
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl'; import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
import { ComponentMutator } from '@node_modules/snjs/dist/@types/models';
type DockShortcut = { type DockShortcut = {
name: string, name: string,
@@ -250,13 +250,11 @@ class FooterViewCtrl extends PureViewCtrl {
this.unregisterComponent = this.application!.componentManager!.registerHandler({ this.unregisterComponent = this.application!.componentManager!.registerHandler({
identifier: 'room-bar', identifier: 'room-bar',
areas: [ComponentArea.Rooms, ComponentArea.Modal], areas: [ComponentArea.Rooms, ComponentArea.Modal],
activationHandler: () => { },
actionHandler: (component, action, data) => { actionHandler: (component, action, data) => {
if (action === ComponentAction.SetSize) { if (action === ComponentAction.SetSize) {
/** Do comparison to avoid repetitive calls by arbitrary component */ /** Do comparison to avoid repetitive calls by arbitrary component */
if (!topLevelCompare(component.getLastSize(), data)) { if (!topLevelCompare(component.getLastSize(), data)) {
this.application!.changeItem(component.uuid, (m) => { this.application!.changeItem<ComponentMutator>(component.uuid, (mutator) => {
const mutator = m as ComponentMutator;
mutator.setLastSize(data); mutator.setLastSize(data);
}) })
} }

View File

@@ -8,15 +8,15 @@ import {
SNSmartTag, SNSmartTag,
ComponentArea, ComponentArea,
SNComponent, SNComponent,
WebPrefKey WebPrefKey,
UuidString,
TagMutator
} from 'snjs'; } from 'snjs';
import template from './tags-view.pug'; import template from './tags-view.pug';
import { AppStateEvent } from '@/ui_models/app_state'; import { AppStateEvent } from '@/ui_models/app_state';
import { PANEL_NAME_TAGS } from '@/views/constants'; import { PANEL_NAME_TAGS } from '@/views/constants';
import { STRING_DELETE_TAG } from '@/strings'; import { STRING_DELETE_TAG } from '@/strings';
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl'; import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
import { UuidString } from '@node_modules/snjs/dist/@types/types';
import { TagMutator } from '@node_modules/snjs/dist/@types/models/app/tag';
import { confirmDialog } from '@/services/alertService'; import { confirmDialog } from '@/services/alertService';
type NoteCounts = Partial<Record<string, number>> type NoteCounts = Partial<Record<string, number>>
@@ -239,7 +239,7 @@ class TagsViewCtrl extends PureViewCtrl {
this.unregisterComponent = this.application.componentManager!.registerHandler({ this.unregisterComponent = this.application.componentManager!.registerHandler({
identifier: 'tags', identifier: 'tags',
areas: [ComponentArea.TagsList], areas: [ComponentArea.TagsList],
activationHandler: (component) => { activationHandler: (_, component) => {
this.component = component; this.component = component;
}, },
contextRequestHandler: () => { contextRequestHandler: () => {
@@ -321,9 +321,8 @@ class TagsViewCtrl extends PureViewCtrl {
); );
return; return;
}; };
await this.application.changeAndSaveItem(tag.uuid, (mutator) => { await this.application.changeAndSaveItem<TagMutator>(tag.uuid, (mutator) => {
const tagMutator = mutator as TagMutator; mutator.title = newTitle;
tagMutator.title = newTitle;
}); });
await this.setTagState({ await this.setTagState({
editingTag: undefined editingTag: undefined
@@ -347,9 +346,8 @@ class TagsViewCtrl extends PureViewCtrl {
return; return;
}; };
const insertedTag = await this.application.insertItem(newTag); const insertedTag = await this.application.insertItem(newTag);
const changedTag = await this.application.changeItem(insertedTag.uuid, (m) => { const changedTag = await this.application.changeItem<TagMutator>(insertedTag.uuid, (m) => {
const mutator = m as TagMutator; m.title = newTitle;
mutator.title = newTitle
}); });
await this.setTagState({ await this.setTagState({
templateTag: undefined, templateTag: undefined,