Merge branch 'develop' of github.com:standardnotes/web into develop
This commit is contained in:
@@ -18,12 +18,6 @@ type ActionSubRow = {
|
|||||||
spinnerClass?: string
|
spinnerClass?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateActionParams = {
|
|
||||||
running?: boolean
|
|
||||||
error?: boolean
|
|
||||||
subrows?: ActionSubRow[]
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExtensionState = {
|
type ExtensionState = {
|
||||||
hidden: boolean
|
hidden: boolean
|
||||||
loading: boolean
|
loading: boolean
|
||||||
@@ -33,6 +27,17 @@ type ExtensionState = {
|
|||||||
type ActionsMenuState = {
|
type ActionsMenuState = {
|
||||||
extensions: SNActionsExtension[]
|
extensions: SNActionsExtension[]
|
||||||
extensionsState: Record<UuidString, ExtensionState>
|
extensionsState: Record<UuidString, ExtensionState>
|
||||||
|
selectedActionId?: number
|
||||||
|
menu: {
|
||||||
|
uuid: UuidString,
|
||||||
|
name: string,
|
||||||
|
loading: boolean,
|
||||||
|
error: boolean,
|
||||||
|
hidden: boolean,
|
||||||
|
actions: (Action & {
|
||||||
|
subrows?: ActionSubRow[]
|
||||||
|
})[]
|
||||||
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements ActionsMenuScope {
|
class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements ActionsMenuScope {
|
||||||
@@ -52,6 +57,7 @@ class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements Acti
|
|||||||
item: this.item
|
item: this.item
|
||||||
});
|
});
|
||||||
this.loadExtensions();
|
this.loadExtensions();
|
||||||
|
this.rebuildMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
@@ -69,10 +75,43 @@ class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements Acti
|
|||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
extensions,
|
extensions,
|
||||||
extensionsState
|
extensionsState,
|
||||||
|
menu: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rebuildMenu({
|
||||||
|
extensions = this.state.extensions,
|
||||||
|
extensionsState = this.state.extensionsState,
|
||||||
|
selectedActionId = this.state.selectedActionId,
|
||||||
|
} = {}) {
|
||||||
|
return this.setState({
|
||||||
|
extensions,
|
||||||
|
extensionsState,
|
||||||
|
selectedActionId,
|
||||||
|
menu: extensions.map(extension => {
|
||||||
|
const state = extensionsState[extension.uuid];
|
||||||
|
return {
|
||||||
|
uuid: extension.uuid,
|
||||||
|
name: extension.name,
|
||||||
|
loading: state?.loading ?? false,
|
||||||
|
error: state?.error ?? false,
|
||||||
|
hidden: state?.hidden ?? false,
|
||||||
|
actions: extension.actionsWithContextForItem(this.item).map(action => {
|
||||||
|
if (action.id === selectedActionId) {
|
||||||
|
return {
|
||||||
|
...action,
|
||||||
|
subrows: this.subRowsForAction(action, extension)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async loadExtensions() {
|
async loadExtensions() {
|
||||||
await Promise.all(this.state.extensions.map(async (extension: SNActionsExtension) => {
|
await Promise.all(this.state.extensions.map(async (extension: SNActionsExtension) => {
|
||||||
await this.setLoadingExtension(extension.uuid, true);
|
await this.setLoadingExtension(extension.uuid, true);
|
||||||
@@ -89,14 +128,14 @@ class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements Acti
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeAction(action: Action, extension: SNActionsExtension) {
|
async executeAction(action: Action, extensionUuid: UuidString) {
|
||||||
if (action.verb === 'nested') {
|
if (action.verb === 'nested') {
|
||||||
if (!action.subrows) {
|
this.rebuildMenu({
|
||||||
const subrows = this.subRowsForAction(action, extension);
|
selectedActionId: action.id
|
||||||
await this.updateAction(action, extension, { subrows });
|
});
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const extension = this.application.findItem(extensionUuid) as SNActionsExtension;
|
||||||
await this.updateAction(action, extension, { running: true });
|
await this.updateAction(action, extension, { running: true });
|
||||||
const response = await this.application.actionsManager!.runAction(
|
const response = await this.application.actionsManager!.runAction(
|
||||||
action,
|
action,
|
||||||
@@ -127,14 +166,15 @@ class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements Acti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private subRowsForAction(parentAction: Action, extension: SNActionsExtension): ActionSubRow[] | undefined {
|
private subRowsForAction(parentAction: Action, extension: Pick<SNActionsExtension, 'uuid'>): ActionSubRow[] | undefined {
|
||||||
if (!parentAction.subactions) {
|
if (!parentAction.subactions) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return parentAction.subactions.map((subaction) => {
|
return parentAction.subactions.map((subaction) => {
|
||||||
return {
|
return {
|
||||||
|
id: subaction.id,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
this.executeAction(subaction, extension);
|
this.executeAction(subaction, extension.uuid);
|
||||||
},
|
},
|
||||||
label: subaction.label,
|
label: subaction.label,
|
||||||
subtitle: subaction.desc,
|
subtitle: subaction.desc,
|
||||||
@@ -146,7 +186,10 @@ class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements Acti
|
|||||||
private async updateAction(
|
private async updateAction(
|
||||||
action: Action,
|
action: Action,
|
||||||
extension: SNActionsExtension,
|
extension: SNActionsExtension,
|
||||||
params: UpdateActionParams
|
params: {
|
||||||
|
running?: boolean
|
||||||
|
error?: boolean
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
const updatedExtension = await this.application.changeItem(extension.uuid, (mutator) => {
|
const updatedExtension = await this.application.changeItem(extension.uuid, (mutator) => {
|
||||||
const extensionMutator = mutator as ActionsExtensionMutator;
|
const extensionMutator = mutator as ActionsExtensionMutator;
|
||||||
@@ -156,7 +199,6 @@ class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements Acti
|
|||||||
...action,
|
...action,
|
||||||
running: params?.running,
|
running: params?.running,
|
||||||
error: params?.error,
|
error: params?.error,
|
||||||
subrows: params?.subrows || act?.subrows,
|
|
||||||
} as Action;
|
} as Action;
|
||||||
}
|
}
|
||||||
return act;
|
return act;
|
||||||
@@ -172,7 +214,7 @@ class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements Acti
|
|||||||
}
|
}
|
||||||
return ext;
|
return ext;
|
||||||
});
|
});
|
||||||
await this.setState({
|
await this.rebuildMenu({
|
||||||
extensions
|
extensions
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -188,49 +230,34 @@ class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements Acti
|
|||||||
}
|
}
|
||||||
return ext;
|
return ext;
|
||||||
});
|
});
|
||||||
this.setState({
|
this.rebuildMenu({
|
||||||
extensions
|
extensions
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async toggleExtensionVisibility(extensionUuid: UuidString) {
|
public toggleExtensionVisibility(extensionUuid: UuidString) {
|
||||||
const { extensionsState } = this.state;
|
const { extensionsState } = this.state;
|
||||||
extensionsState[extensionUuid].hidden = !extensionsState[extensionUuid].hidden;
|
extensionsState[extensionUuid].hidden = !extensionsState[extensionUuid].hidden;
|
||||||
await this.setState({
|
this.rebuildMenu({
|
||||||
extensionsState
|
extensionsState
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private isExtensionVisible(extensionUuid: UuidString) {
|
private setLoadingExtension(extensionUuid: UuidString, value = false) {
|
||||||
const { extensionsState } = this.state;
|
|
||||||
return extensionsState[extensionUuid].hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async setLoadingExtension(extensionUuid: UuidString, value = false) {
|
|
||||||
const { extensionsState } = this.state;
|
const { extensionsState } = this.state;
|
||||||
extensionsState[extensionUuid].loading = value;
|
extensionsState[extensionUuid].loading = value;
|
||||||
await this.setState({
|
this.rebuildMenu({
|
||||||
extensionsState
|
extensionsState
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private isExtensionLoading(extensionUuid: UuidString) {
|
private setErrorExtension(extensionUuid: UuidString, value = false) {
|
||||||
const { extensionsState } = this.state;
|
|
||||||
return extensionsState[extensionUuid].loading;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async setErrorExtension(extensionUuid: UuidString, value = false) {
|
|
||||||
const { extensionsState } = this.state;
|
const { extensionsState } = this.state;
|
||||||
extensionsState[extensionUuid].error = value;
|
extensionsState[extensionUuid].error = value;
|
||||||
await this.setState({
|
this.rebuildMenu({
|
||||||
extensionsState
|
extensionsState
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private extensionHasError(extensionUuid: UuidString) {
|
|
||||||
const { extensionsState } = this.state;
|
|
||||||
return extensionsState[extensionUuid].error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ActionsMenu extends WebDirective {
|
export class ActionsMenu extends WebDirective {
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
.sn-component
|
.sn-component
|
||||||
.sk-menu-panel.dropdown-menu
|
.sk-menu-panel.dropdown-menu
|
||||||
a.no-decoration(
|
a.no-decoration(
|
||||||
href='https://standardnotes.org/extensions',
|
href='https://standardnotes.org/extensions',
|
||||||
ng-if='self.state.extensions.length == 0',
|
ng-if='self.state.extensions.length == 0',
|
||||||
rel='noopener',
|
rel='noopener',
|
||||||
target='blank'
|
target='blank'
|
||||||
)
|
)
|
||||||
menu-row(label="'Download Actions'")
|
menu-row(label="'Download Actions'")
|
||||||
div(ng-repeat='extension in self.state.extensions track by extension.uuid')
|
div(ng-repeat='extension in self.state.menu track by extension.uuid')
|
||||||
.sk-menu-panel-header(
|
.sk-menu-panel-header(
|
||||||
ng-click='self.toggleExtensionVisibility(extension.uuid); $event.stopPropagation();'
|
ng-click='self.toggleExtensionVisibility(extension.uuid); $event.stopPropagation();'
|
||||||
)
|
)
|
||||||
.sk-menu-panel-column
|
.sk-menu-panel-column
|
||||||
.sk-menu-panel-header-title {{extension.name}}
|
.sk-menu-panel-header-title {{extension.name}}
|
||||||
div(ng-if='self.isExtensionVisible(extension.uuid)') …
|
div(ng-if='extension.visible') …
|
||||||
div(ng-if='self.isExtensionLoading(extension.uuid)')
|
div(ng-if='extension.loading')
|
||||||
.sk-spinner.small.loading
|
.sk-spinner.small.loading
|
||||||
menu-row(
|
menu-row(
|
||||||
action='self.executeAction(action, extension)',
|
action='self.executeAction(action, extension.uuid)',
|
||||||
label='action.label',
|
label='action.label',
|
||||||
ng-if='!self.isExtensionVisible(extension.uuid) && !self.isExtensionLoading(extension.uuid) && !self.extensionHasError(extension.uuid)',
|
ng-if='!extension.visible && !extension.loading && !extension.error',
|
||||||
ng-repeat='action in extension.actionsWithContextForItem(self.item) track by $index',
|
ng-repeat='action in extension.actions track by $index',
|
||||||
disabled='action.running'
|
disabled='action.running'
|
||||||
spinner-class="action.running ? 'info' : null",
|
spinner-class="action.running ? 'info' : null",
|
||||||
sub-rows='action.subrows',
|
sub-rows='action.subrows',
|
||||||
subtitle='action.desc'
|
subtitle='action.desc'
|
||||||
)
|
)
|
||||||
.sk-sublabel(ng-if="action.access_type")
|
.sk-sublabel(ng-if="action.access_type")
|
||||||
| Uses
|
| Uses
|
||||||
strong {{action.access_type}}
|
strong {{action.access_type}}
|
||||||
| access to this note.
|
| access to this note.
|
||||||
menu-row(
|
menu-row(
|
||||||
faded='true',
|
faded='true',
|
||||||
label="'No Actions Available'",
|
label="'No Actions Available'",
|
||||||
ng-if='extension.actionsWithContextForItem(self.item).length == 0'
|
ng-if='!extension.actions.length'
|
||||||
)
|
)
|
||||||
menu-row(
|
menu-row(
|
||||||
faded='true',
|
faded='true',
|
||||||
label="'Error loading actions'",
|
label="'Error loading actions'",
|
||||||
subtitle="'Please try again later.'"
|
subtitle="'Please try again later.'"
|
||||||
ng-if='self.extensionHasError(extension.uuid)'
|
ng-if='extension.error'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
.sk-menu-panel-row.row(
|
.sk-menu-panel-row.row(
|
||||||
ng-attr-title='{{ctrl.desc}}',
|
ng-attr-title='{{ctrl.desc}}',
|
||||||
ng-click='ctrl.onClick($event)'
|
ng-click='ctrl.onClick($event)'
|
||||||
)
|
)
|
||||||
.sk-menu-panel-column
|
.sk-menu-panel-column
|
||||||
.left
|
.left
|
||||||
.sk-menu-panel-column(
|
.sk-menu-panel-column(
|
||||||
ng-if=`
|
ng-if=`
|
||||||
ctrl.circle &&
|
ctrl.circle &&
|
||||||
(!ctrl.circleAlign || ctrl.circleAlign == 'left')
|
(!ctrl.circleAlign || ctrl.circleAlign == 'left')
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
@@ -21,17 +21,17 @@
|
|||||||
ng-transclude
|
ng-transclude
|
||||||
.sk-menu-panel-subrows(ng-if='ctrl.subRows && ctrl.subRows.length > 0')
|
.sk-menu-panel-subrows(ng-if='ctrl.subRows && ctrl.subRows.length > 0')
|
||||||
menu-row(
|
menu-row(
|
||||||
ng-repeat='row in ctrl.subRows',
|
ng-repeat='row in ctrl.subRows',
|
||||||
action='row.onClick()',
|
action='row.onClick()',
|
||||||
label='row.label',
|
label='row.label',
|
||||||
spinner-class='row.spinnerClass',
|
spinner-class='row.spinnerClass',
|
||||||
subtitle='row.subtitle'
|
subtitle='row.subtitle'
|
||||||
)
|
)
|
||||||
.sk-menu-panel-column(ng-if="ctrl.circle && ctrl.circleAlign == 'right'")
|
.sk-menu-panel-column(ng-if="ctrl.circle && ctrl.circleAlign == 'right'")
|
||||||
.sk-circle.small(ng-class='ctrl.circle')
|
.sk-circle.small(ng-class='ctrl.circle')
|
||||||
.sk-menu-panel-column(ng-if='ctrl.hasButton')
|
.sk-menu-panel-column(ng-if='ctrl.hasButton')
|
||||||
.sk-button(
|
.sk-button(
|
||||||
ng-class='ctrl.buttonClass',
|
ng-class='ctrl.buttonClass',
|
||||||
ng-click='ctrl.clickAccessoryButton($event)'
|
ng-click='ctrl.clickAccessoryButton($event)'
|
||||||
)
|
)
|
||||||
.sk-label {{ctrl.buttonText}}
|
.sk-label {{ctrl.buttonText}}
|
||||||
|
|||||||
Reference in New Issue
Block a user