Skip to content

FOUR-20534: Implement the perfomance In-flight in Request and Cases #7816

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

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion ProcessMaker/Http/Controllers/CasesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
use ProcessMaker\Models\Screen;
use ProcessMaker\Package\PackageComments\PackageServiceProvider;
use ProcessMaker\ProcessTranslations\ScreenTranslation;
use ProcessMaker\Traits\ProcessMapTrait;

class CasesController extends Controller
{
use ProcessMapTrait;
/**
* Get the list of requests.
*
Expand Down Expand Up @@ -76,6 +78,45 @@ public function show($case_number)
// Get the summary screen tranlations
$this->summaryScreenTranslation($request);

// Load the process map
$processRequest = ProcessRequest::find($request->id);

$bpmn = $request->process->bpmn;
$filteredCompletedNodes = [];
$requestInProgressNodes = [];
$requestIdleNodes = [];

if ($processRequest) {
$requestCompletedNodes = $processRequest->tokens()
->whereIn('status', ['CLOSED', 'COMPLETED', 'TRIGGERED'])
->pluck('element_id');
$requestInProgressNodes = $processRequest->tokens()
->whereIn('status', ['ACTIVE', 'INCOMING'])
->pluck('element_id');
// Remove any node that is 'ACTIVE' from the completed list.
$filteredCompletedNodes = $requestCompletedNodes->diff($requestInProgressNodes)->values();

// Obtain In-Progress nodes that were completed before
$matchingNodes = $requestInProgressNodes->intersect($requestCompletedNodes);

// Get idle nodes.
$xml = $this->loadAndPrepareXML($bpmn);
$nodeIds = $this->getNodeIds($xml);
$requestIdleNodes = $nodeIds->diff($filteredCompletedNodes)->diff($requestInProgressNodes)->values();

// Add completed sequence flow to the list of completed nodes.
$sequenceFlowNodes = $this->getCompletedSequenceFlow($xml, $filteredCompletedNodes->implode(' '), $requestInProgressNodes->implode(' '), $matchingNodes->implode(' '));
$filteredCompletedNodes = $filteredCompletedNodes->merge($sequenceFlowNodes);
}


$inflightData = [
'bpmn' => $bpmn,
'requestCompletedNodes' => $filteredCompletedNodes,
'requestInProgressNodes' => $requestInProgressNodes,
'requestIdleNodes' => $requestIdleNodes,
'requestId' => $request->process->id,
];
// Return the view
return view('cases.edit', compact(
'request',
Expand All @@ -85,7 +126,9 @@ public function show($case_number)
'canViewComments',
'canPrintScreens',
'isProcessManager',
'manager'
'manager',
'bpmn',
'inflightData',
));
}

Expand Down
43 changes: 43 additions & 0 deletions ProcessMaker/Http/Controllers/RequestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
use ProcessMaker\ProcessTranslations\ScreenTranslation;
use ProcessMaker\RetryProcessRequest;
use ProcessMaker\Traits\HasControllerAddons;
use ProcessMaker\Traits\ProcessMapTrait;
use ProcessMaker\Traits\SearchAutocompleteTrait;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

class RequestController extends Controller
{
use SearchAutocompleteTrait;
use HasControllerAddons;
use ProcessMapTrait;

/**
* Get the list of requests.
Expand Down Expand Up @@ -182,6 +184,45 @@ public function show(ProcessRequest $request, Media $mediaItems)
}
$this->summaryScreenTranslation($request);

//Load the process map
$processRequest = ProcessRequest::find($request->id);
$bpmn = $request->process->bpmn;
$filteredCompletedNodes = [];
$requestInProgressNodes = [];
$requestIdleNodes = [];

if ($processRequest) {
$requestCompletedNodes = $processRequest->tokens()
->whereIn('status', ['CLOSED', 'COMPLETED', 'TRIGGERED'])
->pluck('element_id');
$requestInProgressNodes = $processRequest->tokens()
->whereIn('status', ['ACTIVE', 'INCOMING'])
->pluck('element_id');
// Remove any node that is 'ACTIVE' from the completed list.
$filteredCompletedNodes = $requestCompletedNodes->diff($requestInProgressNodes)->values();

// Obtain In-Progress nodes that were completed before
$matchingNodes = $requestInProgressNodes->intersect($requestCompletedNodes);

// Get idle nodes.
$xml = $this->loadAndPrepareXML($bpmn);
$nodeIds = $this->getNodeIds($xml);
$requestIdleNodes = $nodeIds->diff($filteredCompletedNodes)->diff($requestInProgressNodes)->values();

// Add completed sequence flow to the list of completed nodes.
$sequenceFlowNodes = $this->getCompletedSequenceFlow($xml, $filteredCompletedNodes->implode(' '), $requestInProgressNodes->implode(' '), $matchingNodes->implode(' '));
$filteredCompletedNodes = $filteredCompletedNodes->merge($sequenceFlowNodes);
}


$inflightData = [
'bpmn' => $bpmn,
'requestCompletedNodes' => $filteredCompletedNodes,
'requestInProgressNodes' => $requestInProgressNodes,
'requestIdleNodes' => $requestIdleNodes,
'requestId' => $request->process->id,
];

if (isset($_SERVER['HTTP_USER_AGENT']) && MobileHelper::isMobile($_SERVER['HTTP_USER_AGENT'])) {
return view('requests.showMobile', compact(
'request',
Expand Down Expand Up @@ -217,6 +258,8 @@ public function show(ProcessRequest $request, Media $mediaItems)
'eligibleRollbackTask',
'errorTask',
'userConfiguration',
'bpmn',
'inflightData',
));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import RequestTable from "./RequestTable.vue";
import TabHistory from "./TabHistory.vue";
import CompletedForms from "./CompletedForms.vue";
import TabFiles from "./TabFiles.vue";
import Overview from "./Overview.vue";
import Overview from "./NewOverview.vue";
import TabSummary from "./TabSummary.vue";
import ErrorsTab from "./ErrorsTab.vue";
import { getRequestCount, getRequestStatus, isErrors } from "../variables/index";
Expand Down Expand Up @@ -67,7 +67,7 @@ const tabs = [
name: translate.t("Summary"),
href: "#summary",
current: "summary",
show: getRequestStatus() !== 'ERROR',
show: getRequestStatus() !== "ERROR",
content: TabSummary,
},
{
Expand Down
138 changes: 138 additions & 0 deletions resources/jscomposition/cases/casesDetail/components/NewOverview.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<template>
<div
class="tw-w-full tw-h-full tw-overflow-hidden tw-relative"
data-test="body-container"
>
<ProcessMapTooltip
v-show="showTooltip"
ref="tooltipRef"
:enabled="enableTooltip"
:node-id="tooltip.nodeId"
:node-name="tooltip.nodeName"
:request-id="inflightData.requestId"
:style="{
left: `${tooltip.newX}px`,
top: `${tooltip.newY}px`
}"
@is-loading="isTooltipLoading"
/>
<transition
name="fade"
mode="in-out"
>
<Modeler
ref="modelerRef"
:key="keyModeler"
:decorations="decorations"
:request-completed-nodes="inflightData.requestCompletedNodes"
:request-in-progress-nodes="inflightData.requestInProgressNodes"
:request-idle-nodes="inflightData.requestIdleNodes"
:read-only="true"
@set-xml-manager="xmlManager = $event"
@click="handleClick"
/>
</transition>
</div>
</template>

<script setup>
import {
ref, watchEffect, onMounted, computed, nextTick, onBeforeUnmount,
} from "vue";
import { Modeler } from "@processmaker/modeler";
import ProcessMapTooltip from "../../../../js/processes/modeler/components/ProcessMapTooltip.vue";
import { getInflightData } from "../variables";

const keyModeler = ref(Math.random());
const modelerRef = ref("");
const tooltipRef = ref(null);
const enableTooltip = ref(true);
const decorations = ref({
borderOutline: {},
});
const xmlManager = ref();
const tooltip = ref({
isActive: false,
isLoading: false,
nodeId: null,
nodeName: null,
allowedNodes: [
"bpmn:Task",
"bpmn:ManualTask",
"bpmn:SequenceFlow",
"bpmn:ScriptTask",
"bpmn:CallActivity",
"bpmn:ServiceTask",
],
coordinates: { x: 0, y: 0 },
newX: 0,
newY: 0,
});
const inflightData = ref(getInflightData());

const isMappingActive = computed(() => (window.ProcessMaker.modeler.enableProcessMapping !== undefined
? window.ProcessMaker.modeler.enableProcessMapping
: true));

const showTooltip = computed(() => enableTooltip.value && tooltip.value.isActive);

const calculateTooltipPosition = () => {
const rectTooltip = tooltipRef.value.$el.getBoundingClientRect();
tooltip.value.newY = tooltip.value.coordinates.y - rectTooltip.height - 20;
if (tooltip.value.newY <= 0) {
tooltip.value.newY = 10;
}
tooltip.value.newX = tooltip.value.coordinates.x - (rectTooltip.width / 2);
if (tooltip.value.newX < 0) {
tooltip.value.newX = 0;
} else if (tooltip.value.newX + rectTooltip.width > window.innerWidth) {
tooltip.value.newX = window.innerWidth - rectTooltip.width;
}
};

const setupTooltip = ({ event, node }) => {
const isNodeTooltipAllowed = tooltip.value.allowedNodes.includes(node.$type);
if ((isNodeTooltipAllowed && !tooltip.value.isActive)
|| (isNodeTooltipAllowed && tooltip.value.nodeId !== node.id)) {
tooltip.value.nodeId = node.id;
tooltip.value.nodeName = node.name;
tooltip.value.isActive = true;
nextTick(() => {
tooltip.value.coordinates = { x: event.clientX, y: event.clientY };
calculateTooltipPosition();
});
} else if (tooltip.value.nodeId === node.id && tooltip.value.isActive) {
tooltip.value.isActive = false;
}
};

const isTooltipLoading = (value) => {
tooltip.value.isLoading = value;
};

const handleClick = (payload) => {
if (isMappingActive.value) {
setupTooltip(payload);
}
};

watchEffect(() => {
if (!tooltip.value.isLoading) {
nextTick(() => {
calculateTooltipPosition();
});
}
});

onMounted(() => {
ProcessMaker.$modeler = modelerRef.value;
});

onBeforeUnmount(() => {
console.log("unmounted");
ProcessMaker.$modeler = null;
modelerRef.value?.$destroy();
modelerRef.value = null;
tooltipRef.value = null;
});
</script>
4 changes: 4 additions & 0 deletions resources/jscomposition/cases/casesDetail/variables/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ export const getRequestCount = () => requestCount;
export const getErrors = () => errorLogs;

export const isErrors = () => request.status === "ERROR";

export const getInflightData = () => inflightData;

export const getXML = () => inflightData.bpmn;
30 changes: 30 additions & 0 deletions resources/views/cases/edit.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ class="tw-grow tw-overflow-hidden"
@endsection

@section('js')
<script src="{{ mix('js/processes/modeler/initialLoad.js') }}"></script>
<script>
window.ProcessMaker.packages = @json(\App::make(ProcessMaker\Managers\PackageManager::class)->listPackages());
window.Processmaker = {
csrfToken: "{{csrf_token()}}",
userId: "{{\Auth::user()->id}}",
messages: [],
apiTimeout: {{config('app.api_timeout')}}
};
</script>
<script>
const data = @json($request->getRequestData());
const requestId = @json($request->getKey());
Expand All @@ -129,6 +139,26 @@ class="tw-grow tw-overflow-hidden"
const canViewComments = @json($canViewComments);
const comentable_type = @json(get_class($request));
const requestCount = @json($requestCount);
const inflightData = @json($inflightData);

window.ProcessMaker.modeler = {
xml: @json($bpmn),
configurables: [],
requestCompletedNodes: inflightData.requestCompletedNodes,
requestInProgressNodes: inflightData.requestInProgressNodes,
requestIdleNodes: inflightData.requestIdleNodes,
requestId: inflightData.requestId,
}

window.ProcessMaker.EventBus.$on('modeler-start', ({
loadXML
}) => {
loadXML(window.ProcessMaker.modeler.xml);
});

window.PM4ConfigOverrides = {
requestFiles: @json($request->requestFiles())
};
</script>

@if (hasPackage('package-files'))
Expand Down
Loading
Loading