mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-13 00:08:56 +00:00
feat: vis timeline
This commit is contained in:
parent
4ef6ac8db2
commit
51cf096d90
@ -20,11 +20,10 @@ import { useAppStoreWithOut } from "@/store/modules/app";
|
|||||||
import { useNetworkProfilingStore } from "@/store/modules/network-profiling";
|
import { useNetworkProfilingStore } from "@/store/modules/network-profiling";
|
||||||
import type { StrategyItem, CheckItems } from "@/types/continous-profiling";
|
import type { StrategyItem, CheckItems } from "@/types/continous-profiling";
|
||||||
import type { EBPFTaskList, EBPFProfilingSchedule, AnalyzationTrees } from "@/types/ebpf";
|
import type { EBPFTaskList, EBPFProfilingSchedule, AnalyzationTrees } from "@/types/ebpf";
|
||||||
import type { Instance, Process } from "@/types/selector";
|
import type { Instance } from "@/types/selector";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
import type { AxiosResponse } from "axios";
|
||||||
import { EBPFProfilingTriggerType } from "../data";
|
|
||||||
import dateFormatStep from "@/utils/dateFormat";
|
import dateFormatStep from "@/utils/dateFormat";
|
||||||
import getLocalTime from "@/utils/localtime";
|
import getLocalTime from "@/utils/localtime";
|
||||||
|
|
||||||
@ -146,43 +145,6 @@ export const continousProfilingStore = defineStore({
|
|||||||
}
|
}
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getContinousTaskList(params: {
|
|
||||||
serviceId: string;
|
|
||||||
serviceInstanceId: string;
|
|
||||||
targets: string[];
|
|
||||||
triggerType: string;
|
|
||||||
}) {
|
|
||||||
if (!params.serviceId) {
|
|
||||||
return new Promise((resolve) => resolve({}));
|
|
||||||
}
|
|
||||||
const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
|
|
||||||
|
|
||||||
this.errorTip = "";
|
|
||||||
if (res.data.errors) {
|
|
||||||
return res.data;
|
|
||||||
}
|
|
||||||
this.taskList = res.data.data.queryEBPFTasks || [];
|
|
||||||
if (!this.taskList.length) {
|
|
||||||
const networkProfilingStore = useNetworkProfilingStore();
|
|
||||||
networkProfilingStore.seNodes([]);
|
|
||||||
networkProfilingStore.setLinks([]);
|
|
||||||
this.eBPFSchedules = [];
|
|
||||||
this.analyzeTrees = [];
|
|
||||||
this.selectedTask = {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// this.selectedTask = this.taskList[0] || {};
|
|
||||||
// this.setselectedTask(this.selectedTask);
|
|
||||||
// await this.getGraphData();
|
|
||||||
return res.data;
|
|
||||||
},
|
|
||||||
async getGraphData() {
|
|
||||||
if (this.selectedStrategy.type === "NETWORK") {
|
|
||||||
await this.getTopology();
|
|
||||||
} else {
|
|
||||||
await this.preAnalyzeTask();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getTopology() {
|
async getTopology() {
|
||||||
const networkProfilingStore = useNetworkProfilingStore();
|
const networkProfilingStore = useNetworkProfilingStore();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
|
74
src/store/modules/task-timeline.ts
Normal file
74
src/store/modules/task-timeline.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { store } from "@/store";
|
||||||
|
import graphql from "@/graphql";
|
||||||
|
import type { AxiosResponse } from "axios";
|
||||||
|
import type { EBPFTaskList } from "@/types/ebpf";
|
||||||
|
import { useNetworkProfilingStore } from "@/store/modules/network-profiling";
|
||||||
|
// import { EBPFProfilingTriggerType } from "../data";
|
||||||
|
|
||||||
|
interface taskTimelineState {
|
||||||
|
loading: boolean;
|
||||||
|
taskList: EBPFTaskList[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const taskTimelineStore = defineStore({
|
||||||
|
id: "taskTimeline",
|
||||||
|
state: (): taskTimelineState => ({
|
||||||
|
loading: false,
|
||||||
|
taskList: [],
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
async getContinousTaskList(params: {
|
||||||
|
serviceId: string;
|
||||||
|
serviceInstanceId: string;
|
||||||
|
targets: string[];
|
||||||
|
triggerType: string;
|
||||||
|
}) {
|
||||||
|
if (!params.serviceId) {
|
||||||
|
return new Promise((resolve) => resolve({}));
|
||||||
|
}
|
||||||
|
this.loading = true;
|
||||||
|
const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
|
this.errorTip = "";
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.taskList = res.data.data.queryEBPFTasks || [];
|
||||||
|
if (!this.taskList.length) {
|
||||||
|
const networkProfilingStore = useNetworkProfilingStore();
|
||||||
|
networkProfilingStore.seNodes([]);
|
||||||
|
networkProfilingStore.setLinks([]);
|
||||||
|
this.eBPFSchedules = [];
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
this.selectedTask = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// this.selectedTask = this.taskList[0] || {};
|
||||||
|
// this.setselectedTask(this.selectedTask);
|
||||||
|
// await this.getGraphData();
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useTaskTimelineStore(): Recordable {
|
||||||
|
return taskTimelineStore(store);
|
||||||
|
}
|
92
src/views/dashboard/controls/TaskTimeline.vue
Normal file
92
src/views/dashboard/controls/TaskTimeline.vue
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div class="content-wrapper flex-v">
|
||||||
|
<div class="title">Task Timeline</div>
|
||||||
|
<el-popover placement="bottom" trigger="click" :width="100" v-if="dashboardStore.editMode">
|
||||||
|
<template #reference>
|
||||||
|
<span class="operation cp">
|
||||||
|
<Icon iconName="ellipsis_v" size="middle" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<div class="tools" @click="removeWidget">
|
||||||
|
<span>{{ t("delete") }}</span>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
<Content :config="props.data" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import Content from "../related/continuous-profiling/Content.vue";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => ({ graph: {} }),
|
||||||
|
},
|
||||||
|
activeIndex: { type: String, default: "" },
|
||||||
|
needQuery: { type: Boolean, default: true },
|
||||||
|
});
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
|
function removeWidget() {
|
||||||
|
dashboardStore.removeControls(props.data);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operation {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
padding: 5px 0;
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
</style>
|
@ -28,6 +28,7 @@ import NetworkProfiling from "./NetworkProfiling.vue";
|
|||||||
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
||||||
import TimeRange from "./TimeRange.vue";
|
import TimeRange from "./TimeRange.vue";
|
||||||
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
||||||
|
import TaskTimeline from "./TaskTimeline.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Tab,
|
Tab,
|
||||||
@ -44,4 +45,5 @@ export default {
|
|||||||
ContinuousProfiling,
|
ContinuousProfiling,
|
||||||
TimeRange,
|
TimeRange,
|
||||||
ThirdPartyApp,
|
ThirdPartyApp,
|
||||||
|
TaskTimeline,
|
||||||
};
|
};
|
||||||
|
@ -27,6 +27,7 @@ import NetworkProfiling from "./NetworkProfiling.vue";
|
|||||||
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
||||||
import TimeRange from "./TimeRange.vue";
|
import TimeRange from "./TimeRange.vue";
|
||||||
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
||||||
|
import TaskTimeline from "./TaskTimeline.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Widget,
|
Widget,
|
||||||
@ -42,4 +43,5 @@ export default {
|
|||||||
TimeRange,
|
TimeRange,
|
||||||
ThirdPartyApp,
|
ThirdPartyApp,
|
||||||
ContinuousProfiling,
|
ContinuousProfiling,
|
||||||
|
TaskTimeline,
|
||||||
};
|
};
|
||||||
|
@ -242,6 +242,12 @@ export const ProcessTools = [
|
|||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: "addText" },
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
||||||
];
|
];
|
||||||
|
export const ProcessRelationTools = [
|
||||||
|
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||||
|
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
||||||
|
{ name: "library_books", content: "Add Text", id: "addText" },
|
||||||
|
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
||||||
|
];
|
||||||
export const ServiceRelationTools = [
|
export const ServiceRelationTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
||||||
|
@ -145,6 +145,7 @@ limitations under the License. -->
|
|||||||
InstanceRelationTools,
|
InstanceRelationTools,
|
||||||
ServiceRelationTools,
|
ServiceRelationTools,
|
||||||
ProcessTools,
|
ProcessTools,
|
||||||
|
ProcessRelationTools,
|
||||||
} from "../data";
|
} from "../data";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
@ -702,6 +703,9 @@ limitations under the License. -->
|
|||||||
toolIcons.value = EndpointRelationTools;
|
toolIcons.value = EndpointRelationTools;
|
||||||
break;
|
break;
|
||||||
case EntityType[7].value:
|
case EntityType[7].value:
|
||||||
|
toolIcons.value = ProcessRelationTools;
|
||||||
|
break;
|
||||||
|
case EntityType[8].value:
|
||||||
toolIcons.value = ProcessTools;
|
toolIcons.value = ProcessTools;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
39
src/views/dashboard/related/task-timeline/Content.vue
Normal file
39
src/views/dashboard/related/task-timeline/Content.vue
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div class="flex-h content">
|
||||||
|
<Timeline />
|
||||||
|
<profiling-panel :config="config" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import Timeline from "./components/Timeline.vue";
|
||||||
|
import ProfilingPanel from "./components/ProfilingPanel.vue";
|
||||||
|
|
||||||
|
/* global defineProps */
|
||||||
|
defineProps({
|
||||||
|
config: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => ({ graph: {} }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content {
|
||||||
|
height: calc(100% - 50px);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,33 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div class="content"> profiling </div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
|
||||||
|
/* global defineProps */
|
||||||
|
defineProps({
|
||||||
|
config: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => ({ graph: {} }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,152 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div ref="timeline" class="task-timeline"></div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch, onMounted } from "vue";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { useThrottleFn } from "@vueuse/core";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import type { EBPFTaskList } from "@/types/ebpf";
|
||||||
|
import { useTaskTimelineStore } from "@/store/modules/task-timeline";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import { useContinousProfilingStore } from "@/store/modules/continous-profiling";
|
||||||
|
import { DataSet, Timeline } from "vis-timeline/standalone";
|
||||||
|
import "vis-timeline/styles/vis-timeline-graph2d.css";
|
||||||
|
import { EBPFProfilingTriggerType } from "@/store/data";
|
||||||
|
|
||||||
|
const taskTimelineStore = useTaskTimelineStore();
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
|
const continousProfilingStore = useContinousProfilingStore();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
/* global defineProps, Nullable */
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const timeline = ref<Nullable<HTMLDivElement>>(null);
|
||||||
|
const visGraph = ref<Nullable<any>>(null);
|
||||||
|
const oldVal = ref<{ width: number; height: number }>({ width: 0, height: 0 });
|
||||||
|
const visDate = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") => dayjs(date).format(pattern);
|
||||||
|
|
||||||
|
init();
|
||||||
|
onMounted(() => {
|
||||||
|
oldVal.value = (timeline.value && timeline.value.getBoundingClientRect()) || {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
};
|
||||||
|
useThrottleFn(resize, 500)();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
const serviceId = (selectorStore.currentService && selectorStore.currentService.id) || "";
|
||||||
|
const serviceInstanceId = (selectorStore.currentPod && selectorStore.currentPod.id) || "";
|
||||||
|
const type = continousProfilingStore.selectedStrategy.type;
|
||||||
|
const res = await taskTimelineStore.getContinousTaskList({
|
||||||
|
serviceId,
|
||||||
|
serviceInstanceId,
|
||||||
|
targets: [type],
|
||||||
|
triggerType: EBPFProfilingTriggerType.CONTINUOUS_PROFILING,
|
||||||
|
});
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function visTimeline() {
|
||||||
|
if (!timeline.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (visGraph.value) {
|
||||||
|
visGraph.value.destroy();
|
||||||
|
}
|
||||||
|
const h = timeline.value.getBoundingClientRect().height;
|
||||||
|
const events = taskTimelineStore.events.map((d: EBPFTaskList, index: number) => {
|
||||||
|
return {
|
||||||
|
id: index + 1,
|
||||||
|
content: d.triggerType,
|
||||||
|
start: new Date(Number(d.taskStartTime)),
|
||||||
|
end: new Date(Number(d.taskStartTime + d.fixedTriggerDuration * 1000)),
|
||||||
|
data: d,
|
||||||
|
className: d.targetType,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const items: any = new DataSet(events);
|
||||||
|
const options: any = {
|
||||||
|
height: h,
|
||||||
|
width: "100%",
|
||||||
|
locale: "en",
|
||||||
|
groupHeightMode: "fitItems",
|
||||||
|
autoResize: false,
|
||||||
|
tooltip: {
|
||||||
|
overflowMethod: "cap",
|
||||||
|
template(item: Event | any) {
|
||||||
|
const data = item.data || {};
|
||||||
|
let tmp = `<div>ID: ${data.uuid || ""}</div>
|
||||||
|
<div>Name: ${data.name || ""}</div>
|
||||||
|
<div>Event Type: ${data.type || ""}</div>
|
||||||
|
<div>Start Time: ${data.startTime ? visDate(data.startTime) : ""}</div>
|
||||||
|
<div>End Time: ${data.endTime ? visDate(data.endTime) : ""}</div>
|
||||||
|
<div>Message: ${data.message || ""}</div>
|
||||||
|
<div>Service: ${data.source.service || ""}</div>`;
|
||||||
|
return tmp;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
visGraph.value = new Timeline(timeline.value, items, options);
|
||||||
|
visGraph.value.on("select", (properties: { items: number[] }) => {
|
||||||
|
dashboardStore.selectWidget(props.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
const observer = new ResizeObserver((entries) => {
|
||||||
|
const entry = entries[0];
|
||||||
|
const cr = entry.contentRect;
|
||||||
|
if (Math.abs(cr.width - oldVal.value.width) < 3 && Math.abs(cr.height - oldVal.value.height) < 3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
visTimeline();
|
||||||
|
oldVal.value = { width: cr.width, height: cr.height };
|
||||||
|
});
|
||||||
|
if (timeline.value) {
|
||||||
|
observer.observe(timeline.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => taskTimelineStore.taskList,
|
||||||
|
() => {
|
||||||
|
visTimeline();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.task-timeline {
|
||||||
|
width: calc(100% - 5px);
|
||||||
|
margin: 0 5px 5px 0;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
max-width: 400px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user