-
Notifications
You must be signed in to change notification settings - Fork 17
Handlers for Smart Connector UIExtension #70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
32ceb71
ca2e9b1
510c9f7
85cb92c
b79650e
8b77069
0edc62d
cb71c3b
1f8cb5a
6a88438
19d6020
c6ba7bd
6b01139
c97bc4b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| /******************************************************************************** | ||
| * Copyright (c) 2022-2023 STMicroelectronics and others. | ||
| * | ||
| * This program and the accompanying materials are made available under the | ||
| * terms of the Eclipse Public License v. 2.0 which is available at | ||
| * http://www.eclipse.org/legal/epl-2.0. | ||
| * | ||
| * This Source Code may also be made available under the following Secondary | ||
| * Licenses when the conditions for such availability set forth in the Eclipse | ||
| * Public License v. 2.0 are satisfied: GNU General Public License, version 2 | ||
| * with the GNU Classpath Exception which is available at | ||
| * https://www.gnu.org/software/classpath/license.html. | ||
| * | ||
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | ||
| ********************************************************************************/ | ||
| import { | ||
| DefaultSmartConnectorItemProvider, SmartConnectorSettings | ||
| } from '@eclipse-glsp/server'; | ||
| import { | ||
| SmartConnectorPosition, | ||
| SmartConnectorGroupUIType, | ||
| DefaultTypes | ||
| } from '@eclipse-glsp/protocol'; | ||
| import { injectable } from 'inversify'; | ||
| import { ModelTypes } from '../util/model-types'; | ||
|
|
||
| @injectable() | ||
| export class WorkflowSmartConnectorItemProvider extends DefaultSmartConnectorItemProvider { | ||
|
|
||
| protected override smartConnectorNodeSettings: SmartConnectorSettings = { | ||
| position: SmartConnectorPosition.Top, | ||
| showTitle: true, | ||
| submenu: false, | ||
| showOnlyForChildren: SmartConnectorGroupUIType.Labels | ||
| }; | ||
|
|
||
| protected override smartConnectorEdgeSettings: SmartConnectorSettings = { | ||
| position: SmartConnectorPosition.Right, | ||
| showTitle: true, | ||
| submenu: true | ||
| }; | ||
|
|
||
| override nodeOperationFilter = { | ||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||
| [ModelTypes.AUTOMATED_TASK]: [ModelTypes.WEIGHTED_EDGE, ModelTypes.AUTOMATED_TASK, ModelTypes.MANUAL_TASK, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be handled generically. All the required information is present in the typehints of the I don't expect that this is handled with this PR but we should create a follow-up for that. |
||
| ModelTypes.ACTIVITY_NODE], | ||
| [ModelTypes.MERGE_NODE]: [DefaultTypes.EDGE, ModelTypes.MERGE_NODE, ModelTypes.CATEGORY], | ||
| [ModelTypes.FORK_NODE]: [DefaultTypes.EDGE, ModelTypes.FORK_NODE], | ||
| [ModelTypes.CATEGORY]: [ModelTypes.WEIGHTED_EDGE, ModelTypes.FORK_NODE], | ||
| [ModelTypes.JOIN_NODE]: [ModelTypes.AUTOMATED_TASK, ModelTypes.FORK_NODE, ModelTypes.JOIN_NODE] | ||
| }; | ||
|
|
||
| override defaultEdge = DefaultTypes.EDGE; | ||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||
|
|
||
| override edgeTypes = { | ||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||
| [ModelTypes.AUTOMATED_TASK]: DefaultTypes.EDGE, | ||
| [ModelTypes.MERGE_NODE]: DefaultTypes.EDGE | ||
| }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -77,6 +77,8 @@ import { | |
| NavigationTargetProviders, | ||
| Operations | ||
| } from './service-identifiers'; | ||
| import { DefaultSmartConnectorItemProvider, SmartConnectorItemProvider } from '../features/contextactions/smart-connector-item-provider'; | ||
| import { OpenSmartConnectorActionHandler } from '../features/contextactions/smart-connector-action-handler'; | ||
|
|
||
| /** | ||
| * The diagram module is the central configuration artifact for configuring a client session specific injector. For each | ||
|
|
@@ -154,6 +156,7 @@ export abstract class DiagramModule extends GLSPModule { | |
| applyOptionalBindingTarget(context, ToolPaletteItemProvider, this.bindToolPaletteItemProvider()); | ||
| applyOptionalBindingTarget(context, CommandPaletteActionProvider, this.bindCommandPaletteActionProvider()); | ||
| applyOptionalBindingTarget(context, ContextMenuItemProvider, this.bindContextMenuItemProvider()); | ||
| applyOptionalBindingTarget(context, SmartConnectorItemProvider, this.bindSmartConnectorItemProvider()); | ||
| this.configureMultiBinding(new MultiBinding<ContextActionsProvider>(ContextActionsProviders), binding => | ||
| this.configureContextActionProviders(binding) | ||
| ); | ||
|
|
@@ -216,6 +219,7 @@ export abstract class DiagramModule extends GLSPModule { | |
| binding.add(SaveModelActionHandler); | ||
| binding.add(UndoRedoActionHandler); | ||
| binding.add(ComputedBoundsActionHandler); | ||
| binding.add(OpenSmartConnectorActionHandler); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be handled on client side |
||
| } | ||
|
|
||
| protected bindDiagramType(): BindingTarget<string> { | ||
|
|
@@ -344,7 +348,9 @@ export abstract class DiagramModule extends GLSPModule { | |
| protected bindToolPaletteItemProvider(): BindingTarget<ToolPaletteItemProvider> | undefined { | ||
| return DefaultToolPaletteItemProvider; | ||
| } | ||
|
|
||
| protected bindSmartConnectorItemProvider(): BindingTarget<SmartConnectorItemProvider> | undefined { | ||
| return DefaultSmartConnectorItemProvider; | ||
| } | ||
| protected bindCommandPaletteActionProvider(): BindingTarget<CommandPaletteActionProvider> | undefined { | ||
| return undefined; | ||
| } | ||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /******************************************************************************** | ||
| * Copyright (c) 2022-2023 STMicroelectronics and others. | ||
| * | ||
| * This program and the accompanying materials are made available under the | ||
| * terms of the Eclipse Public License v. 2.0 which is available at | ||
| * http://www.eclipse.org/legal/epl-2.0. | ||
| * | ||
| * This Source Code may also be made available under the following Secondary | ||
| * Licenses when the conditions for such availability set forth in the Eclipse | ||
| * Public License v. 2.0 are satisfied: GNU General Public License, version 2 | ||
| * with the GNU Classpath Exception which is available at | ||
| * https://www.gnu.org/software/classpath/license.html. | ||
| * | ||
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | ||
| ********************************************************************************/ | ||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||
| import { | ||
| Action, | ||
| CloseSmartConnectorAction, | ||
| OpenSmartConnectorAction, | ||
| SelectAction, | ||
| MaybePromise} from '@eclipse-glsp/protocol'; | ||
| import { inject, injectable } from 'inversify'; | ||
| import { ActionHandler } from '../../actions/action-handler'; | ||
| import { ModelState } from '../model/model-state'; | ||
| import { GNode } from '@eclipse-glsp/graph'; | ||
|
|
||
| @injectable() | ||
| export class OpenSmartConnectorActionHandler implements ActionHandler { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be handled entirely on client side. |
||
| actionKinds = [SelectAction.KIND]; | ||
|
|
||
| @inject(ModelState) | ||
| protected modelState: ModelState; | ||
|
|
||
| execute(action: Action): MaybePromise<Action[]> { | ||
| if (SelectAction.is(action)) { | ||
| const selectedElement = this.modelState.index.find(action.selectedElementsIDs[0]); | ||
| if (selectedElement && selectedElement instanceof GNode) { | ||
| return [OpenSmartConnectorAction.create(action.selectedElementsIDs[0])]; | ||
| } | ||
| else {return [];} | ||
| } | ||
| return [CloseSmartConnectorAction.create()]; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,181 @@ | ||||||
| /******************************************************************************** | ||||||
| * Copyright (c) 2022-2023 STMicroelectronics and others. | ||||||
| * | ||||||
| * This program and the accompanying materials are made available under the | ||||||
| * terms of the Eclipse Public License v. 2.0 which is available at | ||||||
| * http://www.eclipse.org/legal/epl-2.0. | ||||||
| * | ||||||
| * This Source Code may also be made available under the following Secondary | ||||||
| * Licenses when the conditions for such availability set forth in the Eclipse | ||||||
| * Public License v. 2.0 are satisfied: GNU General Public License, version 2 | ||||||
| * with the GNU Classpath Exception which is available at | ||||||
| * https://www.gnu.org/software/classpath/license.html. | ||||||
| * | ||||||
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | ||||||
| ********************************************************************************/ | ||||||
|
yentelmanero marked this conversation as resolved.
|
||||||
| import { | ||||||
| Args, | ||||||
| CreateEdgeOperation, | ||||||
| CreateNodeOperation, | ||||||
| PaletteItem, | ||||||
| SmartConnectorGroupItem, | ||||||
| EditorContext, | ||||||
| LabeledAction, | ||||||
| MaybePromise, | ||||||
| SmartConnectorPosition, | ||||||
| SmartConnectorGroupUIType, | ||||||
| SmartConnectorNodeItem, | ||||||
| TriggerNodeCreationAction | ||||||
| } from '@eclipse-glsp/protocol'; | ||||||
| import { inject, injectable } from 'inversify'; | ||||||
| import { CreateOperationHandler } from '../../operations/create-operation-handler'; | ||||||
| import { OperationHandlerRegistry } from '../../operations/operation-handler-registry'; | ||||||
| import { ContextActionsProvider } from './context-actions-provider'; | ||||||
|
|
||||||
| /** | ||||||
| * A {@link ContextActionsProvider} for {@link PaletteItem}s in the Smart Connector which appears when a node is selected. | ||||||
| */ | ||||||
| @injectable() | ||||||
| export abstract class SmartConnectorItemProvider implements ContextActionsProvider { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed offline we would like to use a more generic |
||||||
| /** | ||||||
| * Returns the context id of the provider. | ||||||
| */ | ||||||
| get contextId(): string { | ||||||
| return 'smart-connector'; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Returns a list of {@link LabeledAction}s for a given {@link EditorContext}. | ||||||
| * | ||||||
| * @param editorContext The editorContext for which the actions are returned. | ||||||
| * @returns A list of {@link LabeledAction}s for a given {@link EditorContext}. | ||||||
| */ | ||||||
| async getActions(editorContext: EditorContext): Promise<LabeledAction[]> { | ||||||
| return this.getItems(editorContext.args); | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Constructs a list of {@link PaletteItem}s for a given map of string arguments. | ||||||
| * | ||||||
| * @param args A map of string arguments. | ||||||
| * @returns A list of {@link PaletteItem}s for a given map of string arguments. | ||||||
| */ | ||||||
| abstract getItems(args?: Args): MaybePromise<SmartConnectorGroupItem[]>; | ||||||
|
|
||||||
| /** filter that excludes nodes/edges from options, given a node ID as key */ | ||||||
| abstract nodeOperationFilter: Record<string, string[]>; | ||||||
|
|
||||||
| /** edge that is used between source and destination by default when a new node is created | ||||||
| * (if not given, no edge will be created when creating new node) */ | ||||||
| abstract defaultEdge: string; | ||||||
|
|
||||||
| /** list of edges where the key is a node ID and the value is a edge ID | ||||||
| * the edge to a new node when the source node has the ID of the key | ||||||
| * otherwise, the default edge will be used */ | ||||||
| abstract edgeTypes: Record<string, string>; | ||||||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||||||
| } | ||||||
|
|
||||||
| export type SmartConnectorSettings = { | ||||||
| position: SmartConnectorPosition | ||||||
| showTitle: true; | ||||||
| submenu: boolean; | ||||||
| showOnlyForChildren?: SmartConnectorGroupUIType | ||||||
| } | { | ||||||
| position: SmartConnectorPosition | ||||||
| showTitle: false; | ||||||
| showOnlyForChildren?: SmartConnectorGroupUIType | ||||||
| }; | ||||||
|
|
||||||
| @injectable() | ||||||
| export class DefaultSmartConnectorItemProvider extends SmartConnectorItemProvider { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| @inject(OperationHandlerRegistry) operationHandlerRegistry: OperationHandlerRegistry; | ||||||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| protected counter: number; | ||||||
|
|
||||||
| protected smartConnectorNodeSettings: SmartConnectorSettings = { | ||||||
| position: SmartConnectorPosition.Right, | ||||||
| showTitle: true, | ||||||
| submenu: true, | ||||||
| showOnlyForChildren: SmartConnectorGroupUIType.Icons | ||||||
| }; | ||||||
|
|
||||||
| protected smartConnectorEdgeSettings: SmartConnectorSettings = { | ||||||
| position: SmartConnectorPosition.Right, | ||||||
| showTitle: true, | ||||||
| submenu: false | ||||||
| }; | ||||||
| override nodeOperationFilter: Record<string, string[]>; | ||||||
| override defaultEdge: string; | ||||||
| override edgeTypes: Record<string, string>; | ||||||
|
|
||||||
| getItems(args?: Args): SmartConnectorGroupItem[] { | ||||||
| const handlers = this.operationHandlerRegistry.getAll().filter(CreateOperationHandler.is) as CreateOperationHandler[]; | ||||||
| this.counter = 0; | ||||||
| const nodes = this.createSmartConnectorGroupItem(handlers, CreateNodeOperation.KIND, args?.nodeType as string, | ||||||
| this.smartConnectorNodeSettings.showOnlyForChildren); | ||||||
| const edges = this.createSmartConnectorGroupItem(handlers, CreateEdgeOperation.KIND, args?.nodeType as string, | ||||||
| this.smartConnectorEdgeSettings.showOnlyForChildren); | ||||||
| return [ | ||||||
| { | ||||||
| id: 'smart-connector-node-group', | ||||||
| label: 'Nodes', | ||||||
| actions: [], | ||||||
| children: nodes, | ||||||
| icon: 'symbol-property', | ||||||
| sortString: 'A', | ||||||
| ...this.smartConnectorNodeSettings | ||||||
| }, | ||||||
| { | ||||||
| id: 'smart-connector-edge-group', | ||||||
| label: 'Edges', | ||||||
| actions: [], | ||||||
| children: edges, | ||||||
| icon: 'symbol-property', | ||||||
| sortString: 'B', | ||||||
| ...this.smartConnectorEdgeSettings | ||||||
| } | ||||||
| ]; | ||||||
| } | ||||||
|
|
||||||
| createSmartConnectorGroupItem(handlers: CreateOperationHandler[], kind: string, selectedNodeType: string, | ||||||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||||||
| showOnly?: SmartConnectorGroupUIType): PaletteItem[] { | ||||||
| const includedInNodeFilter = (e: string): boolean => this.nodeOperationFilter[selectedNodeType].includes(e); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Solution could be something like |
||||||
| const paletteItems = handlers | ||||||
| .filter(handler => handler.operationType === kind && (selectedNodeType && | ||||||
| this.nodeOperationFilter[selectedNodeType] ? !handler.elementTypeIds.some(includedInNodeFilter) : true)) | ||||||
| .map(handler => handler.getTriggerActions().map(action => this.create(action, handler.label, selectedNodeType))) | ||||||
| .reduce((accumulator, value) => accumulator.concat(value), []) | ||||||
| .sort((a, b) => a.sortString.localeCompare(b.sortString)); | ||||||
| if (showOnly === SmartConnectorGroupUIType.Icons) { | ||||||
| if (paletteItems.every(paletteItem => paletteItem.icon !== '')) { | ||||||
| console.warn('Not all elements have icons. Labels will be shown, check settings for smart connector.'); | ||||||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||||||
| return paletteItems; | ||||||
| } | ||||||
| paletteItems.forEach(paletteItem => paletteItem.label = ''); | ||||||
| } | ||||||
| if (showOnly === SmartConnectorGroupUIType.Labels) {paletteItems.forEach(paletteItem => paletteItem.icon = '');} | ||||||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||||||
| return paletteItems; | ||||||
| } | ||||||
|
|
||||||
| create(action: PaletteItem.TriggerElementCreationAction, label: string, nodeType: string): PaletteItem | SmartConnectorNodeItem { | ||||||
|
yentelmanero marked this conversation as resolved.
Outdated
|
||||||
| if (TriggerNodeCreationAction.is(action)) { | ||||||
| let edgeType = this.edgeTypes[nodeType]; | ||||||
| if (!edgeType) {edgeType = this.defaultEdge;} | ||||||
| return { | ||||||
| id: `smart-connector-palette-item${this.counter++}`, | ||||||
| sortString: label.charAt(0), | ||||||
| label, | ||||||
| actions: [action], | ||||||
| edgeType: edgeType | ||||||
| }; | ||||||
| } | ||||||
| return { | ||||||
| id: `smart-connector-palette-item${this.counter++}`, | ||||||
| sortString: label.charAt(0), | ||||||
| label, | ||||||
| actions: [action] | ||||||
| }; | ||||||
| } | ||||||
|
|
||||||
| } | ||||||
Uh oh!
There was an error while loading. Please reload this page.