fix: incremental loading for actions (#449)
* fix: incremental loading for actions * fix: simplify loadingExtensions initialization * fix: loading spinner per extension * refactor: minor changes * fix: loading and hidden state should not be persisted * chore(deps): update snjs * fix: keep === comparison operator Co-authored-by: Johnny Almonte <johnny243@users.noreply.github.com>
This commit is contained in:
@@ -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<UuidString, Boolean>
|
||||
loadingState: Record<UuidString, Boolean>
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
@@ -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'
|
||||
)
|
||||
|
||||
@@ -64,6 +64,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"sncrypto": "github:standardnotes/sncrypto#4a080efeb646dbf9ca3dffdfcfa9d081b4dc6de0",
|
||||
"snjs": "github:standardnotes/snjs#75ac6ff8e620f3b7e796b117b9d0afce303962a0"
|
||||
"snjs": "github:standardnotes/snjs#2ef57eba1fc0e4f81e667d80bc3b99e0f650b6d1"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user