Incremental work on embedded activity management
This commit is contained in:
parent
1c636e6a9b
commit
a08c2a48df
|
|
@ -5,7 +5,7 @@
|
|||
* It contains typing information for all components that exist in this project.
|
||||
*/
|
||||
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
|
||||
import { ActionDefinition, ActionInvokedArgs, Activity, ActivitySelectedArgs, ContainerSelectedArgs, CreateChildActivityArgs, GraphUpdatedArgs, IntellisenseContext, SelectListItem, TabChangedArgs, TabDefinition, Variable, WorkflowDefinition, WorkflowDefinitionSummary, WorkflowInstance, WorkflowInstanceSummary } from "./models";
|
||||
import { ActionDefinition, ActionInvokedArgs, Activity, ActivitySelectedArgs, ContainerSelectedArgs, CreateChildActivityArgs, EditChildActivityArgs, GraphUpdatedArgs, IntellisenseContext, SelectListItem, TabChangedArgs, TabDefinition, Variable, WorkflowDefinition, WorkflowDefinitionSummary, WorkflowInstance, WorkflowInstanceSummary } from "./models";
|
||||
import { ActivityUpdatedArgs, DeleteActivityRequestedArgs } from "./components/designer/workflow-definition-editor/activity-properties-editor";
|
||||
import { Button } from "./components/shared/button-group/models";
|
||||
import { ContainerActivityComponent } from "./components/activities/container-activity-component";
|
||||
|
|
@ -68,7 +68,6 @@ export namespace Components {
|
|||
"value": string;
|
||||
}
|
||||
interface ElsaDefaultActivityTemplate {
|
||||
"activity": Activity;
|
||||
"activityJson": string;
|
||||
"activityType": string;
|
||||
"displayType": string;
|
||||
|
|
@ -86,9 +85,9 @@ export namespace Components {
|
|||
interface ElsaFlowchart {
|
||||
"addActivity": (args: AddActivityArgs) => Promise<void>;
|
||||
"clear": () => Promise<void>;
|
||||
"exportRoot": () => Promise<Activity>;
|
||||
"export": () => Promise<Activity>;
|
||||
"getGraph": () => Promise<Graph>;
|
||||
"importRoot": (root: Activity) => Promise<void>;
|
||||
"import": (root: Activity) => Promise<void>;
|
||||
"interactiveMode": boolean;
|
||||
"root"?: Activity;
|
||||
"updateLayout": () => Promise<void>;
|
||||
|
|
@ -665,11 +664,11 @@ declare namespace LocalJSX {
|
|||
"value"?: string;
|
||||
}
|
||||
interface ElsaDefaultActivityTemplate {
|
||||
"activity"?: Activity;
|
||||
"activityJson"?: string;
|
||||
"activityType"?: string;
|
||||
"displayType"?: string;
|
||||
"onCreateChildActivity"?: (event: CustomEvent<CreateChildActivityArgs>) => void;
|
||||
"onEditChildActivity"?: (event: CustomEvent<EditChildActivityArgs>) => void;
|
||||
"selected"?: boolean;
|
||||
}
|
||||
interface ElsaDropdownButton {
|
||||
|
|
@ -856,6 +855,7 @@ declare namespace LocalJSX {
|
|||
}
|
||||
interface ElsaWorkflowNavigator {
|
||||
"items"?: Array<WorkflowNavigationItem>;
|
||||
"onNavigate"?: (event: CustomEvent<WorkflowNavigationItem>) => void;
|
||||
}
|
||||
interface ElsaWorkflowPublishButton {
|
||||
"onExportClicked"?: (event: CustomEvent<any>) => void;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import {Activity} from '../../models';
|
|||
export interface ContainerActivityComponent {
|
||||
updateLayout(): Promise<void>;
|
||||
addActivity(args: AddActivityArgs): Promise<void>;
|
||||
exportRoot(): Promise<Activity>
|
||||
importRoot(root: Activity): Promise<void>;
|
||||
export(): Promise<Activity>
|
||||
import(root: Activity): Promise<void>;
|
||||
zoomToFit(): Promise<void>;
|
||||
clear(): Promise<void>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import 'reflect-metadata';
|
|||
import {Node} from "@antv/x6";
|
||||
import {Container, Service} from "typedi"
|
||||
import {ActivityNodeHandler, CreateUINodeContext} from "./activity-node-handler";
|
||||
import {PortProviderRegistry} from "./port-provider-registry";
|
||||
import {PortProviderContext} from "./port-provider";
|
||||
import {PortProviderContext, PortProviderRegistry} from "../../../services";
|
||||
|
||||
@Service()
|
||||
export class DefaultNodeHandler implements ActivityNodeHandler {
|
||||
|
|
|
|||
|
|
@ -108,13 +108,13 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
}
|
||||
|
||||
@Method()
|
||||
async exportRoot(): Promise<Activity> {
|
||||
return this.exportRootInternal();
|
||||
async export(): Promise<Activity> {
|
||||
return this.exportInternal();
|
||||
}
|
||||
|
||||
@Method()
|
||||
async importRoot(root: Activity): Promise<void> {
|
||||
return this.importRootInternal(root);
|
||||
async import(root: Activity): Promise<void> {
|
||||
return this.importInternal(root);
|
||||
}
|
||||
|
||||
async componentDidLoad() {
|
||||
|
|
@ -184,7 +184,7 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
await this.updateLayout();
|
||||
}
|
||||
|
||||
private exportRootInternal = (): Activity => {
|
||||
private exportInternal = (): Activity => {
|
||||
const graph = this.graph;
|
||||
const graphModel = graph.toJSON();
|
||||
const activities = graphModel.cells.filter(x => x.shape == 'activity').map(x => x.data as Activity);
|
||||
|
|
@ -209,7 +209,7 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
} as Flowchart;
|
||||
}
|
||||
|
||||
private importRootInternal = async (root: Activity) => {
|
||||
private importInternal = async (root: Activity) => {
|
||||
this.rootId = root.id;
|
||||
const descriptors = descriptorsStore.activityDescriptors;
|
||||
const flowchart = root as Flowchart;
|
||||
|
|
@ -280,7 +280,7 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
|
||||
@Watch('root')
|
||||
async onRootChange(value: Activity) {
|
||||
await this.importRootInternal(value);
|
||||
await this.importInternal(value);
|
||||
}
|
||||
|
||||
@Watch('interactiveMode')
|
||||
|
|
@ -413,7 +413,7 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
onGraphChanged = async () => {
|
||||
if (this.silent)
|
||||
return;
|
||||
this.graphUpdated.emit({exportGraph: this.exportRootInternal});
|
||||
this.graphUpdated.emit({exportGraph: this.exportInternal});
|
||||
}
|
||||
|
||||
onToggleCanStartWorkflowClicked = (node: ActivityNodeShape) => {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import {Component, h, Prop, State, Event, EventEmitter, Listen, Element} from "@
|
|||
import {camelCase} from 'lodash';
|
||||
import {ActivityIcon, ActivityIconRegistry} from "../../../services";
|
||||
import {Container} from "typedi";
|
||||
import {Activity, ActivityDescriptor, ActivityKind, CreateChildActivityArgs, Port} from "../../../models";
|
||||
import {Activity, ActivityDescriptor, ActivityKind, CreateChildActivityArgs, EditChildActivityArgs, Port} from "../../../models";
|
||||
import descriptorsStore from "../../../data/descriptors-store";
|
||||
import {isNullOrWhitespace} from "../../../utils";
|
||||
|
||||
|
|
@ -25,24 +25,18 @@ export class DefaultActivityTemplate {
|
|||
@Prop({attribute: 'display-type'}) displayType: string;
|
||||
@Prop({attribute: 'activity'}) activityJson: string;
|
||||
@Prop() selected: boolean;
|
||||
@Prop() activity: Activity;
|
||||
@Event() createChildActivity: EventEmitter<CreateChildActivityArgs>;
|
||||
@Event() editChildActivity: EventEmitter<EditChildActivityArgs>;
|
||||
@State() private selectedPortName: string;
|
||||
|
||||
componentWillLoad() {
|
||||
const iconRegistry = this.iconRegistry;
|
||||
|
||||
if (!!this.activity) {
|
||||
{
|
||||
this.parsedActivity = this.activity;
|
||||
}
|
||||
} else {
|
||||
const encodedActivityJson = this.activityJson;
|
||||
const encodedActivityJson = this.activityJson;
|
||||
|
||||
if (!isNullOrWhitespace(encodedActivityJson)) {
|
||||
const decodedActivityJson = decodeURI(encodedActivityJson);
|
||||
this.parsedActivity = JSON.parse(decodedActivityJson);
|
||||
}
|
||||
if (!isNullOrWhitespace(encodedActivityJson)) {
|
||||
const decodedActivityJson = decodeURI(encodedActivityJson);
|
||||
this.parsedActivity = JSON.parse(decodedActivityJson);
|
||||
}
|
||||
|
||||
this.activityDescriptor = descriptorsStore.activityDescriptors.find(x => x.activityType == this.activityType);
|
||||
|
|
@ -150,7 +144,11 @@ export class DefaultActivityTemplate {
|
|||
<span class={textColor}>{childActivityDisplayText}</span>
|
||||
</div>
|
||||
<div class="flex-shrink">
|
||||
<a href="#" class="text-gray-500 hover:text-yellow-700">
|
||||
<a
|
||||
onClick={e => this.onEditChildActivityClick(e, activity, port)}
|
||||
onMouseDown={e => e.stopPropagation()}
|
||||
href="#"
|
||||
class="text-gray-500 hover:text-yellow-700">
|
||||
<svg class="h-6 w-6" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M4 20h4l10.5 -10.5a1.5 1.5 0 0 0 -4 -4l-10.5 10.5v4"/>
|
||||
|
|
@ -163,7 +161,7 @@ export class DefaultActivityTemplate {
|
|||
) : (
|
||||
<div class="relative block w-full border-2 border-gray-300 border-dashed rounded-lg p-5 text-center focus:outline-none">
|
||||
<a href="#"
|
||||
onClick={e => this.onAddChildActivityClick(e, activity, port)}
|
||||
onClick={e => this.onEditChildActivityClick(e, activity, port)}
|
||||
onMouseDown={e => e.stopPropagation()}
|
||||
class="text-gray-400 hover:text-gray-600">
|
||||
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
|
|
@ -197,6 +195,11 @@ export class DefaultActivityTemplate {
|
|||
|
||||
private onAddChildActivityClick = (e: MouseEvent, parentActivity: Activity, port: Port) => {
|
||||
e.preventDefault();
|
||||
this.createChildActivity.emit({parent: parentActivity, port: port});
|
||||
this.createChildActivity.emit({parentActivityId: parentActivity.id, port: port});
|
||||
};
|
||||
|
||||
private onEditChildActivityClick = (e: MouseEvent, parentActivity: Activity, port: Port) => {
|
||||
e.preventDefault();
|
||||
this.editChildActivity.emit({parentActivityId: parentActivity.id, port: port});
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export class Canvas {
|
|||
|
||||
@Method()
|
||||
public async exportGraph(): Promise<Activity> {
|
||||
return await this.root.exportRoot();
|
||||
return await this.root.export();
|
||||
}
|
||||
|
||||
@Method()
|
||||
|
|
@ -46,7 +46,7 @@ export class Canvas {
|
|||
|
||||
@Method()
|
||||
public async importGraph(root: Activity): Promise<void> {
|
||||
return await this.root.importRoot(root);
|
||||
return await this.root.import(root);
|
||||
}
|
||||
|
||||
@Method()
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import {Component, h, Listen, Prop, State, Event, EventEmitter, Method, Watch, Element} from '@stencil/core';
|
||||
import {debounce} from 'lodash';
|
||||
import {v4 as uuid} from 'uuid';
|
||||
import {debounce, camelCase} from 'lodash';
|
||||
import {Container} from "typedi";
|
||||
import {PanelPosition, PanelStateChangedArgs} from '../panel/models';
|
||||
import {
|
||||
Activity,
|
||||
ActivityDescriptor,
|
||||
ActivitySelectedArgs,
|
||||
ContainerSelectedArgs, CreateChildActivityArgs,
|
||||
ContainerSelectedArgs, CreateChildActivityArgs, EditChildActivityArgs,
|
||||
GraphUpdatedArgs, StorageDriverDescriptor,
|
||||
WorkflowDefinition
|
||||
} from '../../../models';
|
||||
|
|
@ -16,10 +15,9 @@ import {
|
|||
ActivityUpdatedArgs,
|
||||
DeleteActivityRequestedArgs
|
||||
} from './activity-properties-editor';
|
||||
import {PluginRegistry, ActivityNameFormatter, ActivityDriverRegistry, EventBus} from '../../../services';
|
||||
import {PluginRegistry, ActivityNameFormatter, ActivityDriverRegistry, EventBus, findActivity, walkActivities, flattenList} from '../../../services';
|
||||
import {MonacoEditorSettings} from "../../../services/monaco-editor-settings";
|
||||
import {Flowchart} from "../../activities/flowchart/models";
|
||||
import {flattenList, walkActivities} from "../../activities/flowchart/activity-walker";
|
||||
import {ActivityPropertyChangedEventArgs, WorkflowDefinitionPropsUpdatedArgs, WorkflowDefinitionUpdatedArgs, WorkflowEditorEventTypes} from "./models";
|
||||
import descriptorsStore from "../../../data/descriptors-store";
|
||||
import {WorkflowNavigationItem} from "../workflow-navigator/models";
|
||||
|
|
@ -51,12 +49,11 @@ export class WorkflowDefinitionEditor {
|
|||
}
|
||||
|
||||
@Prop() workflowDefinition?: WorkflowDefinition;
|
||||
@Prop({attribute: 'monaco-lib-path'}) public monacoLibPath: string;
|
||||
@Prop({attribute: 'monaco-lib-path'}) monacoLibPath: string;
|
||||
@Event() workflowUpdated: EventEmitter<WorkflowDefinitionUpdatedArgs>
|
||||
@State() private workflowDefinitionState: WorkflowDefinition;
|
||||
@State() private selectedActivity?: Activity;
|
||||
@State() private currentActivityPath: Array<WorkflowNavigationItem> = [];
|
||||
@State() private currentRootActivity: Activity;
|
||||
@State() private currentWorkflowPath: Array<WorkflowNavigationItem> = [];
|
||||
|
||||
@Watch('monacoLibPath')
|
||||
private handleMonacoLibPath(value: string) {
|
||||
|
|
@ -96,52 +93,60 @@ export class WorkflowDefinitionEditor {
|
|||
this.saveChangesDebounced();
|
||||
}
|
||||
|
||||
@Listen('createChildActivity')
|
||||
private async handleCreateChildActivity(e: CustomEvent<CreateChildActivityArgs>) {
|
||||
@Listen('editChildActivity')
|
||||
private async editChildActivity(e: CustomEvent<EditChildActivityArgs>) {
|
||||
const activity = findActivity(this.workflowDefinitionState.root, x => x.id == e.detail.parentActivityId);
|
||||
|
||||
const item: WorkflowNavigationItem = {
|
||||
activity: e.detail.parent,
|
||||
activity: activity,
|
||||
port: e.detail.port,
|
||||
};
|
||||
|
||||
this.currentActivityPath = [...this.currentActivityPath, item];
|
||||
this.currentWorkflowPath = [...this.currentWorkflowPath, item];
|
||||
const portName = camelCase(e.detail.port.name);
|
||||
const childActivity = activity[portName] as Activity;
|
||||
|
||||
await this.canvas.clear();
|
||||
if (!childActivity) {
|
||||
await this.canvas.clear();
|
||||
} else {
|
||||
await this.canvas.importGraph(childActivity);
|
||||
}
|
||||
}
|
||||
|
||||
@Method()
|
||||
public async getCanvas(): Promise<HTMLElsaCanvasElement> {
|
||||
async getCanvas(): Promise<HTMLElsaCanvasElement> {
|
||||
return this.canvas;
|
||||
}
|
||||
|
||||
@Method()
|
||||
public async registerActivityDrivers(register: (registry: ActivityDriverRegistry) => void): Promise<void> {
|
||||
async registerActivityDrivers(register: (registry: ActivityDriverRegistry) => void): Promise<void> {
|
||||
const registry = Container.get(ActivityDriverRegistry);
|
||||
register(registry);
|
||||
}
|
||||
|
||||
@Method()
|
||||
public getWorkflowDefinition(): Promise<WorkflowDefinition> {
|
||||
getWorkflowDefinition(): Promise<WorkflowDefinition> {
|
||||
return this.getWorkflowDefinitionInternal();
|
||||
}
|
||||
|
||||
@Method()
|
||||
public async importWorkflow(workflowDefinition: WorkflowDefinition): Promise<void> {
|
||||
this.workflowDefinitionState = workflowDefinition;
|
||||
this.currentActivityPath = [{activity: workflowDefinition.root}];
|
||||
this.currentRootActivity = workflowDefinition.root;
|
||||
async importWorkflow(workflowDefinition: WorkflowDefinition): Promise<void> {
|
||||
await this.updateWorkflowDefinition(workflowDefinition);
|
||||
await this.canvas.importGraph(workflowDefinition.root);
|
||||
await this.eventBus.emit(WorkflowEditorEventTypes.WorkflowDefinition.Imported, this, {workflowDefinition});
|
||||
}
|
||||
|
||||
// Updates the workflow definition without importing it into the designer.
|
||||
@Method()
|
||||
public async updateWorkflowDefinition(workflowDefinition: WorkflowDefinition): Promise<void> {
|
||||
async updateWorkflowDefinition(workflowDefinition: WorkflowDefinition): Promise<void> {
|
||||
this.workflowDefinitionState = workflowDefinition;
|
||||
|
||||
if (this.currentWorkflowPath.length == 0 || this.currentWorkflowPath.length == 1)
|
||||
this.currentWorkflowPath = [{activity: workflowDefinition.root, port: null}];
|
||||
}
|
||||
|
||||
@Method()
|
||||
public async newWorkflow() {
|
||||
async newWorkflow() {
|
||||
|
||||
const flowchartDescriptor = descriptorsStore.activityDescriptors.find(x => x.activityType == 'Elsa.Flowchart');
|
||||
const newName = await this.generateUniqueActivityName(flowchartDescriptor);
|
||||
|
|
@ -167,15 +172,14 @@ export class WorkflowDefinitionEditor {
|
|||
materializerName: 'Json'
|
||||
}
|
||||
|
||||
|
||||
await this.importWorkflow(workflowDefinition);
|
||||
}
|
||||
|
||||
public async componentWillLoad() {
|
||||
this.workflowDefinitionState = this.workflowDefinition;
|
||||
async componentWillLoad() {
|
||||
await this.updateWorkflowDefinition(this.workflowDefinition);
|
||||
}
|
||||
|
||||
public async componentDidLoad() {
|
||||
async componentDidLoad() {
|
||||
if (!this.workflowDefinitionState)
|
||||
await this.newWorkflow();
|
||||
else
|
||||
|
|
@ -184,7 +188,7 @@ export class WorkflowDefinitionEditor {
|
|||
await this.eventBus.emit(WorkflowEditorEventTypes.WorkflowEditor.Ready, this, {workflowEditor: this});
|
||||
}
|
||||
|
||||
public render() {
|
||||
render() {
|
||||
const tunnelState: WorkflowDesignerState = {
|
||||
workflowDefinition: this.workflowDefinitionState,
|
||||
};
|
||||
|
|
@ -193,7 +197,7 @@ export class WorkflowDefinitionEditor {
|
|||
<WorkflowEditorTunnel.Provider state={tunnelState}>
|
||||
<div class="absolute inset-0" ref={el => this.container = el}>
|
||||
<elsa-workflow-definition-editor-toolbar zoomToFit={this.onZoomToFit}/>
|
||||
<elsa-workflow-navigator items={this.currentActivityPath}/>
|
||||
<elsa-workflow-navigator items={this.currentWorkflowPath} onNavigate={this.onNavigateHierarchy}/>
|
||||
<elsa-panel
|
||||
class="elsa-activity-picker-container"
|
||||
position={PanelPosition.Left}
|
||||
|
|
@ -234,9 +238,26 @@ export class WorkflowDefinitionEditor {
|
|||
}
|
||||
|
||||
private getWorkflowDefinitionInternal = async (): Promise<WorkflowDefinition> => {
|
||||
const root = await this.canvas.exportGraph();
|
||||
const activity: Activity = await this.canvas.exportGraph();
|
||||
const workflowDefinition = this.workflowDefinitionState;
|
||||
workflowDefinition.root = root;
|
||||
const currentWorkflowPath = this.currentWorkflowPath;
|
||||
const currentWorkflowNavigationItem = currentWorkflowPath[currentWorkflowPath.length - 1];
|
||||
let currentActivity = currentWorkflowNavigationItem.activity;
|
||||
const currentPort = currentWorkflowNavigationItem.port;
|
||||
|
||||
if (!!currentPort) {
|
||||
const portName = camelCase(currentPort.name);
|
||||
const flowchart = activity as Flowchart;
|
||||
const activities = flowchart.activities;
|
||||
const root = activities.length == 0 ? null : activities.length == 1 ? activities[0] : flowchart;
|
||||
currentActivity[portName] = root;
|
||||
currentWorkflowPath[currentWorkflowPath.length - 1] = {activity: currentActivity, port: currentPort};
|
||||
|
||||
} else {
|
||||
workflowDefinition.root = activity;
|
||||
currentWorkflowPath[0] = {activity: activity, port: null};
|
||||
}
|
||||
|
||||
return workflowDefinition;
|
||||
};
|
||||
|
||||
|
|
@ -246,6 +267,7 @@ export class WorkflowDefinitionEditor {
|
|||
|
||||
private saveChanges = async (): Promise<void> => {
|
||||
const workflowDefinition = await this.getWorkflowDefinitionInternal();
|
||||
this.workflowDefinitionState = workflowDefinition;
|
||||
this.workflowUpdated.emit({workflowDefinition});
|
||||
};
|
||||
|
||||
|
|
@ -267,8 +289,7 @@ export class WorkflowDefinitionEditor {
|
|||
const activityType = activityDescriptor.activityType;
|
||||
const workflowDefinition = await this.getWorkflowDefinitionInternal();
|
||||
const root = workflowDefinition.root;
|
||||
const activityDescriptors = descriptorsStore.activityDescriptors;
|
||||
const graph = walkActivities(root, activityDescriptors);
|
||||
const graph = walkActivities(root);
|
||||
const activityNodes = flattenList(graph.children);
|
||||
const activityCount = activityNodes.filter(x => x.activity.typeName == activityType).length;
|
||||
let counter = activityCount + 1;
|
||||
|
|
@ -315,4 +336,13 @@ export class WorkflowDefinitionEditor {
|
|||
this.deleteActivity(e.detail.activity);
|
||||
this.selectedActivity = null;
|
||||
};
|
||||
|
||||
private onNavigateHierarchy = async (e: CustomEvent<WorkflowNavigationItem>) => {
|
||||
const item = e.detail;
|
||||
const path = this.currentWorkflowPath;
|
||||
const index = path.indexOf(item);
|
||||
|
||||
this.currentWorkflowPath = path.slice(0, index + 1);
|
||||
await this.canvas.importGraph(item.activity);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
import {Component, h, Prop, State, Watch} from "@stencil/core";
|
||||
import {ActionDefinition, ActionType, ActivityDescriptor, ActivityMetadata, WorkflowDefinition, WorkflowExecutionLogRecord, WorkflowInstance} from "../../../models";
|
||||
import {Container} from "typedi";
|
||||
import {ElsaApiClientProvider} from "../../../services";
|
||||
import {ActivityNode, ElsaApiClientProvider, flatten, walkActivities} from "../../../services";
|
||||
import {durationToString, formatTime, formatTimestamp, getDuration, isNullOrWhitespace} from "../../../utils";
|
||||
import {ActivityNode, flatten, walkActivities} from "../../activities/flowchart/activity-walker";
|
||||
import descriptorsStore from '../../../data/descriptors-store';
|
||||
import {ActivityExecutionEventBlock} from "./models";
|
||||
import {start} from "@stencil/core/dev-server";
|
||||
|
||||
const PAGE_SIZE: number = 20;
|
||||
|
||||
|
|
@ -118,8 +116,7 @@ export class WorkflowJournal {
|
|||
if (!this.workflowInstance || !this.workflowDefinition)
|
||||
return;
|
||||
|
||||
const activityDescriptors = descriptorsStore.activityDescriptors;
|
||||
const rootNode = walkActivities(this.workflowDefinition.root, activityDescriptors);
|
||||
const rootNode = walkActivities(this.workflowDefinition.root);
|
||||
const nodes = flatten(rootNode);
|
||||
this.activityNodes = nodes;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Activity, Port} from "../../../models";
|
||||
|
||||
export interface WorkflowNavigationItem {
|
||||
activity?: Activity;
|
||||
activity: Activity;
|
||||
port?: Port;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
import {Component, FunctionalComponent, h, Prop} from "@stencil/core";
|
||||
import {FlowchartIcon, IfIcon} from "../../icons/activities";
|
||||
import {Activity} from "../../../models";
|
||||
import descriptorsStore from "../../../data/descriptors-store";
|
||||
import {Component, FunctionalComponent, h, Prop, Event, EventEmitter} from "@stencil/core";
|
||||
import {Container} from "typedi";
|
||||
import {ActivityIconRegistry} from "../../../services";
|
||||
import {WorkflowNavigationItem} from "./models";
|
||||
|
|
@ -13,6 +10,7 @@ import {WorkflowNavigationItem} from "./models";
|
|||
export class WorkflowNavigator {
|
||||
|
||||
@Prop() items: Array<WorkflowNavigationItem> = [];
|
||||
@Event() navigate: EventEmitter<WorkflowNavigationItem>;
|
||||
|
||||
render() {
|
||||
|
||||
|
|
@ -24,29 +22,38 @@ export class WorkflowNavigator {
|
|||
return <div class="ml-8">
|
||||
<nav class="flex" aria-label="Breadcrumb">
|
||||
<ol role="list" class="flex items-center space-x-3">
|
||||
{items.map(activity => <ActivityPathItem item={activity}/>)}
|
||||
{items.map((activity, index) => <ActivityPathItem item={activity} onClick={this.onItemClick}/>)}
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
}
|
||||
|
||||
private onItemClick = (item: WorkflowNavigationItem) => this.navigate.emit(item);
|
||||
}
|
||||
|
||||
interface ActivityPathItemProps {
|
||||
item: WorkflowNavigationItem;
|
||||
onClick: (item: WorkflowNavigationItem) => void;
|
||||
}
|
||||
|
||||
const ActivityPathItem: FunctionalComponent<ActivityPathItemProps> = ({item}) => {
|
||||
const ActivityPathItem: FunctionalComponent<ActivityPathItemProps> = ({item, onClick}) => {
|
||||
const iconRegistry = Container.get(ActivityIconRegistry);
|
||||
const activity = item.activity;
|
||||
const icon = iconRegistry.get(activity.typeName)();
|
||||
const activityId = activity.id;
|
||||
|
||||
const listElements = [];
|
||||
|
||||
const onItemClick = (e: MouseEvent, item: WorkflowNavigationItem) => {
|
||||
e.preventDefault();
|
||||
onClick(item);
|
||||
}
|
||||
|
||||
listElements.push(
|
||||
<li>
|
||||
<div class="flex items-center">
|
||||
<a href="#" class="block flex items-center text-gray-400 hover:text-gray-500">
|
||||
<a onClick={e => onItemClick(e, item)}
|
||||
href="#"
|
||||
class="block flex items-center text-gray-400 hover:text-gray-500">
|
||||
<div class="bg-blue-500 rounded">
|
||||
{icon}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@ export interface GraphUpdatedArgs {
|
|||
}
|
||||
|
||||
export interface CreateChildActivityArgs {
|
||||
parent: Activity;
|
||||
parentActivityId: string;
|
||||
port: Port;
|
||||
}
|
||||
|
||||
export interface EditChildActivityArgs {
|
||||
parentActivityId: string;
|
||||
port: Port;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import 'reflect-metadata';
|
||||
import {FunctionalComponent, h} from '@stencil/core';
|
||||
import {Container, Service} from "typedi";
|
||||
import {ActivityIconRegistry, InputControlRegistry} from "../../services";
|
||||
import {ActivityIconRegistry, InputControlRegistry, PortProviderRegistry} from "../../services";
|
||||
import {Plugin} from "../../models";
|
||||
import {PortProviderRegistry} from "../../components/activities/flowchart/port-provider-registry";
|
||||
import {SwitchPortProvider} from "./switch-port-provider";
|
||||
|
||||
@Service()
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'reflect-metadata';
|
||||
import {Service} from "typedi";
|
||||
import {PortProvider, PortProviderContext} from "../../components/activities/flowchart/port-provider";
|
||||
import {Port} from "../../models";
|
||||
import {SwitchActivity} from "./models";
|
||||
import {PortProvider, PortProviderContext} from "../../services";
|
||||
|
||||
@Service()
|
||||
export class SwitchPortProvider implements PortProvider {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import {Service} from 'typedi';
|
||||
import {camelCase, startCase, snakeCase, kebabCase} from 'lodash';
|
||||
import {ActivityDescriptor} from "../models";
|
||||
import {ActivityNode} from "../components/activities/flowchart/activity-walker";
|
||||
import {stripActivityNameSpace} from "../utils";
|
||||
import {ActivityNode} from "./activity-walker";
|
||||
|
||||
export type ActivityNameStrategy = (context: ActivityNameFormatterContext) => string;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import 'reflect-metadata';
|
||||
import {camelCase} from 'lodash';
|
||||
import {Container} from "typedi"
|
||||
import {Activity, ActivityDescriptor} from "../../../models";
|
||||
import {Activity, ActivityDescriptor} from "../models";
|
||||
import {PortProviderRegistry} from "./port-provider-registry";
|
||||
import descriptorsStore from '../data/descriptors-store';
|
||||
|
||||
export interface ActivityNode {
|
||||
activity: Activity;
|
||||
|
|
@ -16,7 +17,8 @@ export interface ActivityPort {
|
|||
port: string;
|
||||
}
|
||||
|
||||
export function walkActivities(root: Activity, descriptors: Array<ActivityDescriptor>): ActivityNode {
|
||||
export function walkActivities(root: Activity): ActivityNode {
|
||||
const descriptors = descriptorsStore.activityDescriptors;
|
||||
const collectedActivities = new Set<Activity>([root]);
|
||||
const graph: ActivityNode = {activity: root, parents: [], children: []};
|
||||
const collectedNodes = new Set<ActivityNode>([graph]);
|
||||
|
|
@ -39,6 +41,12 @@ export function flattenList(activities: Array<ActivityNode>): Array<ActivityNode
|
|||
return list;
|
||||
}
|
||||
|
||||
export function findActivity(root: Activity, predicate: (activity: Activity) => boolean): Activity {
|
||||
const graph = walkActivities(root);
|
||||
const nodes = flatten(graph);
|
||||
return nodes.find(node => predicate(node.activity))?.activity;
|
||||
}
|
||||
|
||||
function walkRecursive(node: ActivityNode, activity: Activity, collectedActivities: Set<Activity>, collectedNodes: Set<ActivityNode>, descriptors: Array<ActivityDescriptor>) {
|
||||
const ports = getPorts(node, activity, descriptors);
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import 'reflect-metadata';
|
||||
import {Service} from "typedi"
|
||||
import {Port} from "../../../models";
|
||||
import {PortProvider, PortProviderContext} from "./port-provider";
|
||||
import {Port} from "../models";
|
||||
|
||||
@Service()
|
||||
export class DefaultPortProvider implements PortProvider {
|
||||
|
|
@ -9,3 +9,7 @@ export * from './input-driver-registry';
|
|||
export * from './server-settings';
|
||||
export * from './activity-name-formatter';
|
||||
export * from './plugin-registry';
|
||||
export * from './activity-walker';
|
||||
export * from './default-port-provider';
|
||||
export * from './port-provider';
|
||||
export * from './port-provider-registry';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {Activity, ActivityDescriptor, Port} from "../../../models";
|
||||
import {Activity, ActivityDescriptor, Port} from "../models";
|
||||
|
||||
export interface PortProvider {
|
||||
getInboundPorts(context: PortProviderContext): Array<Port>;
|
||||
Loading…
Reference in a new issue