Discover: sideBar trace done.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -37,3 +37,6 @@ vscode
|
|||||||
.env.demo
|
.env.demo
|
||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
|
|
||||||
|
.scannerwork
|
||||||
|
sonar-project.properties
|
||||||
|
|||||||
63
package-lock.json
generated
63
package-lock.json
generated
@@ -12,6 +12,7 @@
|
|||||||
"axios": "^1.2.2",
|
"axios": "^1.2.2",
|
||||||
"cytoscape": "^3.23.0",
|
"cytoscape": "^3.23.0",
|
||||||
"cytoscape-dagre": "^2.5.0",
|
"cytoscape-dagre": "^2.5.0",
|
||||||
|
"cytoscape-popper": "^2.0.0",
|
||||||
"javascript-color-gradient": "^2.4.4",
|
"javascript-color-gradient": "^2.4.4",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
"primeicons": "^6.0.1",
|
"primeicons": "^6.0.1",
|
||||||
"primevue": "^3.23.0",
|
"primevue": "^3.23.0",
|
||||||
"tailwindcss": "^3.2.4",
|
"tailwindcss": "^3.2.4",
|
||||||
|
"tippy.js": "^6.3.7",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.2.45",
|
||||||
"vue-axios": "^3.5.2",
|
"vue-axios": "^3.5.2",
|
||||||
"vue-router": "^4.1.6",
|
"vue-router": "^4.1.6",
|
||||||
@@ -631,6 +633,15 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@popperjs/core": {
|
||||||
|
"version": "2.11.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz",
|
||||||
|
"integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/popperjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rushstack/eslint-patch": {
|
"node_modules/@rushstack/eslint-patch": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
|
||||||
@@ -2070,6 +2081,17 @@
|
|||||||
"cytoscape": "^3.2.22"
|
"cytoscape": "^3.2.22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cytoscape-popper": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cytoscape-popper/-/cytoscape-popper-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-b7WSOn8qXHWtdIXFNmrgc8qkaOs16tMY0EwtRXlxzvn8X+al6TAFrUwZoYATkYSlotfd/36ZMoeKMEoUck6feA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@popperjs/core": "^2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"cytoscape": "^3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dagre": {
|
"node_modules/dagre": {
|
||||||
"version": "0.8.5",
|
"version": "0.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
|
||||||
@@ -5603,6 +5625,14 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tippy.js": {
|
||||||
|
"version": "6.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
|
||||||
|
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@popperjs/core": "^2.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tmp": {
|
"node_modules/tmp": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
|
||||||
@@ -6045,9 +6075,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webpack": {
|
"node_modules/webpack": {
|
||||||
"version": "5.75.0",
|
"version": "5.76.3",
|
||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.3.tgz",
|
||||||
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
|
"integrity": "sha512-18Qv7uGPU8b2vqGeEEObnfICyw2g39CHlDEK4I7NK13LOur1d0HGmGNKGT58Eluwddpn3oEejwvBPoP4M7/KSA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -6634,6 +6664,11 @@
|
|||||||
"fastq": "^1.6.0"
|
"fastq": "^1.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@popperjs/core": {
|
||||||
|
"version": "2.11.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz",
|
||||||
|
"integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw=="
|
||||||
|
},
|
||||||
"@rushstack/eslint-patch": {
|
"@rushstack/eslint-patch": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
|
||||||
@@ -7779,6 +7814,14 @@
|
|||||||
"dagre": "^0.8.5"
|
"dagre": "^0.8.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cytoscape-popper": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cytoscape-popper/-/cytoscape-popper-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-b7WSOn8qXHWtdIXFNmrgc8qkaOs16tMY0EwtRXlxzvn8X+al6TAFrUwZoYATkYSlotfd/36ZMoeKMEoUck6feA==",
|
||||||
|
"requires": {
|
||||||
|
"@popperjs/core": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dagre": {
|
"dagre": {
|
||||||
"version": "0.8.5",
|
"version": "0.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
|
||||||
@@ -10340,6 +10383,14 @@
|
|||||||
"integrity": "sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==",
|
"integrity": "sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"tippy.js": {
|
||||||
|
"version": "6.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
|
||||||
|
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
|
||||||
|
"requires": {
|
||||||
|
"@popperjs/core": "^2.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tmp": {
|
"tmp": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
|
||||||
@@ -10622,9 +10673,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"webpack": {
|
"webpack": {
|
||||||
"version": "5.75.0",
|
"version": "5.76.3",
|
||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.3.tgz",
|
||||||
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
|
"integrity": "sha512-18Qv7uGPU8b2vqGeEEObnfICyw2g39CHlDEK4I7NK13LOur1d0HGmGNKGT58Eluwddpn3oEejwvBPoP4M7/KSA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"axios": "^1.2.2",
|
"axios": "^1.2.2",
|
||||||
"cytoscape": "^3.23.0",
|
"cytoscape": "^3.23.0",
|
||||||
"cytoscape-dagre": "^2.5.0",
|
"cytoscape-dagre": "^2.5.0",
|
||||||
|
"cytoscape-popper": "^2.0.0",
|
||||||
"javascript-color-gradient": "^2.4.4",
|
"javascript-color-gradient": "^2.4.4",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
"primeicons": "^6.0.1",
|
"primeicons": "^6.0.1",
|
||||||
"primevue": "^3.23.0",
|
"primevue": "^3.23.0",
|
||||||
"tailwindcss": "^3.2.4",
|
"tailwindcss": "^3.2.4",
|
||||||
|
"tippy.js": "^6.3.7",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.2.45",
|
||||||
"vue-axios": "^3.5.2",
|
"vue-axios": "^3.5.2",
|
||||||
"vue-router": "^4.1.6",
|
"vue-router": "^4.1.6",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<div class="w-full mr-8">
|
<div class="w-full mr-8">
|
||||||
<span class="block text-sm">{{ numberLabel(stats.cases.count) }} / {{ numberLabel(stats.cases.total) }}</span>
|
<span class="block text-sm">{{ numberLabel(stats.cases.count) }} / {{ numberLabel(stats.cases.total) }}</span>
|
||||||
<ProgressBar :value="valueCases" :showValue="false" class="!h-2 !rounded-full my-2"></ProgressBar>
|
<ProgressBar :value="valueCases" :showValue="false" class="!h-2 !rounded-full my-2 !bg-neutral-300"></ProgressBar>
|
||||||
</div>
|
</div>
|
||||||
<span class="block text-primary text-2xl font-medium">{{ getPercentLabel(stats.cases.ratio) }}</span>
|
<span class="block text-primary text-2xl font-medium">{{ getPercentLabel(stats.cases.ratio) }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<div class="w-full mr-8">
|
<div class="w-full mr-8">
|
||||||
<span class="block text-sm">{{ numberLabel(stats.traces.count) }} / {{ numberLabel(stats.traces.total) }}</span>
|
<span class="block text-sm">{{ numberLabel(stats.traces.count) }} / {{ numberLabel(stats.traces.total) }}</span>
|
||||||
<ProgressBar :value="valueTraces" :showValue="false" class="!h-2 !rounded-full my-2"></ProgressBar>
|
<ProgressBar :value="valueTraces" :showValue="false" class="!h-2 !rounded-full my-2 !bg-neutral-300"></ProgressBar>
|
||||||
</div>
|
</div>
|
||||||
<span class="block text-primary text-2xl font-medium">{{ getPercentLabel(stats.traces.ratio) }}</span>
|
<span class="block text-primary text-2xl font-medium">{{ getPercentLabel(stats.traces.ratio) }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<div class="w-full mr-8">
|
<div class="w-full mr-8">
|
||||||
<span class="block text-sm">{{ numberLabel(stats.task_instances.count) }} / {{ numberLabel(stats.task_instances.total) }}</span>
|
<span class="block text-sm">{{ numberLabel(stats.task_instances.count) }} / {{ numberLabel(stats.task_instances.total) }}</span>
|
||||||
<ProgressBar :value="valueTaskInstances" :showValue="false" class="!h-2 !rounded-full my-2"></ProgressBar>
|
<ProgressBar :value="valueTaskInstances" :showValue="false" class="!h-2 !rounded-full my-2 !bg-neutral-300"></ProgressBar>
|
||||||
</div>
|
</div>
|
||||||
<span class="block text-primary text-2xl font-medium">{{ getPercentLabel(stats.task_instances.ratio) }}</span>
|
<span class="block text-primary text-2xl font-medium">{{ getPercentLabel(stats.task_instances.ratio) }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<div class="w-full mr-8">
|
<div class="w-full mr-8">
|
||||||
<span class="block text-sm">{{ numberLabel(stats.tasks.count) }} / {{ numberLabel(stats.tasks.total) }}</span>
|
<span class="block text-sm">{{ numberLabel(stats.tasks.count) }} / {{ numberLabel(stats.tasks.total) }}</span>
|
||||||
<ProgressBar :value="valueTasks" :showValue="false" class="!h-2 !rounded-full my-2"></ProgressBar>
|
<ProgressBar :value="valueTasks" :showValue="false" class="!h-2 !rounded-full my-2 !bg-neutral-300"></ProgressBar>
|
||||||
</div>
|
</div>
|
||||||
<span class="block text-primary text-2xl font-medium">{{ getPercentLabel(stats.tasks.ratio) }}</span>
|
<span class="block text-primary text-2xl font-medium">{{ getPercentLabel(stats.tasks.ratio) }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -116,9 +116,8 @@
|
|||||||
<TabPanel header="Self-loop">
|
<TabPanel header="Self-loop">
|
||||||
<p v-if="insights.self_loops.length === 0">No data</p>
|
<p v-if="insights.self_loops.length === 0">No data</p>
|
||||||
<ul v-else class="list-disc ml-6">
|
<ul v-else class="list-disc ml-6">
|
||||||
<li>
|
<li v-for="(value, key) in insights.self_loops" :key="key">
|
||||||
<span v-for="(value, key) in insights.self_loops" :key="key">{{ value }}<span v-if="key !== insights.self_loops.length -1"> <span class="material-symbols-outlined text-lg align-sub">arrow_forward</span> </span>
|
<span>{{ value }}</span>
|
||||||
</span>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@@ -126,7 +125,7 @@
|
|||||||
<p v-if="insights.short_loops.length === 0">No data</p>
|
<p v-if="insights.short_loops.length === 0">No data</p>
|
||||||
<ul v-else class="list-disc ml-6">
|
<ul v-else class="list-disc ml-6">
|
||||||
<li class="break-words" v-for="(item, key) in insights.short_loops" :key="key">
|
<li class="break-words" v-for="(item, key) in insights.short_loops" :key="key">
|
||||||
<span v-for="(value, index) in item" :key="index">{{ value }}<span v-if="index !== item.length - 1"> <span class="material-symbols-outlined text-lg align-sub">arrow_forward</span> </span>
|
<span v-for="(value, index) in item" :key="index">{{ value }}<span v-if="index !== item.length - 1"> <span class="material-symbols-outlined text-lg align-sub">sync_alt</span> </span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -194,36 +193,37 @@ export default {
|
|||||||
valueTaskInstances: 0,
|
valueTaskInstances: 0,
|
||||||
valueTasks: 0,
|
valueTasks: 0,
|
||||||
active1: 0,
|
active1: 0,
|
||||||
nnnstats:this.stats
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/**
|
||||||
* switch Summary or Insight
|
* @param {string} switch Summary or Insight
|
||||||
*/
|
*/
|
||||||
switchTab(tab) {
|
switchTab(tab) {
|
||||||
this.tab = tab;
|
this.tab = tab;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* use timeLabel.js
|
* @param {number} time use timeLabel.js
|
||||||
*/
|
*/
|
||||||
timeLabel(time){
|
timeLabel(time){
|
||||||
return getTimeLabel(time);
|
return getTimeLabel(time);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* use moment
|
* @param {number} time use moment
|
||||||
*/
|
*/
|
||||||
moment(time){
|
moment(time){
|
||||||
return getMoment(time).format('YYYY-MM-DD HH:mm');
|
return getMoment(time).format('YYYY-MM-DD HH:mm');
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* use numberLabel.js
|
* @param {number} num use numberLabel.js
|
||||||
*/
|
*/
|
||||||
numberLabel(num){
|
numberLabel(num){
|
||||||
return getNumberLabel(num);
|
return getNumberLabel(num);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Number to percentage
|
* Number to percentage
|
||||||
|
* @param {number} val
|
||||||
|
* @returns {string} 轉換完成的百分比字串
|
||||||
*/
|
*/
|
||||||
getPercentLabel(val){
|
getPercentLabel(val){
|
||||||
if(val * 100 === 100) return `${val * 100}%`;
|
if(val * 100 === 100) return `${val * 100}%`;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<Sidebar :visible="sidebarTraces" :closeIcon="'pi pi-chevron-left'" :modal="false" position="left" :dismissable="true" class="!w-11/12">
|
<Sidebar :visible="sidebarTraces" :closeIcon="'pi pi-chevron-left'" :modal="false" position="left" :dismissable="true" class="!w-11/12" @show="show()">
|
||||||
<template #header>
|
<template #header>
|
||||||
<p class="h1">Traces</p>
|
<p class="h1">Traces</p>
|
||||||
</template>
|
</template>
|
||||||
<div class="pt-4 h-full flex items-center justify-start">
|
<div class="pt-4 h-full flex items-center justify-start">
|
||||||
<!-- Trace List -->
|
<!-- Trace List -->
|
||||||
<section class="w-80 h-full pr-4 border-r border-neutral-300">
|
<section class="w-80 h-full pr-4 border-r border-neutral-300">
|
||||||
<p class="h2 px-2 mb-2">Trace List (25)</p>
|
<p class="h2 px-2 mb-2">Trace List ({{ traceTotal }})</p>
|
||||||
<p class="text-primary h2 px-2 mb-2">
|
<p class="text-primary h2 px-2 mb-2">
|
||||||
<span class="material-symbols-outlined text-base align-[-10%] mr-2">info</span>Click trace number to see more.
|
<span class="material-symbols-outlined text-base align-[-10%] mr-2">info</span>Click trace number to see more.
|
||||||
</p>
|
</p>
|
||||||
@@ -19,13 +19,15 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr v-for="(trace, key) in traceList" :key="key" class=" cursor-pointer hover:text-primary" @dblclick="switchCaseData(trace.id)">
|
||||||
<td class="text-xs p-2">#365</td>
|
<td class="text-xs p-2">#{{ trace.id }}</td>
|
||||||
<td class="text-xs p-2 w-24">
|
<td class="text-xs p-2 w-24">
|
||||||
<ProgressBar :value="80" :showValue="false" class="!h-4"></ProgressBar>
|
<div class="h-4 w-full bg-neutral-300 rounded-sm overflow-hidden">
|
||||||
|
<div class="h-full bg-primary" :style="progressWidth(trace.value)"></div>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-xs py-2">1,234,567,890</td>
|
<td class="text-xs py-2 text-right">{{ trace.count }}</td>
|
||||||
<td class="text-xs p-2">100%</td>
|
<td class="text-xs p-2">{{ trace.ratio }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -33,16 +35,17 @@
|
|||||||
</section>
|
</section>
|
||||||
<!-- Trace item Table -->
|
<!-- Trace item Table -->
|
||||||
<section class="pl-4 h-full w-[calc(100%_-_320px)]">
|
<section class="pl-4 h-full w-[calc(100%_-_320px)]">
|
||||||
<p class="h2 mb-2">Trace #501</p>
|
<p class="h2 mb-2">Trace #{{ showTraceId }}</p>
|
||||||
<div class="h-52 px-2 mb-2 border border-neutral-300 rounded">
|
<div class="h-52 w-full px-2 mb-2 border border-neutral-300 rounded">
|
||||||
<div class="h-full scrollbar overflow-x-auto">
|
<div class="h-full w-full scrollbar overflow-x-auto">
|
||||||
|
<div id="cyTrace" ref="cyTrace" class="h-full min-w-full relative"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-y-auto overflow-x-auto scrollbar h-[calc(100%_-_264px)]">
|
<div class="overflow-y-auto overflow-x-auto scrollbar h-[calc(100%_-_264px)]">
|
||||||
<DataTable :value="products" showGridlines>
|
<DataTable :value="cases" showGridlines>
|
||||||
<Column field="code" header="Code" sortable></Column>
|
<Column field="id" header="Case ID" sortable></Column>
|
||||||
<Column field="name" header="Name" sortable></Column>
|
<Column field="started_at" header="Start time" sortable></Column>
|
||||||
<Column field="category" header="Category" sortable></Column>
|
<Column field="completed_at" header="End time" sortable></Column>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -51,211 +54,142 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import cytoscapeMapTrace from '@/module/cytoscapeMapTrace.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
sidebarTraces: {
|
sidebarTraces: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
require: true,
|
require: true,
|
||||||
},
|
},
|
||||||
|
traces: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
traceTaskSeq: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
cases: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
products: [
|
processMap:{
|
||||||
{
|
nodes:[],
|
||||||
id: '1000',
|
edges:[],
|
||||||
code: 'f230fh0g3',
|
|
||||||
name: 'Bamboo Watch',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'bamboo-watch.jpg',
|
|
||||||
price: 65,
|
|
||||||
category: 'Accessories',
|
|
||||||
quantity: 24,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 5
|
|
||||||
},
|
},
|
||||||
{
|
showTraceId: 1,
|
||||||
id: '1001',
|
|
||||||
code: 'nvklal433',
|
|
||||||
name: 'Black Watch',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'black-watch.jpg',
|
|
||||||
price: 72,
|
|
||||||
category: 'Accessories',
|
|
||||||
quantity: 61,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1002',
|
|
||||||
code: 'zz21cz3c1',
|
|
||||||
name: 'Blue Band',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'blue-band.jpg',
|
|
||||||
price: 79,
|
|
||||||
category: 'Fitness',
|
|
||||||
quantity: 2,
|
|
||||||
inventoryStatus: 'LOWSTOCK',
|
|
||||||
rating: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1003',
|
|
||||||
code: '244wgerg2',
|
|
||||||
name: 'Blue T-Shirt',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'blue-t-shirt.jpg',
|
|
||||||
price: 29,
|
|
||||||
category: 'Clothing',
|
|
||||||
quantity: 25,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1000',
|
|
||||||
code: 'f230fh0g3',
|
|
||||||
name: 'Bamboo Watch',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'bamboo-watch.jpg',
|
|
||||||
price: 65,
|
|
||||||
category: 'Accessories',
|
|
||||||
quantity: 24,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1001',
|
|
||||||
code: 'nvklal433',
|
|
||||||
name: 'Black Watch',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'black-watch.jpg',
|
|
||||||
price: 72,
|
|
||||||
category: 'Accessories',
|
|
||||||
quantity: 61,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1002',
|
|
||||||
code: 'zz21cz3c1',
|
|
||||||
name: 'Blue Band',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'blue-band.jpg',
|
|
||||||
price: 79,
|
|
||||||
category: 'Fitness',
|
|
||||||
quantity: 2,
|
|
||||||
inventoryStatus: 'LOWSTOCK',
|
|
||||||
rating: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1003',
|
|
||||||
code: '244wgerg2',
|
|
||||||
name: 'Blue T-Shirt',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'blue-t-shirt.jpg',
|
|
||||||
price: 29,
|
|
||||||
category: 'Clothing',
|
|
||||||
quantity: 25,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1000',
|
|
||||||
code: 'f230fh0g3',
|
|
||||||
name: 'Bamboo Watch',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'bamboo-watch.jpg',
|
|
||||||
price: 65,
|
|
||||||
category: 'Accessories',
|
|
||||||
quantity: 24,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1001',
|
|
||||||
code: 'nvklal433',
|
|
||||||
name: 'Black Watch',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'black-watch.jpg',
|
|
||||||
price: 72,
|
|
||||||
category: 'Accessories',
|
|
||||||
quantity: 61,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1002',
|
|
||||||
code: 'zz21cz3c1',
|
|
||||||
name: 'Blue Band',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'blue-band.jpg',
|
|
||||||
price: 79,
|
|
||||||
category: 'Fitness',
|
|
||||||
quantity: 2,
|
|
||||||
inventoryStatus: 'LOWSTOCK',
|
|
||||||
rating: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1003',
|
|
||||||
code: '244wgerg2',
|
|
||||||
name: 'Blue T-Shirt',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'blue-t-shirt.jpg',
|
|
||||||
price: 29,
|
|
||||||
category: 'Clothing',
|
|
||||||
quantity: 25,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1000',
|
|
||||||
code: 'f230fh0g3',
|
|
||||||
name: 'Bamboo Watch',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'bamboo-watch.jpg',
|
|
||||||
price: 65,
|
|
||||||
category: 'Accessories',
|
|
||||||
quantity: 24,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1001',
|
|
||||||
code: 'nvklal433',
|
|
||||||
name: 'Black Watch',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'black-watch.jpg',
|
|
||||||
price: 72,
|
|
||||||
category: 'Accessories',
|
|
||||||
quantity: 61,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1002',
|
|
||||||
code: 'zz21cz3c1',
|
|
||||||
name: 'Blue Band',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'blue-band.jpg',
|
|
||||||
price: 79,
|
|
||||||
category: 'Fitness',
|
|
||||||
quantity: 2,
|
|
||||||
inventoryStatus: 'LOWSTOCK',
|
|
||||||
rating: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1003',
|
|
||||||
code: '244wgerg2',
|
|
||||||
name: 'Blue T-Shirt',
|
|
||||||
description: 'Product Description',
|
|
||||||
image: 'blue-t-shirt.jpg',
|
|
||||||
price: 29,
|
|
||||||
category: 'Clothing',
|
|
||||||
quantity: 25,
|
|
||||||
inventoryStatus: 'INSTOCK',
|
|
||||||
rating: 5
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
traceTotal: function() {
|
||||||
|
return this.traces.length;
|
||||||
|
},
|
||||||
|
traceList: function() {
|
||||||
|
let list = [];
|
||||||
|
|
||||||
|
this.traces.forEach((trace, index) => {
|
||||||
|
let data = {
|
||||||
|
id: trace.id,
|
||||||
|
value: Number((trace.ratio * 100).toFixed(1)),
|
||||||
|
count: trace.count,
|
||||||
|
ratio: this.getPercentLabel(trace.ratio),
|
||||||
|
};
|
||||||
|
|
||||||
|
list.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* Number to percentage
|
||||||
|
* @param {number} val
|
||||||
|
* @returns {string} 轉換完成的百分比字串
|
||||||
|
*/
|
||||||
|
getPercentLabel(val){
|
||||||
|
return (val * 100 === 100) ? `${val * 100}%` : `${(val * 100).toFixed(1)}%`;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* set progress bar width
|
||||||
|
* @param {number} value
|
||||||
|
* @returns {string} 樣式的寬度設定
|
||||||
|
*/
|
||||||
|
progressWidth(value){
|
||||||
|
return `width:${value}%;`
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* switch case data
|
||||||
|
* @param {number} id
|
||||||
|
*/
|
||||||
|
async switchCaseData(id) {
|
||||||
|
this.showTraceId = id;
|
||||||
|
this.$emit('switch-Trace-Id', this.showTraceId);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 將 trace element nodes 資料彙整
|
||||||
|
*/
|
||||||
|
setNodesData(){
|
||||||
|
// 避免每次渲染都重複累加
|
||||||
|
this.processMap.nodes = [];
|
||||||
|
// 將 api call 回來的資料帶進 node
|
||||||
|
this.traceTaskSeq.forEach((node, index) => {
|
||||||
|
this.processMap.nodes.push({
|
||||||
|
data: {
|
||||||
|
id: index,
|
||||||
|
label: node,
|
||||||
|
backgroundColor: '#CCE5FF',
|
||||||
|
bordercolor: '#003366',
|
||||||
|
shape: 'round-rectangle',
|
||||||
|
height: 80,
|
||||||
|
width: 100
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 將 trace edge line 資料彙整
|
||||||
|
*/
|
||||||
|
setEdgesData(){
|
||||||
|
this.processMap.edges = [];
|
||||||
|
this.traceTaskSeq.forEach((edge, index) => {
|
||||||
|
this.processMap.edges.push({
|
||||||
|
data: {
|
||||||
|
source: `${index}`,
|
||||||
|
target: `${index + 1}`,
|
||||||
|
lineWidth: 1,
|
||||||
|
style: 'solid'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// 關係線數量筆節點少一個
|
||||||
|
this.processMap.edges.pop();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* create trace cytoscape's map
|
||||||
|
*/
|
||||||
|
createCy(){
|
||||||
|
let graphId = this.$refs.cyTrace;
|
||||||
|
|
||||||
|
this.setNodesData();
|
||||||
|
this.setEdgesData();
|
||||||
|
cytoscapeMapTrace(this.processMap.nodes, this.processMap.edges, graphId);
|
||||||
|
},
|
||||||
|
show() {
|
||||||
|
this.setNodesData();
|
||||||
|
this.setEdgesData();
|
||||||
|
this.createCy();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created(){
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import mitt from 'mitt';
|
|||||||
import ToastPlugin from 'vue-toast-notification';
|
import ToastPlugin from 'vue-toast-notification';
|
||||||
import cytoscape from 'cytoscape';
|
import cytoscape from 'cytoscape';
|
||||||
import dagre from 'cytoscape-dagre';
|
import dagre from 'cytoscape-dagre';
|
||||||
|
import popper from 'cytoscape-popper';
|
||||||
|
|
||||||
// import CSS
|
// import CSS
|
||||||
import "./assets/main.css";
|
import "./assets/main.css";
|
||||||
@@ -50,6 +51,7 @@ app.config.globalProperties.$cytoscape = cytoscape;
|
|||||||
|
|
||||||
// Cytoscape.js's style
|
// Cytoscape.js's style
|
||||||
cytoscape.use( dagre );
|
cytoscape.use( dagre );
|
||||||
|
cytoscape.use( popper );
|
||||||
|
|
||||||
app.use(pinia);
|
app.use(pinia);
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import cytoscape from 'cytoscape';
|
import cytoscape from 'cytoscape';
|
||||||
import dagre from 'cytoscape-dagre';
|
import dagre from 'cytoscape-dagre';
|
||||||
|
// import tippy from 'tippy.js';
|
||||||
|
// import 'tippy.js/dist/tippy.css';
|
||||||
import Gradient from 'javascript-color-gradient'; // 多個色階產生器
|
import Gradient from 'javascript-color-gradient'; // 多個色階產生器
|
||||||
import TimeLabel from '@/module/timeLabel.js'; // 時間格式轉換器
|
import TimeLabel from '@/module/timeLabel.js'; // 時間格式轉換器
|
||||||
|
|
||||||
|
|||||||
105
src/module/cytoscapeMapTrace.js
Normal file
105
src/module/cytoscapeMapTrace.js
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import cytoscape from 'cytoscape';
|
||||||
|
import dagre from 'cytoscape-dagre';
|
||||||
|
import tippy from 'tippy.js';
|
||||||
|
import 'tippy.js/dist/tippy.css';
|
||||||
|
|
||||||
|
cytoscape.use( dagre );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* draw processmap for trace
|
||||||
|
* @param {array} nodes array of an object, it contains
|
||||||
|
* data:{
|
||||||
|
* backgroundColor: string
|
||||||
|
* bordercolor: string
|
||||||
|
* height: number
|
||||||
|
* id: number
|
||||||
|
* label: string
|
||||||
|
* shape: string
|
||||||
|
* width: number
|
||||||
|
* }
|
||||||
|
* @param {array} edges it's similar to nodes
|
||||||
|
* @param {string} graphId
|
||||||
|
*/
|
||||||
|
export default function cytoscapeMapTrace(nodes, edges, graphId) {
|
||||||
|
// create Cytoscape
|
||||||
|
let cy = cytoscape({
|
||||||
|
container: graphId,
|
||||||
|
elements: {
|
||||||
|
nodes: nodes, // 節點的資料
|
||||||
|
edges: edges, // 關係線的資料
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
name: 'dagre',
|
||||||
|
rankDir: 'LR' // 直向 TB | 橫向 LR, 'cytoscape-dagre' 套件裡的變數
|
||||||
|
},
|
||||||
|
style: [
|
||||||
|
// node 節點的樣式
|
||||||
|
{
|
||||||
|
selector: 'node',
|
||||||
|
style: {
|
||||||
|
'label':
|
||||||
|
function(node) { // 節點要顯示的文字
|
||||||
|
let text = '';
|
||||||
|
|
||||||
|
// node.data('label') 為原先陣列 node.data.label
|
||||||
|
text = node.data('label').length > 18 ? `${node.data('label').substr(0,15)}...` : `${node.data('label')}`;
|
||||||
|
|
||||||
|
return text
|
||||||
|
},
|
||||||
|
'text-opacity': 0.7,
|
||||||
|
'background-color': 'data(backgroundColor)',
|
||||||
|
'border-color': 'data(bordercolor)',
|
||||||
|
'border-width': '1',
|
||||||
|
'shape': 'data(shape)',
|
||||||
|
'text-wrap': 'wrap',
|
||||||
|
'text-max-width': 75,
|
||||||
|
'text-halign': 'center',
|
||||||
|
'text-valign': 'center',
|
||||||
|
'height': 'data(height)',
|
||||||
|
'width': 'data(width)',
|
||||||
|
'color': '#001933',
|
||||||
|
'font-size': 14,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// edge 關係線的樣式
|
||||||
|
{
|
||||||
|
selector: 'edge',
|
||||||
|
style: {
|
||||||
|
'curve-style': 'taxi', // unbundled-bezier | taxi
|
||||||
|
'target-arrow-shape': 'triangle', // 指向目標的箭頭形狀: 三角形
|
||||||
|
'color': 'gray', //#0066cc
|
||||||
|
'width': 'data(lineWidth)',
|
||||||
|
'line-style': 'data(style)',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 點擊 node 後改變的樣式
|
||||||
|
{
|
||||||
|
selector: 'node:selected',
|
||||||
|
style:{
|
||||||
|
'border-color': 'red',
|
||||||
|
'border-width': '3',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// creat tippy.js
|
||||||
|
let tip;
|
||||||
|
cy.on('mouseover', 'node', function(event) {
|
||||||
|
var node = event.target
|
||||||
|
let ref = node.popperRef()
|
||||||
|
let dummyDomEle = document.createElement('div');
|
||||||
|
let content = document.createElement('div');
|
||||||
|
content.innerHTML = node.data("label")
|
||||||
|
tip = new tippy(dummyDomEle, { // tippy props:
|
||||||
|
getReferenceClientRect: ref.getBoundingClientRect,
|
||||||
|
trigger: 'manual',
|
||||||
|
content:content
|
||||||
|
});
|
||||||
|
tip.show();
|
||||||
|
// if(node.data("label").length > 18) tip.show();
|
||||||
|
})
|
||||||
|
cy.on('mouseout', 'node', function(event) {
|
||||||
|
tip.hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -3,19 +3,24 @@ import loadingStore from './loading.js';
|
|||||||
import pinia from '@/stores/main.js'
|
import pinia from '@/stores/main.js'
|
||||||
import {useToast} from 'vue-toast-notification';
|
import {useToast} from 'vue-toast-notification';
|
||||||
import 'vue-toast-notification/dist/theme-sugar.css';
|
import 'vue-toast-notification/dist/theme-sugar.css';
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
const loading = loadingStore(pinia);
|
const loading = loadingStore(pinia);
|
||||||
const $toast = useToast();
|
const $toast = useToast();
|
||||||
// Delay loading and toast 待模組化
|
// Delay loading and toast 待模組化
|
||||||
let delay = s => new Promise((resolve, reject) => setTimeout(resolve, s));
|
let delay = (s = 0) => new Promise((resolve, reject) => setTimeout(resolve, s));
|
||||||
|
|
||||||
export default defineStore('allMapDataStore', {
|
export default defineStore('allMapDataStore', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
logId: null,
|
logId: null,
|
||||||
|
traceId: 1,
|
||||||
allProcessMap: {},
|
allProcessMap: {},
|
||||||
allBpmn: {},
|
allBpmn: {},
|
||||||
allStats: {},
|
allStats: {},
|
||||||
allInsights: {},
|
allInsights: {},
|
||||||
|
allTrace: [],
|
||||||
|
allCase: [],
|
||||||
|
allTraceTaskSeq: [],
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
@@ -30,6 +35,15 @@ export default defineStore('allMapDataStore', {
|
|||||||
},
|
},
|
||||||
insights: state => {
|
insights: state => {
|
||||||
return state.allInsights;
|
return state.allInsights;
|
||||||
|
},
|
||||||
|
traces: state => {
|
||||||
|
return state.allTrace;
|
||||||
|
},
|
||||||
|
cases: state => {
|
||||||
|
return state.allCase;
|
||||||
|
},
|
||||||
|
traceTaskSeq: state => {
|
||||||
|
return state.allTraceTaskSeq;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@@ -37,7 +51,7 @@ export default defineStore('allMapDataStore', {
|
|||||||
* fetch discover api, include '/process-map, /bpmn, /stats, /insights'.
|
* fetch discover api, include '/process-map, /bpmn, /stats, /insights'.
|
||||||
*/
|
*/
|
||||||
async getAllMapData() {
|
async getAllMapData() {
|
||||||
let logId = this.logId
|
let logId = this.logId;
|
||||||
const api = `/api/logs/${logId}/discover`;
|
const api = `/api/logs/${logId}/discover`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -57,9 +71,66 @@ export default defineStore('allMapDataStore', {
|
|||||||
loading.isLoading = false;
|
loading.isLoading = false;
|
||||||
return delay(500);
|
return delay(500);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
$toast.default('Failed to load the discover.');
|
$toast.default('Failed to load the Map.');
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* fetch trace api.
|
||||||
|
*/
|
||||||
|
async getAllTrace() {
|
||||||
|
let logId = this.logId;
|
||||||
|
const api = `/api/filters/params?log_id=${logId}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.$axios.get(api);
|
||||||
|
this.allTrace = response.data.traces;
|
||||||
|
|
||||||
|
if(this.httpStatus < 300) loading.isLoading = false;
|
||||||
|
} catch(error) {
|
||||||
|
this.httpStatus = error.request.status;
|
||||||
|
delay().then(() =>{
|
||||||
|
loading.isLoading = true;
|
||||||
|
return delay(1000);
|
||||||
|
}).then(()=>{
|
||||||
|
loading.isLoading = false;
|
||||||
|
return delay(500);
|
||||||
|
}).then(() => {
|
||||||
|
$toast.default('Failed to load the Trace.');
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* fetch trace detail api.
|
||||||
|
*/
|
||||||
|
async getTraceDetail() {
|
||||||
|
let logId = this.logId;
|
||||||
|
let traceId = this.traceId;
|
||||||
|
const api = `/api/logs/${logId}/traces/${traceId}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.$axios.get(api);
|
||||||
|
this.allTraceTaskSeq = response.data.task_seq;
|
||||||
|
this.allCase = response.data.cases;
|
||||||
|
this.allCase.map(c => {
|
||||||
|
c.started_at = moment(c.started_at).format('YYYY-MM-DD HH:MM');
|
||||||
|
c.completed_at = moment(c.completed_at).format('YYYY-MM-DD HH:MM');
|
||||||
|
return this.allCase;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(this.httpStatus < 300) loading.isLoading = false;
|
||||||
|
} catch(error) {
|
||||||
|
this.httpStatus = error.request.status;
|
||||||
|
delay().then(() =>{
|
||||||
|
loading.isLoading = true;
|
||||||
|
return delay(1000);
|
||||||
|
}).then(()=>{
|
||||||
|
loading.isLoading = false;
|
||||||
|
return delay(500);
|
||||||
|
}).then(() => {
|
||||||
|
$toast.default('Failed to load the Trace Detail.');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -118,5 +118,5 @@ export default defineStore('filesStore', {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
track_changes
|
track_changes
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="inline-flex items-center justify-center border border-neutral-500 rounded-full w-9 h-9 cursor-pointer bg-neutral-100 drop-shadow hover:border-primary">
|
<li class="inline-flex items-center justify-center border border-neutral-500 rounded-full w-9 h-9 cursor-pointer bg-neutral-100 drop-shadow hover:border-primary" @click="sidebarFilter = true" :class="{'border-primary': sidebarFilter}">
|
||||||
<span class="material-symbols-outlined text-2xl text-neutral-500 hover:text-primary p-1.5">
|
<span class="material-symbols-outlined text-2xl text-neutral-500 hover:text-primary p-1.5" :class="[sidebarFilter ? 'text-primary' : 'text-neutral-500']">
|
||||||
tornado
|
tornado
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<!-- Cytoscape Map -->
|
<!-- Cytoscape Map -->
|
||||||
<div class="min-w-full h-screen-main bg-neutral-100 -z-40">
|
<div class="min-w-full h-screen-main bg-neutral-100 -z-40">
|
||||||
<div id="cy" class="min-w-full h-screen-main "></div>
|
<div id="cy" class="min-w-full h-screen-main"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Sidebar: State -->
|
<!-- Sidebar: State -->
|
||||||
@@ -47,7 +47,15 @@
|
|||||||
<!-- Sidebar Model -->
|
<!-- Sidebar Model -->
|
||||||
<SidebarView v-model:visible="sidebarView" @switch-map-type="switchMapType" @switch-curve-styles="switchCurveStyles" @switch-rank="switchRank" @switch-data-layer-type="switchDataLayerType" ></SidebarView>
|
<SidebarView v-model:visible="sidebarView" @switch-map-type="switchMapType" @switch-curve-styles="switchCurveStyles" @switch-rank="switchRank" @switch-data-layer-type="switchDataLayerType" ></SidebarView>
|
||||||
<SidebarState v-model:visible="sidebarState" :insights="insights" :stats="stats"></SidebarState>
|
<SidebarState v-model:visible="sidebarState" :insights="insights" :stats="stats"></SidebarState>
|
||||||
<SidebarTraces v-model:visible="sidebarTraces"></SidebarTraces>
|
<SidebarTraces v-model:visible="sidebarTraces" :traces="traces" :cases="cases" :traceTaskSeq="traceTaskSeq" @switch-Trace-Id="switchTraceId" ref="tracesView"></SidebarTraces>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<Sidebar v-model:visible="sidebarFilter" :closeIcon="'pi pi-chevron-left'" :modal="false" position="left" :dismissable="true" class="!w-11/12">
|
||||||
|
<template #header>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</Sidebar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -64,21 +72,15 @@ export default {
|
|||||||
const loadingStore = LoadingStore();
|
const loadingStore = LoadingStore();
|
||||||
const allMapDataStore = AllMapDataStore();
|
const allMapDataStore = AllMapDataStore();
|
||||||
const { isLoading } = storeToRefs(loadingStore);
|
const { isLoading } = storeToRefs(loadingStore);
|
||||||
const { processMap, bpmn, stats, insights } = storeToRefs(allMapDataStore);
|
const { processMap, bpmn, stats, insights, traces, traceTaskSeq,cases } = storeToRefs(allMapDataStore);
|
||||||
|
|
||||||
return {
|
return { isLoading, processMap, bpmn, stats, insights, traces, traceTaskSeq,cases, allMapDataStore,}
|
||||||
isLoading,
|
|
||||||
processMap,
|
|
||||||
bpmn,
|
|
||||||
stats,
|
|
||||||
insights,
|
|
||||||
allMapDataStore,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
SidebarView,
|
SidebarView,
|
||||||
SidebarState,
|
SidebarState,
|
||||||
SidebarTraces,
|
SidebarTraces,
|
||||||
|
// SidebarFilter,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -99,9 +101,12 @@ export default {
|
|||||||
dataLayerType: 'freq', // freq | duration
|
dataLayerType: 'freq', // freq | duration
|
||||||
dataLayerOption: 'total',
|
dataLayerOption: 'total',
|
||||||
rank: 'LR', // 直向 TB | 橫向 LR
|
rank: 'LR', // 直向 TB | 橫向 LR
|
||||||
|
traceId: 1,
|
||||||
sidebarView: false, // SideBar: Visualization Setting
|
sidebarView: false, // SideBar: Visualization Setting
|
||||||
sidebarState: false, // SideBar: Summary & Insight
|
sidebarState: false, // SideBar: Summary & Insight
|
||||||
sidebarTraces: false, // SideBar: Traces
|
sidebarTraces: false, // SideBar: Traces
|
||||||
|
sidebarFilter: false, // SideBar: Filter
|
||||||
|
iii:null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed:{
|
computed:{
|
||||||
@@ -146,6 +151,15 @@ export default {
|
|||||||
this.dataLayerOption = option;
|
this.dataLayerOption = option;
|
||||||
this.createCy(this.mapType);
|
this.createCy(this.mapType);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* switch trace id and data
|
||||||
|
* @param {string} id
|
||||||
|
*/
|
||||||
|
async switchTraceId(id) {
|
||||||
|
this.allMapDataStore.traceId = id;
|
||||||
|
await this.allMapDataStore.getTraceDetail();
|
||||||
|
this.$refs.tracesView.createCy();
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 將 element nodes 資料彙整
|
* 將 element nodes 資料彙整
|
||||||
* @param {object} type processMapData | bpmnData
|
* @param {object} type processMapData | bpmnData
|
||||||
@@ -269,13 +283,6 @@ export default {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* get api data
|
|
||||||
*/
|
|
||||||
async executeApi() {
|
|
||||||
await this.allMapDataStore.getAllMapData();
|
|
||||||
this.createCy(this.mapType);
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* create cytoscape's map
|
* create cytoscape's map
|
||||||
* @param {string} type this.mapType processMap | bpmn
|
* @param {string} type this.mapType processMap | bpmn
|
||||||
@@ -291,12 +298,17 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
async created() {
|
||||||
this.allMapDataStore.logId = this.$route.params.logId;
|
this.allMapDataStore.logId = this.$route.params.logId;
|
||||||
|
|
||||||
|
await this.allMapDataStore.getAllMapData();
|
||||||
|
await this.allMapDataStore.getAllTrace();
|
||||||
|
await this.allMapDataStore.getTraceDetail();
|
||||||
|
|
||||||
|
this.createCy(this.mapType);
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.isLoading = false;
|
// this.isLoading = false;
|
||||||
this.executeApi();
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<Loading v-if="loadingStore.isLoading" />
|
<Loading v-if="loadingStore.isLoading" />
|
||||||
<router-view></router-view>
|
<router-view>
|
||||||
|
</router-view>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
build: {
|
build: {
|
||||||
commonjsOptions: {
|
commonjsOptions: {
|
||||||
transformMixedEsModules: true, // Enable @walletconnect/web3-provider which has some code in CommonJS
|
transformMixedEsModules: true, // Enable @walletconnect/web3-provider which has some code in CommonJS
|
||||||
|
// esmExternals: true, // If you set esmExternals to true, this plugins assumes that all external dependencies are ES modules
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
|
|||||||
Reference in New Issue
Block a user