Issue #165: Done.

This commit is contained in:
chiayin
2023-10-11 18:50:46 +08:00
parent 6e0d5b15fe
commit 1cfbddf510
6 changed files with 137 additions and 50 deletions

View File

@@ -102,6 +102,9 @@ export default {
await this.allMapDataStore.addTempFilterId();
await this.allMapDataStore.getAllMapData();
await this.allMapDataStore.getAllTrace(); // SidebarTrace 要連動
if(this.temporaryData[0]?.type) {
this.allMapDataStore.traceId = await this.allMapDataStore.traces[0]?.id;
}
await this.$emit('submit-all');
this.isLoading = false;
this.$toast.success('Filter(s) applied.');

View File

@@ -50,8 +50,8 @@
<div id="cyTrace" ref="cyTrace" class="h-full min-w-full relative"></div>
</div>
</div>
<div class="overflow-y-auto overflow-x-auto scrollbar h-[calc(100%_-_264px)]">
<DataTable :value="cases" showGridlines tableClass="text-sm" breakpoint="0">
<div class="overflow-y-auto overflow-x-auto scrollbar h-[calc(100%_-_264px)] infiniteTable" @scroll="handleScroll">
<DataTable :value="infiniteData" showGridlines tableClass="text-sm" breakpoint="0">
<Column field="id" header="Case ID" ></Column>
<Column field="started_at" header="Start time" ></Column>
<Column field="completed_at" header="End time" ></Column>
@@ -72,10 +72,10 @@ export default {
setup() {
const allMapDataStore = AllMapDataStore();
const loadingStore = LoadingStore();
const { traces, traceTaskSeq, cases } = storeToRefs(allMapDataStore);
const { infinit404, infiniteStart, traces, traceTaskSeq, cases } = storeToRefs(allMapDataStore);
const { isLoading } = storeToRefs(loadingStore);
return {allMapDataStore, traces, traceTaskSeq, cases, isLoading}
return {allMapDataStore, infinit404, infiniteStart, traces, traceTaskSeq, cases, isLoading}
},
data() {
return {
@@ -84,6 +84,8 @@ export default {
edges:[],
},
showTraceId: null,
infinitMaxItems: false,
infiniteData: [],
chartOptions: null,
selectArea: [0, 1]
}
@@ -136,7 +138,14 @@ export default {
selectArea: function(newValue) {
let roundValue = Math.round(newValue[1].toFixed());
if(newValue[1] !== roundValue) this.selectArea[1] = roundValue;
}
},
infinite404: function(newValue) {
if(newValue === 404) this.infinitMaxItems = true;
},
showTraceId: function(newValue, oldValue) {
let isScrollTop = document.querySelector('.infiniteTable');
if(isScrollTop && typeof isScrollTop.scrollTop !== 'undefined') if(newValue !== oldValue) isScrollTop.scrollTop = 0;
},
},
methods: {
/**
@@ -210,9 +219,12 @@ export default {
*/
async switchCaseData(id, count) {
if(count >= 1000) this.isLoading = true;
this.infinit404 = null;
this.infinitMaxItems = false;
this.showTraceId = id;
this.infiniteStart = 0;
this.allMapDataStore.traceId = id;
await this.allMapDataStore.getTraceDetail();
this.infiniteData = await this.allMapDataStore.getTraceDetail();
this.createCy();
this.isLoading = false;
},
@@ -265,6 +277,30 @@ export default {
this.setEdgesData();
cytoscapeMapTrace(this.processMap.nodes, this.processMap.edges, graphId);
},
/**
* 無限滾動: 監聽 scroll 有沒有滾到底部
* @param {element} event
*/
handleScroll(event) {
if(this.infinitMaxItems || this.cases.length < 20) return;
const container = event.target;
const overScrollHeight = container.scrollTop + container.clientHeight >= container.scrollHeight;
if(overScrollHeight) this.fetchData();
},
/**
* 無限滾動: 滾到底後,要載入數據
*/
async fetchData() {
try {
this.infiniteStart += 20;
await this.allMapDataStore.getTraceDetail();
this.infiniteData = [...this.infiniteData, ...this.cases];
} catch(error) {
console.error('Failed to load data:', error);
}
}
},
mounted() {
this.setNodesData();

View File

@@ -1,5 +1,5 @@
<template>
<Sidebar :visible="sidebarFilter" :closeIcon="'pi pi-chevron-left'" :modal="false" position="left" :dismissable="true" :baseZIndex="15" class="!w-11/12 !bg-neutral-100" @hide="hide()">
<Sidebar :visible="sidebarFilter" :closeIcon="'pi pi-chevron-left'" :modal="false" position="left" :dismissable="true" :baseZIndex="15" class="!w-11/12 !bg-neutral-100">
<template #header>
<ul class="flex space-x-4">
<li class="h1 border-r-2 border-neutral-300 pr-4 cursor-pointer hover:text-neutral-900 hover:duration-700" @click="switchTab('filter')" :class="tab === 'filter'? 'text-neutral-900': 'text-neutral-500'" id="tabFilter">Filter</li>
@@ -498,10 +498,12 @@ export default {
}
break;
case 'Trace': // Filter Type 選 Trace 的行為
let lowerIndex = this.$refs.filterTraceView.selectArea[0];
let upperIndex = this.$refs.filterTraceView.selectArea[1]-1;
data = {
type: 'trace-freq',
lower: this.$refs.filterTraceView.selectArea[0]+1,
upper: this.$refs.filterTraceView.selectArea[1],
lower: this.allMapDataStore.traces[lowerIndex].id,
upper: this.allMapDataStore.traces[upperIndex].id,
is_exclude: isExclude,
};
break;
@@ -552,14 +554,6 @@ export default {
sumbitAll() {
this.$emit('submit-all');
},
/**
* hide map
*/
hide() {
// 因 trace api 連動,所以關閉側邊欄時讓數值歸 1
this.allMapDataStore.traceId = 1;
this.allMapDataStore.getTraceDetail();
}
},
}
</script>

View File

@@ -1,5 +1,5 @@
<template>
<Sidebar :visible="sidebarTraces" :closeIcon="'pi pi-chevron-left'" :modal="false" position="left" :dismissable="true" class="!w-11/12" @show="show()" @hide="hide()">
<Sidebar :visible="sidebarTraces" :closeIcon="'pi pi-chevron-left'" :modal="false" position="left" :dismissable="true" class="!w-11/12" @show="show()">
<template #header>
<p class="h1">Traces</p>
</template>
@@ -41,8 +41,8 @@
<div id="cyTrace" ref="cyTrace" class="h-full min-w-full relative"></div>
</div>
</div>
<div class="overflow-y-auto overflow-x-auto scrollbar h-[calc(100%_-_264px)]">
<DataTable :value="cases" showGridlines tableClass="text-sm" breakpoint="0">
<div class="overflow-y-auto overflow-x-auto scrollbar h-[calc(100%_-_264px)] infiniteTable" @scroll="handleScroll">
<DataTable :value="infiniteData" showGridlines tableClass="text-sm" breakpoint="0">
<Column field="id" header="Case ID" ></Column>
<Column field="started_at" header="Start time" ></Column>
<Column field="completed_at" header="End time" ></Column>
@@ -52,21 +52,17 @@
</div>
</Sidebar>
</template>
<script>
import cytoscapeMapTrace from '@/module/cytoscapeMapTrace.js';
import { storeToRefs } from 'pinia';
import AllMapDataStore from '@/stores/allMapData.js';
import cytoscapeMapTrace from '@/module/cytoscapeMapTrace.js';
export default {
props: {
sidebarTraces: Boolean,
traces: Array,
traceTaskSeq: Array,
cases: Array,
},
props: ['sidebarTraces'],
setup() {
const allMapDataStore = AllMapDataStore();
return {allMapDataStore}
const { infinit404, infiniteStart, traceId, traces, traceTaskSeq, cases, infiniteFirstCases } = storeToRefs(allMapDataStore);
return {allMapDataStore, infinit404, infiniteStart, traceId, traces, traceTaskSeq, cases, infiniteFirstCases}
},
data() {
return {
@@ -74,7 +70,9 @@ export default {
nodes:[],
edges:[],
},
showTraceId: 1,
showTraceId: null,
infinitMaxItems: false,
infiniteData: [],
}
},
computed: {
@@ -93,7 +91,25 @@ export default {
ratio: this.getPercentLabel(trace.count / sum),
};
}).sort((x, y) => x.id - y.id);
}
},
watch: {
infinite404: function(newValue) {
if(newValue === 404) this.infinitMaxItems = true;
},
traceId: {
handler(newValue) {
this.showTraceId = newValue;
},
immediate: true
},
showTraceId: function(newValue, oldValue) {
let isScrollTop = document.querySelector('.infiniteTable');
if(isScrollTop && typeof isScrollTop.scrollTop !== 'undefined') if(newValue !== oldValue) isScrollTop.scrollTop = 0;
},
infiniteFirstCases: function(newValue){
if(this.infiniteFirstCases) this.infiniteData = JSON.parse(JSON.stringify(newValue));
}
},
methods: {
/**
@@ -117,7 +133,11 @@ export default {
* @param {number} id
*/
async switchCaseData(id, count) {
if(count >= 1000) this.isLoading = true;
this.infinit404 = null;
this.infinitMaxItems = false;
this.showTraceId = id;
this.infiniteStart = 0;
this.$emit('switch-Trace-Id', {id: this.showTraceId, count: count});
},
/**
@@ -172,20 +192,43 @@ export default {
/**
* create map
*/
show() {
async show() {
// 因 trace api 連動,所以關閉側邊欄時讓數值歸 traces 第一筆 id
this.showTraceId = await this.traces[0]?.id;
this.infiniteStart = await 0;
await this.allMapDataStore.getTraceDetail();
this.setNodesData();
this.setEdgesData();
this.createCy();
},
/**
* hide map
* 無限滾動: 監聽 scroll 有沒有滾到底部
* @param {element} event
*/
hide() {
// 因 trace api 連動,所以關閉側邊欄時讓數值歸 1
this.showTraceId = 1;
this.allMapDataStore.getTraceDetail();
handleScroll(event) {
if(this.infinitMaxItems || this.cases.length < 20) return;
const container = event.target;
const overScrollHeight = container.scrollTop + container.clientHeight >= container.scrollHeight;
if(overScrollHeight) this.fetchData();
},
/**
* 無限滾動: 滾到底後,要載入數據
*/
async fetchData() {
try {
this.infiniteStart += 20;
await this.allMapDataStore.getTraceDetail();
this.infiniteData = [...this.infiniteData, ...this.cases];
} catch(error) {
console.error('Failed to load data:', error);
}
}
},
async created() {
this.allMapDataStore.getTraceDetail();
}
}
</script>

View File

@@ -38,6 +38,8 @@ export default defineStore('allMapDataStore', {
allFunnelData: [],
isUpdataFilter: false, // 是否成功儲存 Filter 檔
selectTimeFrame: [], // user select time start and end
infinite404: null, // 無限滾動式是否到底要換頁
infiniteStart: 0, // 無限滾動 case 開始的數字
}),
getters: {
processMap: state => {
@@ -58,6 +60,9 @@ export default defineStore('allMapDataStore', {
cases: state => {
return state.allCase;
},
infiniteFirstCases: state => {
if(state.infiniteStart === 0) return state.allCase;
},
traceTaskSeq: state => {
return state.allTraceTaskSeq;
},
@@ -153,12 +158,14 @@ export default defineStore('allMapDataStore', {
let traceId = this.traceId;
let tempFilterId = this.tempFilterId;
let createfilterId = this.createFilterId;
let start = this.infiniteStart;
let api = '';
// 先判斷暫存 再判斷 filter 最後 log
if(tempFilterId != null) api = `/api/temp-filters/${tempFilterId}/traces/${traceId}`;
else if(createfilterId!= null) api = `/api/filters/${createfilterId}/traces/${traceId}`;
else api = `/api/logs/${logId}/traces/${traceId}`;
if(tempFilterId != null) api = `/api/temp-filters/${tempFilterId}/traces/${traceId}?start=${start}&page_size=20`;
else if(createfilterId!= null) api = `/api/filters/${createfilterId}/traces/${traceId}?start=${start}&page_size=20`;
else api = `/api/logs/${logId}/traces/${traceId}?start=${start}&page_size=20`;
try {
const response = await this.$axios.get(api);
@@ -169,9 +176,12 @@ export default defineStore('allMapDataStore', {
c.completed_at = moment(c.completed_at).format('YYYY-MM-DD HH:MM');
return this.allCase;
});
return this.allCase;
// if(this.httpStatus < 300) loading.isLoading = false;
} catch(error) {
if(error.response.status === 404) this.infinite404 = 404;
else {
this.httpStatus = error.request.status;
await delay();
loading.isLoading = true;
@@ -179,6 +189,7 @@ export default defineStore('allMapDataStore', {
loading.isLoading = false;
await delay(500);
$toast.default('Failed to load the Trace Detail.',{position: 'bottom'});
}
};
},
/**

View File

@@ -47,7 +47,7 @@
<!-- Sidebar Model -->
<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>
<SidebarTraces v-model:visible="sidebarTraces" :traces="traces" :cases="cases" :traceTaskSeq="traceTaskSeq" @switch-Trace-Id="switchTraceId" ref="tracesView"></SidebarTraces>
<SidebarTraces v-model:visible="sidebarTraces" @switch-Trace-Id="switchTraceId" ref="tracesView"></SidebarTraces>
<SidebarFilter v-model:visible="sidebarFilter" :filterTasks="filterTasks" :filterStartToEnd="filterStartToEnd" :filterEndToStart="filterEndToStart" :filterTimeframe="filterTimeframe" :filterTrace="filterTrace"
@submit-all="createCy(mapType)" @switch-Trace-Id="switchTraceId" ref="sidevarFilterRef"></SidebarFilter>
@@ -68,9 +68,9 @@ export default {
const loadingStore = LoadingStore();
const allMapDataStore = AllMapDataStore();
const { isLoading } = storeToRefs(loadingStore);
const { processMap, bpmn, stats, insights, traceId, traces, traceTaskSeq, cases, filterTasks, filterStartToEnd, filterEndToStart, filterTimeframe, filterTrace, temporaryData, isRuleData, ruleData, logId, createFilterId } = storeToRefs(allMapDataStore);
const { processMap, bpmn, stats, insights, traceId, traces, filterTasks, filterStartToEnd, filterEndToStart, filterTimeframe, filterTrace, temporaryData, isRuleData, ruleData, logId, createFilterId } = storeToRefs(allMapDataStore);
return { isLoading, processMap, bpmn, stats, insights, traceId, traces, traceTaskSeq, cases, filterTasks, filterStartToEnd, filterEndToStart, filterTimeframe, filterTrace, logId, createFilterId, temporaryData, isRuleData, ruleData, allMapDataStore}
return { isLoading, processMap, bpmn, stats, insights, traceId, traces, filterTasks, filterStartToEnd, filterEndToStart, filterTimeframe, filterTrace, logId, createFilterId, temporaryData, isRuleData, ruleData, allMapDataStore}
},
components: {
SidebarView,
@@ -102,6 +102,7 @@ export default {
sidebarState: false, // SideBar: Summary & Insight
sidebarTraces: false, // SideBar: Traces
sidebarFilter: false, // SideBar: Filter
infiniteFirstCases: null,
}
},
computed:{
@@ -311,7 +312,6 @@ export default {
await this.allMapDataStore.getAllMapData();
await this.allMapDataStore.getAllTrace();
this.traceId = await this.traces[0]?.id; // log、filter 檔切換過程中, trace id 不同,將初始 trace id 設定為該檔案的 trace 幣一筆資料的 id。
await this.allMapDataStore.getTraceDetail();
this.createCy(this.mapType);
await this.allMapDataStore.getFilterParams();