diff --git a/app/assets/javascripts/directives/views/actionsMenu.ts b/app/assets/javascripts/directives/views/actionsMenu.ts index 04e465387..1defb6d10 100644 --- a/app/assets/javascripts/directives/views/actionsMenu.ts +++ b/app/assets/javascripts/directives/views/actionsMenu.ts @@ -2,7 +2,7 @@ import { WebApplication } from '@/ui_models/application'; import { WebDirective } from './../../types'; import template from '%/directives/actions-menu.pug'; import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl'; -import { SNItem, Action, SNActionsExtension } from 'snjs/dist/@types'; +import { SNItem, Action, SNActionsExtension, UuidString } from 'snjs/dist/@types'; import { ActionResponse } from 'snjs/dist/@types/services/actions_service'; import { ActionsExtensionMutator } from 'snjs/dist/@types/models/app/extension'; @@ -15,7 +15,7 @@ type ActionSubRow = { onClick: () => void label: string subtitle: string - spinnerClass: string | undefined + spinnerClass?: string } type UpdateActionParams = { @@ -24,24 +24,21 @@ type UpdateActionParams = { subrows?: ActionSubRow[] } -type UpdateExtensionParams = { - hidden?: boolean +type ActionsMenuState = { + extensions: SNActionsExtension[], + hiddenState: Record + loadingState: Record } -class ActionsMenuCtrl extends PureViewCtrl implements ActionsMenuScope { - +class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements ActionsMenuScope { application!: WebApplication item!: SNItem - public loadingExtensions: boolean = true /* @ngInject */ constructor( $timeout: ng.ITimeoutService ) { super($timeout); - this.state = { - extensions: [] - }; } $onInit() { @@ -52,20 +49,28 @@ class ActionsMenuCtrl extends PureViewCtrl implements ActionsMenuScope { this.loadExtensions(); }; - async loadExtensions() { - const actionExtensions = this.application.actionsManager!.getExtensions().sort((a, b) => { + /** @override */ + getInitialState() { + const extensions = this.application.actionsManager!.getExtensions().sort((a, b) => { return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1; }); - const extensionsForItem = await Promise.all(actionExtensions.map((extension) => { - return this.application.actionsManager!.loadExtensionInContextOfItem( + return { + extensions, + loadingState: {}, + hiddenState: {} + }; + } + + async loadExtensions() { + await Promise.all(this.state.extensions.map(async (extension: SNActionsExtension) => { + await this.setLoadingExtension(extension.uuid, true); + const updatedExtension = await this.application.actionsManager!.loadExtensionInContextOfItem( extension, - this.props.item + this.item ); + await this.updateExtension(updatedExtension!); + await this.setLoadingExtension(extension.uuid, false); })); - this.loadingExtensions = false; - await this.setState({ - extensions: extensionsForItem - }); } async executeAction(action: Action, extension: SNActionsExtension) { @@ -79,7 +84,7 @@ class ActionsMenuCtrl extends PureViewCtrl implements ActionsMenuScope { await this.updateAction(action, extension, { running: true }); const response = await this.application.actionsManager!.runAction( action, - this.props.item, + this.item, async () => { /** @todo */ return ''; @@ -144,40 +149,59 @@ class ActionsMenuCtrl extends PureViewCtrl implements ActionsMenuScope { await this.updateExtension(updatedExtension); } - private async updateExtension( - extension: SNActionsExtension, - params?: UpdateExtensionParams - ) { - const updatedExtension = await this.application.changeItem(extension.uuid, (mutator) => { - const extensionMutator = mutator as ActionsExtensionMutator; - extensionMutator.hidden = Boolean(params?.hidden); - }) as SNActionsExtension; + private async updateExtension(extension: SNActionsExtension) { const extensions = this.state.extensions.map((ext: SNActionsExtension) => { if (extension.uuid === ext.uuid) { - return updatedExtension; + return extension; } return ext; }); await this.setState({ - extensions: extensions + extensions }); } private async reloadExtension(extension: SNActionsExtension) { const extensionInContext = await this.application.actionsManager!.loadExtensionInContextOfItem( extension, - this.props.item + this.item ); const extensions = this.state.extensions.map((ext: SNActionsExtension) => { if (extension.uuid === ext.uuid) { - return extensionInContext; + return extensionInContext!; } return ext; }); this.setState({ - extensions: extensions + extensions }); } + + private async toggleExtensionVisibility(extensionUuid: UuidString) { + const { hiddenState } = this.state; + hiddenState[extensionUuid] = !hiddenState[extensionUuid] ?? false; + await this.setState({ + hiddenState + }); + } + + private isExtensionVisible(extensionUuid: UuidString) { + const { hiddenState } = this.state; + return hiddenState[extensionUuid] ?? false; + } + + private async setLoadingExtension(extensionUuid: UuidString, value = false) { + const { loadingState } = this.state; + loadingState[extensionUuid] = value; + await this.setState({ + loadingState + }); + } + + private isExtensionLoading(extensionUuid: UuidString) { + const { loadingState } = this.state; + return loadingState[extensionUuid] ?? false; + } } export class ActionsMenu extends WebDirective { diff --git a/app/assets/templates/directives/actions-menu.pug b/app/assets/templates/directives/actions-menu.pug index 79637acc9..e82ed2324 100644 --- a/app/assets/templates/directives/actions-menu.pug +++ b/app/assets/templates/directives/actions-menu.pug @@ -7,23 +7,20 @@ target='blank' ) menu-row(label="'Download Actions'") - div(ng-if='self.loadingExtensions') - .sk-menu-panel-header - .sk-menu-panel-column - .sk-menu-panel-header-title Loading... - .sk-spinner.small.loading div(ng-repeat='extension in self.state.extensions track by extension.uuid') .sk-menu-panel-header( - ng-click='self.updateExtension(extension, { hidden: !extension.hidden }); $event.stopPropagation();' + ng-click='self.toggleExtensionVisibility(extension.uuid); $event.stopPropagation();' ) .sk-menu-panel-column .sk-menu-panel-header-title {{extension.name}} - div(ng-if='extension.hidden') … + div(ng-if='self.isExtensionVisible(extension.uuid)') … + div(ng-if='self.isExtensionLoading(extension.uuid)') + .sk-spinner.small.loading menu-row( action='self.executeAction(action, extension)', label='action.label', - ng-if='!extension.hidden', - ng-repeat='action in extension.actionsWithContextForItem(self.props.item) track by $index', + ng-if='!self.isExtensionVisible(extension.uuid) && !self.isExtensionLoading(extension.uuid)', + ng-repeat='action in extension.actionsWithContextForItem(self.item) track by $index', disabled='action.running' spinner-class="action.running ? 'info' : null", sub-rows='action.subrows', @@ -36,5 +33,5 @@ menu-row( faded='true', label="'No Actions Available'", - ng-if='extension.actionsWithContextForItem(self.props.item).length == 0' + ng-if='extension.actionsWithContextForItem(self.item).length == 0' ) diff --git a/package.json b/package.json index faf2d2013..2983810ad 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,6 @@ }, "dependencies": { "sncrypto": "github:standardnotes/sncrypto#4a080efeb646dbf9ca3dffdfcfa9d081b4dc6de0", - "snjs": "github:standardnotes/snjs#75ac6ff8e620f3b7e796b117b9d0afce303962a0" + "snjs": "github:standardnotes/snjs#2ef57eba1fc0e4f81e667d80bc3b99e0f650b6d1" } }