Fix race condition between activity selection and execution event block

Fixes #4077
This commit is contained in:
Sipke Schoorstra 2023-05-29 21:22:31 +02:00
parent d12b38cae2
commit 921472b6b8
3 changed files with 35 additions and 32 deletions

View file

@ -227,7 +227,7 @@ export class Journal {
private onJournalItemClick = async (e: MouseEvent, block: ActivityExecutionEventBlock, activity: Activity) => {
e.preventDefault();
this.journalItemSelected.emit({activity: activity, executionLog: block, activityNode: this.journalActivityMap[block.nodeId]});
this.journalItemSelected.emit({activity: activity, executionEventBlock: block, activityNode: this.journalActivityMap[block.nodeId]});
};
private sortByTimestamp(blocks: ActivityExecutionEventBlock[]) {

View file

@ -13,9 +13,9 @@ import {ActivityDriverRegistry, EventBus, ActivityNode} from '../../../services'
import {MonacoEditorSettings} from "../../../services/monaco-editor-settings";
import {WorkflowDefinition} from "../../workflow-definitions/models/entities";
import {WorkflowEditorEventTypes} from "../../workflow-definitions/models/ui";
import { JournalItemSelectedArgs } from '../events';
import {JournalItemSelectedArgs} from '../events';
import {JournalApi} from "../services/journal-api";
import { Flowchart } from '../../flowchart/models';
import {Flowchart} from '../../flowchart/models';
@Component({
tag: 'elsa-workflow-instance-viewer',
@ -26,6 +26,7 @@ export class WorkflowInstanceViewer {
private readonly journalApi: JournalApi;
private flowchartElement: HTMLElsaFlowchartElement;
private container: HTMLDivElement;
private isJournalSelecting: boolean = false;
constructor() {
this.eventBus = Container.get(EventBus);
@ -40,7 +41,7 @@ export class WorkflowInstanceViewer {
@State() private targetWorkflowDefinitionState: WorkflowDefinition;
@State() private workflowInstanceState: WorkflowInstance;
@State() private selectedActivity?: Activity;
@State() private selectedActivityExecutionLog?: WorkflowExecutionLogRecord;
@State() private selectedExecutionLogRecord?: WorkflowExecutionLogRecord;
@State() private flowchartRootActivity: Activity;
@Watch('monacoLibPath')
@ -77,32 +78,35 @@ export class WorkflowInstanceViewer {
@Listen('activitySelected')
private async handleActivitySelected(e: CustomEvent<ActivitySelectedArgs>) {
if (this.isJournalSelecting)
return;
this.selectedActivity = e.detail.activity;
const workflowInstanceId = this.workflowInstance.id;
const activityId = this.selectedActivity.id;
this.selectedActivityExecutionLog = await this.journalApi.getLastEntry({workflowInstanceId, activityId});
this.selectedExecutionLogRecord = await this.journalApi.getLastEntry({workflowInstanceId, activityId});
}
@Listen('journalItemSelected')
private async handleJournalItemSelected(e: CustomEvent<JournalItemSelectedArgs>) {
const activityId = e.detail.activity.id;
const activityNode = e.detail.activityNode;
const graph = await this.flowchartElement.getGraph();
const graphNode = graph.getNodes().find(n => n.id == activityId)
if(graphNode == null) {
await this.importSelectedItemsWorkflow(activityNode);
graph.resetSelection();
this.selectedActivity = e.detail.activity;
}
else {
graph.resetSelection(graphNode);
this.selectedActivity = graphNode.data;
}
const executionEventBlock = e.detail.executionEventBlock;
this.selectedExecutionLogRecord = executionEventBlock.faulted ? executionEventBlock.faultedRecord : executionEventBlock.completed ? executionEventBlock.completedRecord : executionEventBlock.startedRecord;
const log = e.detail.executionLog;
this.selectedActivityExecutionLog = log.faulted ? log.faultedRecord : log.completed ? log.completedRecord : log.startedRecord;
this.isJournalSelecting = true;
if (graphNode == null) {
await this.importSelectedItemsWorkflow(activityNode);
this.selectedActivity = e.detail.activity;
graph.resetSelection();
} else {
this.selectedActivity = graphNode.data;
graph.resetSelection(graphNode);
}
this.isJournalSelecting = false;
}
private async importSelectedItemsWorkflow(activityNode: ActivityNode) {
@ -115,32 +119,29 @@ export class WorkflowInstanceViewer {
});
}
private findConsumingWorkflowRecursive(activityNode: ActivityNode) : ActivityNode {
private findConsumingWorkflowRecursive(activityNode: ActivityNode): ActivityNode {
const parent = activityNode.parents[0];
if(parent == null) {
if (parent == null) {
return activityNode;
}
else{
} else {
const type = parent.activity.type;
if(type == "Elsa.Workflow" || type == "Elsa.Flowchart") {
if (type == "Elsa.Workflow" || type == "Elsa.Flowchart") {
return this.findConsumingWorkflowRecursive(parent);
}
else {
} else {
return parent;
}
}
}
private async getFlowchartByActivityNode(consumingWorkflowNode: ActivityNode) : Promise<Flowchart> {
private async getFlowchartByActivityNode(consumingWorkflowNode: ActivityNode): Promise<Flowchart> {
const isConsumingWorkflowSameAsMain = consumingWorkflowNode.parents[0] == null;
return isConsumingWorkflowSameAsMain ? this.workflowDefinition.root as Flowchart : this.findFlowchartOfActivityRecursive(consumingWorkflowNode.activity);
}
private findFlowchartOfActivityRecursive(activity: Activity): Flowchart {
if(activity.type == "Elsa.Flowchart"){
if (activity.type == "Elsa.Flowchart") {
return activity as Flowchart;
}
else{
} else {
return this.findFlowchartOfActivityRecursive((activity as Workflow).root);
}
}
@ -193,8 +194,10 @@ export class WorkflowInstanceViewer {
private renderSelectedObject = () => {
const activity = this.selectedActivity;
if (!!activity)
return <elsa-activity-properties activity={activity} activityExecutionLog={this.selectedActivityExecutionLog}/>;
if (!!activity) {
const selectedRecord = this.selectedExecutionLogRecord;
return <elsa-activity-properties activity={activity} activityExecutionLog={selectedRecord}/>;
}
}
private getWorkflowInternal = async (): Promise<WorkflowDefinition> => {

View file

@ -4,6 +4,6 @@ import { ActivityExecutionEventBlock } from "./models";
export interface JournalItemSelectedArgs {
activity: Activity;
executionLog: ActivityExecutionEventBlock;
executionEventBlock: ActivityExecutionEventBlock;
activityNode: ActivityNode;
}
}