From 5da441ff9a5099fcde20ea009fad0155a78ef272 Mon Sep 17 00:00:00 2001 From: Fine0830 Date: Thu, 8 Sep 2022 21:46:37 +0800 Subject: [PATCH 1/4] fix: polish the endpoint list graph (#155) --- src/locales/lang/en.ts | 1 + src/locales/lang/es.ts | 1 + src/locales/lang/zh.ts | 1 + src/views/dashboard/graphs/EndpointList.vue | 18 ++++++++---------- src/views/dashboard/graphs/InstanceList.vue | 11 +---------- src/views/dashboard/graphs/ServiceList.vue | 7 +------ src/views/dashboard/graphs/style.scss | 15 ++++++++++++++- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts index 58fd4945..7af04a65 100644 --- a/src/locales/lang/en.ts +++ b/src/locales/lang/en.ts @@ -152,6 +152,7 @@ const msg = { text: "Text", query: "Query", postgreSQL: "PostgreSQL", + endpointTips: "The table shows up to 20 pieces of endpoints.", seconds: "Seconds", hourTip: "Select Hour", minuteTip: "Select Minute", diff --git a/src/locales/lang/es.ts b/src/locales/lang/es.ts index 0b167791..136cd56f 100644 --- a/src/locales/lang/es.ts +++ b/src/locales/lang/es.ts @@ -152,6 +152,7 @@ const msg = { enableAssociate: "Activar asociación", query: "Consulta", postgreSQL: "PostgreSQL", + endpointTips: "Aquí, la tabla muestra hasta 20 punto final.", seconds: "Segundos", hourTip: "Seleccione Hora", minuteTip: "Seleccione Minuto", diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts index e180079a..e0f50e98 100644 --- a/src/locales/lang/zh.ts +++ b/src/locales/lang/zh.ts @@ -149,6 +149,7 @@ const msg = { text: "文本", query: "查询", postgreSQL: "PostgreSQL", + endpointTips: "这里最多展示20条endpoints。", seconds: "秒", hourTip: "选择小时", minuteTip: "选择分钟", diff --git a/src/views/dashboard/graphs/EndpointList.vue b/src/views/dashboard/graphs/EndpointList.vue index 2967a567..c4654b22 100644 --- a/src/views/dashboard/graphs/EndpointList.vue +++ b/src/views/dashboard/graphs/EndpointList.vue @@ -17,17 +17,17 @@ limitations under the License. -->
@@ -56,6 +56,7 @@ limitations under the License. --> import { ref, watch, computed } from "vue"; import { useSelectorStore } from "@/store/modules/selectors"; import { ElMessage } from "element-plus"; +import { useI18n } from "vue-i18n"; import type { PropType } from "vue"; import { EndpointListConfig } from "@/types/dashboard"; import { Endpoint } from "@/types/selector"; @@ -92,6 +93,7 @@ const props = defineProps({ intervalTime: { type: Array as PropType, default: () => [] }, }); +const { t } = useI18n(); const selectorStore = useSelectorStore(); const dashboardStore = useDashboardStore(); const chartLoading = ref(false); @@ -191,11 +193,7 @@ watch( diff --git a/src/views/dashboard/graphs/InstanceList.vue b/src/views/dashboard/graphs/InstanceList.vue index 412973ca..04ae5412 100644 --- a/src/views/dashboard/graphs/InstanceList.vue +++ b/src/views/dashboard/graphs/InstanceList.vue @@ -18,12 +18,11 @@ limitations under the License. --> @@ -243,14 +242,6 @@ watch( diff --git a/src/views/dashboard/graphs/style.scss b/src/views/dashboard/graphs/style.scss index a1b83a93..261abc2f 100644 --- a/src/views/dashboard/graphs/style.scss +++ b/src/views/dashboard/graphs/style.scss @@ -23,6 +23,7 @@ .list { margin-top: 10px; margin-bottom: 10px; + height: calc(100% - 90px); } .pagination { @@ -40,9 +41,21 @@ } .search { - text-align: right; + margin-top: 5px; } .input-with-search { width: 400px; } + +.btn { + margin-top: -12px; +} + +.chart { + height: 60px; +} + +.inputs { + width: 300px; +} From 0d63d538c3aada85d55082ee92d239d4d3ae51e2 Mon Sep 17 00:00:00 2001 From: Fine0830 Date: Thu, 8 Sep 2022 22:41:02 +0800 Subject: [PATCH 2/4] fix: set up a new time range after clicking the refresh button (#156) --- src/layout/components/NavBar.vue | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/layout/components/NavBar.vue b/src/layout/components/NavBar.vue index 19355743..d5710e7c 100644 --- a/src/layout/components/NavBar.vue +++ b/src/layout/components/NavBar.vue @@ -18,7 +18,7 @@ limitations under the License. -->
{{ t("timeTips") }} (""); const timeRange = ref(0); -const time = ref([ - appStore.durationRow.start, - appStore.durationRow.end, -]); resetDuration(); getVersion(); @@ -73,15 +68,13 @@ const setConfig = (value: string) => { pageName.value = value || ""; }; -const handleReload = () => { +function handleReload() { const gap = appStore.duration.end.getTime() - appStore.duration.start.getTime(); - const dates: Date[] = [ - getLocalTime(appStore.utc, new Date(new Date().getTime() - gap)), - getLocalTime(appStore.utc, new Date()), - ]; + const dates: Date[] = [new Date(new Date().getTime() - gap), new Date()]; appStore.setDuration(timeFormat(dates)); -}; +} + function changeTimeRange(val: Date[] | any) { timeRange.value = val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0; @@ -114,7 +107,6 @@ function resetDuration() { step: d.step, }); appStore.updateUTC(d.utc); - time.value = [new Date(d.start), new Date(d.end)]; } } From 9ed0121fd0763bc026e43eef7664872aec37e24b Mon Sep 17 00:00:00 2001 From: Fine0830 Date: Tue, 13 Sep 2022 16:31:30 +0800 Subject: [PATCH 3/4] fix: update styles for an adaptive height (#157) --- src/App.vue | 2 +- src/layout/components/SideBar.vue | 5 +++-- src/views/dashboard/List.vue | 9 +++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/App.vue b/src/App.vue index 1fbc2e99..06d3cfc4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -19,7 +19,7 @@ limitations under the License. --> #app { color: #2c3e50; height: 100%; - overflow: auto; + overflow: hidden; min-width: 1024px; } diff --git a/src/layout/components/SideBar.vue b/src/layout/components/SideBar.vue index 44392bc4..e05e9af5 100644 --- a/src/layout/components/SideBar.vue +++ b/src/layout/components/SideBar.vue @@ -141,13 +141,14 @@ const filterMenus = (menus: any[]) => { .side-bar { background: #252a2f; height: 100%; - min-height: 700px; position: relative; margin-bottom: 100px; + overflow-y: auto; + overflow-x: hidden; } .el-menu-vertical:not(.el-menu--collapse) { - width: 200px; + width: 220px; font-size: 16px; } diff --git a/src/views/dashboard/List.vue b/src/views/dashboard/List.vue index e4072d0b..dec6cefa 100644 --- a/src/views/dashboard/List.vue +++ b/src/views/dashboard/List.vue @@ -46,7 +46,7 @@ limitations under the License. --> ref="multipleTableRef" :default-sort="{ prop: 'name', order: 'ascending' }" @selection-change="handleSelectionChange" - height="637px" + height="calc(100% - 60px)" size="small" > @@ -156,7 +156,7 @@ import { isEmptyObject } from "@/utils/is"; const { t } = useI18n(); const appStore = useAppStoreWithOut(); const dashboardStore = useDashboardStore(); -const pageSize = 18; +const pageSize = 20; const dashboards = ref([]); const searchText = ref(""); const loading = ref(false); @@ -500,12 +500,13 @@ function changePage(pageIndex: number) { } .table { - padding: 20px; + padding: 20px 10px; background-color: #fff; box-shadow: 0px 1px 4px 0px #00000029; border-radius: 5px; width: 100%; - overflow: hidden; + height: 100%; + overflow: auto; } .toggle-selection { From 26817e9f927dd07fb439f415227bf371f45a9645 Mon Sep 17 00:00:00 2001 From: Fine0830 Date: Thu, 15 Sep 2022 17:18:39 +0800 Subject: [PATCH 4/4] feat: enhance the process topology graph to support dragging nodes (#158) --- src/layout/components/SideBar.vue | 3 +- src/store/modules/network-profiling.ts | 24 +- src/types/ebpf.d.ts | 2 + src/views/dashboard/controls/Widget.vue | 5 + .../related/components/utils/zoom.ts | 8 +- .../related/network-profiling/Content.vue | 2 +- .../components/Graph/linkProcess.ts | 141 +++---- .../components/Graph/nodeProcess.ts | 54 --- .../components/ProcessTopology.vue | 363 ++++++++++++------ 9 files changed, 311 insertions(+), 291 deletions(-) delete mode 100644 src/views/dashboard/related/network-profiling/components/Graph/nodeProcess.ts diff --git a/src/layout/components/SideBar.vue b/src/layout/components/SideBar.vue index e05e9af5..a343cd59 100644 --- a/src/layout/components/SideBar.vue +++ b/src/layout/components/SideBar.vue @@ -141,7 +141,6 @@ const filterMenus = (menus: any[]) => { .side-bar { background: #252a2f; height: 100%; - position: relative; margin-bottom: 100px; overflow-y: auto; overflow-x: hidden; @@ -174,7 +173,7 @@ span.collapse { .menu-control { position: absolute; top: 7px; - left: 200px; + left: 220px; cursor: pointer; transition: all 0.2s linear; z-index: 99; diff --git a/src/store/modules/network-profiling.ts b/src/store/modules/network-profiling.ts index 88cd54d4..2c45208c 100644 --- a/src/store/modules/network-profiling.ts +++ b/src/store/modules/network-profiling.ts @@ -92,15 +92,21 @@ export const networkProfilingStore = defineStore({ } return prev; }, []); - calls = calls.map((d: any) => { - d.sourceId = d.source; - d.targetId = d.target; - d.source = d.sourceObj; - d.target = d.targetObj; - delete d.sourceObj; - delete d.targetObj; - return d; - }); + const param = {} as any; + calls = data.calls.reduce((prev: (Call | any)[], next: Call | any) => { + if (param[next.targetId + next.sourceId]) { + next.lowerArc = true; + } + param[next.sourceId + next.targetId] = true; + next.sourceId = next.source; + next.targetId = next.target; + next.source = next.sourceObj; + next.target = next.targetObj; + delete next.sourceObj; + delete next.targetObj; + prev.push(next); + return prev; + }, []); this.calls = calls; this.nodes = data.nodes; }, diff --git a/src/types/ebpf.d.ts b/src/types/ebpf.d.ts index 5dfca0ef..e9986ef1 100644 --- a/src/types/ebpf.d.ts +++ b/src/types/ebpf.d.ts @@ -74,4 +74,6 @@ export type ProcessNode = { serviceInstanceName: string; name: string; isReal: boolean; + x?: number; + y?: number; }; diff --git a/src/views/dashboard/controls/Widget.vue b/src/views/dashboard/controls/Widget.vue index ec582664..6d986f2e 100644 --- a/src/views/dashboard/controls/Widget.vue +++ b/src/views/dashboard/controls/Widget.vue @@ -228,6 +228,11 @@ export default defineComponent({ watch( () => [selectorStore.currentProcess, selectorStore.currentDestProcess], () => { + if ( + !(selectorStore.currentDestProcess && selectorStore.currentProcess) + ) { + return; + } if (dashboardStore.entity === EntityType[7].value) { queryMetrics(); } diff --git a/src/views/dashboard/related/components/utils/zoom.ts b/src/views/dashboard/related/components/utils/zoom.ts index 9227089c..6ba31c04 100644 --- a/src/views/dashboard/related/components/utils/zoom.ts +++ b/src/views/dashboard/related/components/utils/zoom.ts @@ -19,11 +19,11 @@ export default (d3: any, graph: any, diff: number[]) => d3 .zoom() .scaleExtent([0.3, 10]) - .on("zoom", (event: any) => { + .on("zoom", (d: any) => { graph.attr( "transform", - `translate(${event.transform.x + diff[0]},${ - event.transform.y + diff[1] - })scale(${event.transform.k})` + `translate(${d.transform.x + diff[0]},${ + d.transform.y + diff[1] + })scale(${d.transform.k})` ); }); diff --git a/src/views/dashboard/related/network-profiling/Content.vue b/src/views/dashboard/related/network-profiling/Content.vue index f041b75f..d9d615ad 100644 --- a/src/views/dashboard/related/network-profiling/Content.vue +++ b/src/views/dashboard/related/network-profiling/Content.vue @@ -53,7 +53,7 @@ const { t } = useI18n(); height: 100%; flex-grow: 2; min-width: 700px; - overflow: auto; + overflow: hidden; position: relative; width: calc(100% - 330px); } diff --git a/src/views/dashboard/related/network-profiling/components/Graph/linkProcess.ts b/src/views/dashboard/related/network-profiling/components/Graph/linkProcess.ts index 858e090a..26c94e4c 100644 --- a/src/views/dashboard/related/network-profiling/components/Graph/linkProcess.ts +++ b/src/views/dashboard/related/network-profiling/components/Graph/linkProcess.ts @@ -17,96 +17,6 @@ import icons from "@/assets/img/icons"; import { Call } from "@/types/topology"; -export const linkElement = (graph: any) => { - const linkEnter = graph - .append("path") - .attr("class", "topo-call") - .attr("marker-end", "url(#arrow)") - .attr("stroke", "#97B0F8") - .attr("d", (d: Call) => { - const controlPos = computeControlPoint( - [d.source.x, d.source.y - 5], - [d.target.x, d.target.y - 5], - 0.5 - ); - if (d.lowerArc) { - controlPos[1] = - Math.abs(controlPos[1]) < 50 - ? -controlPos[1] + 90 - : -controlPos[1] - 10; - } - return ( - "M" + - d.source.x + - " " + - (d.source.y - 5) + - " " + - "Q" + - controlPos[0] + - " " + - controlPos[1] + - " " + - d.target.x + - " " + - (d.target.y - 5) - ); - }); - return linkEnter; -}; -export const anchorElement = (graph: any, funcs: any, tip: any) => { - const linkEnter = graph - .append("g") - .attr("class", "topo-line-anchor") - .on("mouseover", function (event: unknown, d: unknown) { - tip.html(funcs.tipHtml).show(d, this); - }) - .on("mouseout", function () { - tip.hide(this); - }) - .on("click", (event: unknown, d: unknown) => { - funcs.handleLinkClick(event, d); - }); - linkEnter - .append("image") - .attr("width", 15) - .attr("height", 15) - .attr("x", (d: Call) => { - const p = getMidpoint(d); - return p[0] - 8; - }) - .attr("y", (d: Call) => { - const p = getMidpoint(d); - return p[1] - 13; - }) - .attr("xlink:href", (d: Call) => { - const types = [...d.sourceComponents, ...d.targetComponents]; - if (types.includes("tcp") || types.includes("http")) { - return icons.HTTPDARK; - } - if (types.includes("https") || types.includes("tls")) { - return icons.HTTPS; - } - }); - return linkEnter; -}; -export const arrowMarker = (graph: any) => { - const defs = graph.append("defs"); - const arrow = defs - .append("marker") - .attr("id", "arrow") - .attr("class", "topo-line-arrow") - .attr("markerUnits", "strokeWidth") - .attr("markerWidth", "8") - .attr("markerHeight", "8") - .attr("viewBox", "0 0 12 12") - .attr("refX", "10") - .attr("refY", "6") - .attr("orient", "auto"); - const arrowPath = "M2,2 L10,6 L2,10 L6,6 L2,2"; - - arrow.append("path").attr("d", arrowPath).attr("fill", "#97B0F8"); - return arrow; -}; // Control Point coordinates of quadratic Bezier curve function computeControlPoint(ps: number[], pe: number[], arc = 0.5) { const deltaX = pe[0] - ps[0]; @@ -137,15 +47,20 @@ function quadraticBezier( const y = (1 - t) * (1 - t) * ps.y + 2 * t * (1 - t) * pc.y + t * t * pe.y; return [x, y]; } -function getMidpoint(d: Call) { +export function getMidpoint(d: Call) { + if (isNaN(d.source.x) || isNaN(d.source.y)) { + return [0, 0]; + } + if (isNaN(d.target.x) || isNaN(d.target.y)) { + return [0, 0]; + } const controlPos = computeControlPoint( [d.source.x, d.source.y], [d.target.x, d.target.y], 0.5 ); if (d.lowerArc) { - controlPos[1] = - Math.abs(controlPos[1]) < 50 ? -controlPos[1] + 100 : -controlPos[1] - 10; + controlPos[1] = -controlPos[1]; } const p = quadraticBezier( 0.5, @@ -155,3 +70,43 @@ function getMidpoint(d: Call) { ); return p; } +export function linkPath(d: Call) { + if (isNaN(d.source.x) || isNaN(d.source.y)) { + return; + } + if (isNaN(d.target.x) || isNaN(d.target.y)) { + return; + } + const controlPos = computeControlPoint( + [d.source.x, d.source.y - 5], + [d.target.x, d.target.y - 5], + 0.5 + ); + if (d.lowerArc) { + controlPos[1] = -controlPos[1] - 10; + } + return ( + "M" + + d.source.x + + " " + + (d.source.y - 5) + + " " + + "Q" + + controlPos[0] + + " " + + controlPos[1] + + " " + + d.target.x + + " " + + (d.target.y - 5) + ); +} +export function getAnchor(d: Call) { + const types = [...d.sourceComponents, ...d.targetComponents]; + if (types.includes("tcp") || types.includes("http")) { + return icons.HTTPDARK; + } + if (types.includes("https") || types.includes("tls")) { + return icons.HTTPS; + } +} diff --git a/src/views/dashboard/related/network-profiling/components/Graph/nodeProcess.ts b/src/views/dashboard/related/network-profiling/components/Graph/nodeProcess.ts deleted file mode 100644 index 23a033d4..00000000 --- a/src/views/dashboard/related/network-profiling/components/Graph/nodeProcess.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * 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 icons from "@/assets/img/icons"; -import { Node } from "@/types/topology"; - -export default (d3: any, graph: any, funcs: any, tip: any) => { - const nodeEnter = graph - .append("g") - .call( - d3 - .drag() - .on("start", funcs.dragstart) - .on("drag", funcs.dragged) - .on("end", funcs.dragended) - ) - .on("mouseover", function (event: unknown, d: Node) { - tip.html(funcs.tipHtml).show(d, this); - }) - .on("mouseout", function () { - tip.hide(this); - }); - nodeEnter - .append("image") - .attr("width", 35) - .attr("height", 35) - .attr("x", (d: any) => d.x - 15) - .attr("y", (d: any) => d.y - 15) - .attr("style", "cursor: move;") - .attr("xlink:href", icons.CUBE); - nodeEnter - .append("text") - .attr("fill", "#000") - .attr("text-anchor", "middle") - .attr("x", (d: any) => d.x) - .attr("y", (d: any) => d.y + 28) - .text((d: { name: string }) => - d.name.length > 10 ? `${d.name.substring(0, 10)}...` : d.name - ); - return nodeEnter; -}; diff --git a/src/views/dashboard/related/network-profiling/components/ProcessTopology.vue b/src/views/dashboard/related/network-profiling/components/ProcessTopology.vue index 23df6290..a3316d90 100644 --- a/src/views/dashboard/related/network-profiling/components/ProcessTopology.vue +++ b/src/views/dashboard/related/network-profiling/components/ProcessTopology.vue @@ -13,13 +13,103 @@ 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. -->