<template>
<div>
<v-toolbar>
<v-toolbar-title>Executions</v-toolbar-title>
<v-spacer></v-spacer>
<span class="mx-3">Running Instances: {{ runningInstances.length }}</span>
<v-btn color="primary" @click="showDeployModal = true" :loading="isCurrentlyDeploying"
>Deploy Process</v-btn
>
</v-toolbar>
<popup :popupData="popupData" />
<v-dialog
eager
fullscreen
v-model="updateElementMachineMapping"
@keydown.esc="updateElementMachineMapping = false"
>
<MachineMappingModeler
:show="updateElementMachineMapping"
:xml="deployProcessXml"
@saveMachineMapping="saveMachineMapping($event)"
@cancel="updateElementMachineMapping = false"
@deploy="deployProcessToMachines(processToDeploy, false)"
/>
</v-dialog>
<v-container fluid>
<v-row justify="center" id="wrapper">
<v-col class="text-center centered">
<DeploymentDatatable
:deployments="sortedDeployments.local"
@openModal="navigateToDeployment"
>
<div>
<v-row><span class="mx-3">Known Processes</span></v-row>
<v-row
><span class="text-caption font-weight-light mx-3"
>Deployments with processes known to the Management System</span
></v-row
>
</div>
</DeploymentDatatable>
</v-col>
</v-row>
</v-container>
<v-container
fluid
v-if="Array.isArray(sortedDeployments.external) && sortedDeployments.external.length"
>
<v-row justify="center" id="wrapper">
<v-col class="text-center centered">
<DeploymentDatatable
:deployments="sortedDeployments.external"
is-external
@click:import="importProcess($event)"
@openModal="navigateToDeployment"
>
<div>
<v-row><span class="mx-3">Discovered Processes</span></v-row>
<v-row
><span class="text-caption font-weight-light mx-3"
>Deployments with processes unknown to the Management System</span
></v-row
>
</div>
</DeploymentDatatable>
</v-col>
</v-row>
</v-container>
<ProcessModal
isDeploymentMode
callToActionText="Deploy Process"
:show="showDeployModal"
maxWidth="1200px"
@cancel="showDeployModal = false"
@staticDeployment="openMappingEditor($event)"
@dynamicDeployment="deployProcessToMachines($event, true)"
></ProcessModal>
</div>
</template>
<script>
import { engineNetworkInterface } from '@/frontend/backend-api/index.js';
import { setMachineInfo, setDeploymentMethod } from '@proceed/bpmn-helper';
import DeploymentDatatable from '@/frontend/components/deployments/DeploymentDatatable.vue';
import AlertWindow from '@/frontend/components/universal/Alert.vue';
import MachineMappingModeler from '@/frontend/components/deployments/MachineMappingModeler.vue';
import ProcessModal from '@/frontend/components/processes/editor/ProcessModal.vue';
/**
* @module views
*/
/**
* @memberof module:views
* @module Vue:Deployments
*/
export default {
components: {
DeploymentDatatable,
MachineMappingModeler,
popup: AlertWindow,
ProcessModal,
},
data() {
return {
/** */
deployDefinitionId: '',
popupData: {
body: '',
display: 'none',
color: '',
},
/** */
updateElementMachineMapping: false,
/** */
deployProcessXml: '',
/** */
processToDeploy: null,
/** */
showDeployModal: false,
/** */
isCurrentlyDeploying: false,
};
},
computed: {
processes() {
const processes = this.$store.getters['processStore/processes'];
/**
* Adding additional meta information to current fetched processes
* Key 1 : totalDeployments
* Key 2 : totalInstances
*/
return processes.map((process) => {
const specificDeployedProcesses = this.deployedProcesses.filter(
(deployment) => deployment.definitionId === process.id
);
process.totalDeployments = specificDeployedProcesses.length;
process.totalInstances = 0;
for (const deployment of specificDeployedProcesses) {
process.totalInstances += deployment.runningInstances.length;
process.totalInstances += deployment.endedInstances.length;
}
return process;
});
},
deployedProcesses() {
// list of states that signal a still unfinished instance
const activeStates = ['RUNNING', 'READY', 'DEPLOYMENT-WAITING', 'PAUSED'];
const deployedProcesses = this.$store.getters['machineStore/deployments'].map(
(deployedProcess) => {
const deployedProcessInformation = { ...deployedProcess };
delete deployedProcessInformation.instances;
const runningInstances = [];
const endedInstances = [];
deployedProcess.instances.forEach((instance) => {
const instanceIsRunning = instance.instanceState.some((state) =>
activeStates.includes(state)
);
if (instanceIsRunning) {
runningInstances.push(instance);
} else {
endedInstances.push(instance);
}
});
deployedProcessInformation.runningInstances = runningInstances;
deployedProcessInformation.endedInstances = endedInstances;
return deployedProcessInformation;
}
);
return deployedProcesses;
},
/**
* Sort deployments into two lists: one for local process deployments and one for external deployments
*
* @returns {object} - object containing local and external member for deployments
*/
sortedDeployments() {
const sortedDeployments = { local: [], external: [] };
for (const deployment of this.deployedProcesses) {
const storedDeployedProcess = this.processes.find(
(process) => process.id === deployment.definitionId
);
if (storedDeployedProcess) {
sortedDeployments.local.push({ ...deployment, type: storedDeployedProcess.type });
} else {
sortedDeployments.external.push(deployment);
}
}
return sortedDeployments;
},
runningInstances() {
let runningInstances = [];
for (const deployment of this.deployedProcesses) {
const instanceInfo = deployment.runningInstances.map((instance) => ({
definitionId: deployment.definitionId,
instanceId: instance.processInstanceId,
machineIds: instance.machines.map((machine) => machine.id),
}));
runningInstances = [...runningInstances, ...instanceInfo];
}
return runningInstances;
},
},
methods: {
/**
* Deploys the given process
*
* @param {string} processToDeploy - process to be deployed as xml
*/
deployProcess(processToDeploy) {
this.processToDeploy = processToDeploy;
this.deployDefinitionId = processToDeploy.id;
this.showDeployModal = false;
},
/** */
navigateToDeployment(deployment) {
if (deployment.type === 'project') {
this.$router.push({ name: 'show-project-bpmn', params: { id: deployment.definitionId } });
} else {
this.$router.push({
name: 'deployment-overview',
params: { id: deployment.definitionId },
});
}
},
/** */
async deployProcessToMachines(processToDeploy, dynamic) {
if (this.deployedProcesses.find((process) => process.definitionId == processToDeploy.id)) {
this.popupData.body = 'Process already deployed';
this.popupData.color = 'warning';
this.showDeployModal = false;
this.openPopup();
} else {
this.deployProcess(processToDeploy);
this.isCurrentlyDeploying = true;
try {
await engineNetworkInterface.deployProcess(processToDeploy.id, dynamic);
this.popupData.body = 'Deployed process successfully';
this.popupData.color = 'success';
} catch (err) {
this.popupData.body = `Failed to deploy process: ${err.message}.`;
this.popupData.color = 'error';
}
this.openPopup();
this.isCurrentlyDeploying = false;
}
this.updateElementMachineMapping = false;
setTimeout(() => {
this.popupData.display = 'none';
}, 7000);
this.deployDefinitionId = '';
},
/**
* Opens a popup dialog
*/
openPopup() {
this.popupData.display = 'block';
},
/**
* Opens dialog that allows editing of machine maching for process with given id
*
* @param {string} definitionId id of the process we want to update
*/
async openMappingEditor(processToDeploy) {
this.deployProcess(processToDeploy);
const process = this.processes.find(
(storedProcess) => storedProcess.id === processToDeploy.id
);
this.deployProcessXml = await setDeploymentMethod(
await this.$store.getters['processStore/xmlById'](process.id),
'static'
);
this.updateElementMachineMapping = true;
this.$store.dispatch('processStore/updateWholeXml', {
id: this.deployDefinitionId,
bpmn: this.deployProcessXml,
});
},
/**
* Saves the given machine mapping in the bpmn of the currently selected process
*
* @param {object} obj the flowNode to machine mapping
*/
async saveMachineMapping(obj) {
if (obj) {
this.deployProcessXml = await setMachineInfo(this.deployProcessXml, obj);
this.$store.dispatch('processStore/updateWholeXml', {
id: this.deployDefinitionId,
bpmn: this.deployProcessXml,
});
}
},
/**
* For saving processes on the MS which are stored on an engine
*/
importProcess(deployment) {
// TODO: like in import
this.$store.dispatch('processStore/add', {
process: {
name: deployment.name,
id: deployment.definitionId,
variables: [],
},
bpmn: deployment.bpmn,
});
},
},
mounted() {
engineNetworkInterface.subscribeForDeploymentsUpdates();
engineNetworkInterface.startMachinePolling();
},
async beforeRouteLeave(to, from, next) {
await engineNetworkInterface.unsubscribeFromDeploymentsUpdates();
await engineNetworkInterface.stopMachinePolling();
next();
},
};
</script>