Merge branch 'main' into dependabot/npm_and_yarn/vite-4.5.2

This commit is contained in:
Fine0830 2024-01-31 11:29:11 +08:00 committed by GitHub
commit a6c1c2ff46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 433 additions and 106 deletions

View File

@ -0,0 +1,138 @@
<!-- 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. -->
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400.000000 400.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,400.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M1737 3725 c-379 -61 -696 -224 -968 -495 -249 -248 -403 -533 -481
-890 -20 -93 -22 -133 -22 -340 0 -207 2 -247 22 -339 48 -217 123 -407 231
-581 253 -406 658 -688 1141 -791 91 -20 135 -23 330 -24 172 0 246 4 315 17
361 69 669 231 926 487 271 272 438 604 494 983 23 154 16 448 -15 593 -147
694 -668 1214 -1366 1365 -130 29 -472 37 -607 15z m461 -131 c24 -3 52 -14
63 -25 23 -23 25 -76 3 -100 -15 -17 -15 -19 0 -34 25 -26 20 -82 -10 -112
-25 -25 -28 -25 -112 -19 -48 4 -88 8 -89 10 -1 1 4 60 12 131 8 72 15 137 15
145 0 17 14 17 118 4z m-359 -30 c30 -22 61 -89 61 -137 0 -48 -22 -102 -48
-116 -23 -12 -163 -43 -169 -38 -7 7 -53 280 -48 285 8 9 78 20 130 21 32 1
59 -5 74 -15z m564 -8 c7 -8 22 -44 31 -80 l18 -66 62 48 c48 38 66 47 85 43
23 -6 18 -12 -58 -71 -76 -61 -83 -69 -98 -122 -12 -43 -21 -58 -34 -58 -28 0
-30 14 -10 73 l19 56 -29 93 c-16 51 -29 94 -29 96 0 8 31 0 43 -12z m-858
-45 c0 -8 -30 -27 -69 -43 -38 -15 -71 -30 -74 -32 -4 -4 17 -76 22 -76 1 0
31 11 66 25 76 30 90 31 90 7 0 -13 -19 -24 -70 -42 -61 -21 -69 -27 -64 -45
15 -46 24 -65 32 -65 5 0 42 14 82 30 57 23 75 27 82 18 4 -7 8 -16 8 -19 0
-7 -180 -79 -197 -79 -6 0 -28 44 -49 98 -20 53 -43 112 -51 131 -7 19 -11 36
-9 38 10 11 173 71 186 70 8 -1 15 -9 15 -16z m-257 -157 c26 -29 28 -61 6
-92 -12 -17 -12 -22 -2 -22 7 0 42 -13 77 -29 62 -28 63 -29 41 -44 -21 -15
-26 -14 -59 2 -20 10 -53 24 -73 30 -37 12 -37 13 -96 -25 -2 -1 13 -27 32
-58 34 -52 35 -56 17 -65 -17 -10 -27 2 -92 101 -39 62 -74 119 -76 128 -2 9
14 26 44 44 119 73 138 76 181 30z m-292 -145 c3 -6 -19 -37 -52 -70 l-58 -59
29 -30 29 -30 56 55 c48 47 59 54 69 42 10 -12 2 -24 -44 -68 l-56 -52 32 -33
32 -33 64 59 c52 47 68 57 78 47 11 -10 -1 -27 -66 -92 l-80 -80 -99 105 c-55
58 -100 108 -100 111 0 10 139 139 150 139 5 0 12 -5 16 -11z m1197 -44 c494
-74 896 -467 982 -959 19 -113 19 -299 0 -410 -73 -416 -377 -773 -776 -910
-142 -48 -213 -59 -384 -59 -175 -1 -241 10 -400 65 -383 131 -680 481 -761
893 -22 115 -20 335 5 450 79 372 314 669 656 831 214 102 441 135 678 99z
m-1319 -258 c81 -91 95 -110 86 -126 -9 -18 -14 -18 -122 16 -62 19 -117 38
-123 41 -10 6 17 -27 109 -133 41 -46 48 -60 39 -73 -13 -20 0 -23 -160 28
-89 28 -133 47 -133 56 0 28 27 25 134 -15 73 -26 103 -34 94 -23 -7 9 -43 50
-80 91 -55 61 -65 78 -57 93 13 25 30 23 147 -15 l103 -33 -82 82 c-67 67 -80
85 -74 103 4 12 10 21 14 19 4 -2 51 -51 105 -111z m2502 -151 c38 -38 44 -77
19 -126 -19 -37 -43 -50 -95 -50 -61 0 -100 41 -100 105 0 40 5 52 31 76 46
42 99 41 145 -5z m-2677 -171 c16 -8 41 -29 56 -47 24 -29 27 -38 23 -91 -4
-54 -8 -63 -41 -93 -32 -30 -44 -34 -90 -34 -126 0 -200 102 -150 207 9 20 30
44 47 54 38 23 115 25 155 4z m-145 -306 c35 -16 50 -59 42 -124 l-6 -54 32
-5 c18 -3 44 -7 58 -8 19 -2 24 -8 22 -23 -2 -11 -5 -21 -6 -22 -5 -6 -272 30
-280 37 -5 5 -4 42 3 87 9 63 16 82 37 101 28 24 60 28 98 11z m2717 -590 c14
-7 18 -16 14 -27 -4 -9 -20 -52 -36 -95 l-29 -78 33 -13 c77 -32 72 -34 105
51 29 75 55 102 67 70 3 -7 -7 -48 -24 -90 l-29 -76 55 -21 c30 -11 58 -18 62
-15 5 2 23 45 41 95 31 87 41 99 68 82 10 -7 2 -36 -32 -126 -25 -65 -47 -120
-49 -123 -3 -2 -82 26 -177 62 -95 36 -175 65 -177 65 -9 0 1 33 39 137 24 62
44 113 46 113 2 0 12 -5 23 -11z m34 -411 c80 -57 145 -106 145 -109 0 -3 -6
-14 -14 -24 -13 -18 -17 -16 -79 28 -36 26 -69 47 -74 47 -10 0 -113 -145
-113 -158 0 -7 61 -53 122 -93 14 -9 -11 -52 -26 -46 -10 4 -288 198 -304 212
-6 5 18 45 26 45 5 0 36 -21 71 -46 34 -25 64 -44 65 -42 1 2 25 35 52 73 28
39 53 75 57 81 4 7 -18 29 -58 55 -35 24 -65 49 -65 55 0 16 23 35 38 29 7 -2
78 -51 157 -107z m-2350 -142 c35 -15 65 -59 65 -96 0 -54 -57 -110 -112 -110
-13 0 -37 9 -55 20 -69 41 -63 154 9 185 42 18 51 18 93 1z m2003 -75 c8 -5
12 -17 10 -27 -3 -14 -11 -18 -33 -17 -82 7 -145 -48 -145 -126 0 -89 73 -161
162 -161 43 0 54 4 84 34 27 27 34 42 34 74 0 32 4 41 22 45 29 8 38 1 38 -31
-1 -38 -32 -102 -66 -133 -75 -69 -196 -57 -276 28 -27 28 -58 99 -58 132 0
65 56 152 115 177 34 15 94 18 113 5z m-247 -340 c79 -74 145 -138 147 -142 2
-4 -7 -13 -19 -19 -19 -11 -26 -7 -65 31 l-43 42 -68 -31 -68 -32 -3 -64 c-2
-55 -6 -66 -23 -71 -11 -4 -23 -5 -25 -2 -3 2 -9 94 -14 203 -8 180 -7 200 8
212 9 7 19 11 23 10 4 -2 71 -63 150 -137z m-321 34 c58 -30 78 -120 40 -182
-19 -31 -48 -44 -151 -67 l-26 -6 14 -60 c15 -68 12 -80 -20 -80 -20 0 -24 12
-56 173 -19 94 -36 179 -38 188 -4 12 11 19 64 31 90 20 138 21 173 3z m-334
-207 c38 -105 71 -195 72 -200 2 -4 -10 -8 -26 -8 -28 0 -32 5 -49 58 l-20 57
-79 3 -79 3 -27 -54 c-24 -49 -29 -54 -53 -50 -14 3 -25 9 -23 13 2 3 41 88
87 188 112 243 106 244 197 -10z"/>
<path d="M2120 3537 c0 -14 -2 -32 -6 -40 -4 -11 6 -16 43 -20 54 -6 83 5 83
32 0 27 -24 43 -75 49 -43 4 -45 3 -45 -21z"/>
<path d="M2105 3399 c-4 -22 -5 -42 -2 -45 9 -10 77 -16 101 -10 52 13 44 70
-12 86 -68 19 -79 14 -87 -31z"/>
<path d="M1697 3533 c-13 -3 -17 -11 -14 -26 3 -12 11 -58 18 -102 7 -44 14
-81 15 -83 7 -10 96 13 113 29 39 36 21 165 -24 183 -18 7 -80 6 -108 -1z"/>
<path d="M1156 3310 l-47 -30 22 -33 c12 -17 24 -34 25 -36 6 -7 94 50 103 67
5 10 5 27 0 40 -12 31 -45 28 -103 -8z"/>
<path d="M1060 2137 c-20 -10 -25 -20 -25 -52 0 -37 4 -42 53 -75 79 -52 68
-97 -21 -88 -23 2 -32 -1 -32 -12 0 -11 14 -16 57 -18 48 -2 60 0 77 19 40 43
27 78 -46 125 -71 45 -70 68 5 72 35 2 52 7 52 16 0 26 -78 34 -120 13z"/>
<path d="M1230 2020 c0 -123 1 -130 20 -130 17 0 20 7 20 43 l1 42 20 -25 c12
-14 27 -33 34 -43 8 -11 22 -17 35 -15 21 3 20 4 -9 43 -38 50 -38 61 0 105
29 34 29 35 8 38 -12 2 -26 -4 -34 -15 -7 -10 -22 -29 -34 -43 l-20 -25 -1 78
c0 70 -2 77 -20 77 -19 0 -20 -7 -20 -130z"/>
<path d="M2030 1976 c0 -130 1 -136 20 -136 20 0 20 5 18 132 -3 117 -5 133
-20 136 -16 3 -18 -8 -18 -132z"/>
<path d="M2133 2103 c-10 -3 -13 -40 -13 -134 0 -121 1 -129 19 -129 16 0 20
8 23 43 l3 42 30 -42 c20 -28 38 -42 53 -43 12 0 22 3 22 6 0 3 -16 26 -35 51
l-35 46 35 43 c40 48 42 54 18 54 -10 0 -35 -19 -55 -42 l-37 -43 -1 78 c0 75
-2 81 -27 70z"/>
<path d="M2310 2090 c0 -13 7 -20 20 -20 13 0 20 7 20 20 0 13 -7 20 -20 20
-13 0 -20 -7 -20 -20z"/>
<path d="M1410 2073 c0 -5 7 -30 15 -58 9 -27 20 -67 26 -87 5 -22 16 -38 24
-38 8 0 15 -4 15 -8 0 -17 -25 -32 -52 -32 -18 0 -28 -5 -28 -15 0 -22 72 -20
92 3 9 9 28 60 42 112 15 52 29 103 32 113 5 15 1 18 -17 15 -17 -2 -25 -12
-32 -38 -23 -94 -29 -110 -36 -106 -5 3 -11 20 -15 38 -17 85 -27 108 -46 108
-11 0 -20 -3 -20 -7z"/>
<path d="M1766 2031 c-3 -4 -8 -35 -12 -67 -8 -75 -19 -96 -28 -58 -25 105
-26 105 -53 102 -23 -3 -29 -10 -41 -58 -15 -63 -32 -88 -32 -48 0 14 -3 40
-7 59 -5 28 -7 30 -14 14 -13 -35 -10 -112 6 -125 29 -24 49 -7 67 55 9 33 17
62 18 65 1 3 11 -24 23 -60 19 -57 25 -65 47 -65 22 0 27 7 37 50 7 28 16 71
19 98 5 39 4 47 -9 47 -9 0 -18 -4 -21 -9z"/>
<path d="M1853 2033 c-7 -2 -13 -12 -13 -20 0 -12 7 -14 31 -9 34 7 69 -8 69
-28 0 -8 -17 -16 -42 -20 -53 -9 -68 -21 -68 -57 0 -43 21 -57 90 -56 l60 0 0
68 c0 103 -19 130 -90 128 -14 0 -31 -3 -37 -6z m87 -128 c0 -18 -7 -26 -24
-31 -30 -7 -46 1 -46 25 0 24 9 31 42 31 23 0 28 -4 28 -25z"/>
<path d="M2317 2033 c-4 -3 -7 -48 -7 -100 0 -86 1 -93 20 -93 19 0 20 7 20
100 0 77 -3 100 -13 100 -8 0 -17 -3 -20 -7z"/>
<path d="M2400 1938 c0 -91 1 -98 20 -98 17 0 19 8 22 78 l3 77 35 0 35 0 3
-77 c3 -70 5 -78 22 -78 18 0 20 7 20 78 0 106 -9 117 -94 118 l-66 1 0 -99z"/>
<path d="M2642 2025 l-33 -14 4 -73 c2 -40 -1 -84 -7 -97 -9 -20 -6 -27 17
-47 51 -43 147 -23 147 30 0 31 -16 43 -78 57 -64 15 -67 29 -7 29 58 0 90 28
81 71 -3 15 -1 31 4 34 39 24 -74 32 -128 10z m74 -29 c27 -20 7 -51 -32 -51
-23 0 -30 5 -32 24 -6 38 29 52 64 27z m-8 -151 c14 -4 22 -13 20 -23 -4 -22
-60 -28 -77 -9 -15 19 -3 49 18 43 9 -2 26 -7 39 -11z"/>
<path d="M549 2531 c-50 -50 -35 -120 33 -151 52 -24 80 -25 117 -5 72 37 56
137 -26 171 -52 22 -91 18 -124 -15z"/>
<path d="M471 2222 c-10 -19 -18 -99 -11 -105 3 -2 24 -7 47 -10 l42 -5 7 54
c4 37 2 59 -6 69 -17 21 -67 19 -79 -3z"/>
<path d="M2571 750 c0 -25 4 -66 7 -91 l7 -46 57 27 57 27 -65 64 -64 63 1
-44z"/>
<path d="M2247 708 c-25 -7 -36 -15 -33 -23 2 -7 10 -41 17 -74 l12 -62 31 6
c84 17 103 26 114 50 17 37 15 59 -9 89 -23 29 -61 33 -132 14z"/>
<path d="M1927 590 l-36 -75 60 -9 c33 -5 62 -7 64 -4 4 4 -4 28 -47 148 -4 9
-19 -14 -41 -60z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -23,6 +23,7 @@ export const ServicesTopology = {
name name
type type
isReal isReal
layers
} }
calls { calls {
id id

View File

@ -24,7 +24,7 @@ export default function getDashboard(param?: { name?: string; layer: string; ent
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const opt = param || dashboardStore.currentDashboard; const opt = param || dashboardStore.currentDashboard;
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]"); const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
let dashboard; let dashboard: Recordable;
if (type === ConfigFieldTypes.NAME) { if (type === ConfigFieldTypes.NAME) {
dashboard = list.find( dashboard = list.find(
(d: { name: string; layer: string; entity: string }) => (d: { name: string; layer: string; entity: string }) =>
@ -62,6 +62,9 @@ export default function getDashboard(param?: { name?: string; layer: string; ent
filters, filters,
}; };
dashboardStore.setWidget(item); dashboardStore.setWidget(item);
if (widget.id === sourceId) {
return;
}
const targetTabIndex = (widget.id || "").split("-"); const targetTabIndex = (widget.id || "").split("-");
const sourceTabindex = (sourceId || "").split("-") || []; const sourceTabindex = (sourceId || "").split("-") || [];
let container: Nullable<Element>; let container: Nullable<Element>;

View File

@ -21,6 +21,7 @@ import { routesMarketplace } from "./marketplace";
import { routesAlarm } from "./alarm"; import { routesAlarm } from "./alarm";
import routesLayers from "./layer"; import routesLayers from "./layer";
import { routesSettings } from "./settings"; import { routesSettings } from "./settings";
import { routesNotFound } from "./notFound";
const routes: RouteRecordRaw[] = [ const routes: RouteRecordRaw[] = [
...routesMarketplace, ...routesMarketplace,
@ -28,6 +29,7 @@ const routes: RouteRecordRaw[] = [
...routesAlarm, ...routesAlarm,
...routesDashboard, ...routesDashboard,
...routesSettings, ...routesSettings,
...routesNotFound,
]; ];
const router = createRouter({ const router = createRouter({

26
src/router/notFound.ts Normal file
View File

@ -0,0 +1,26 @@
/**
* 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 type { RouteRecordRaw } from "vue-router";
import NotFound from "@/views/NotFound.vue";
export const routesNotFound: Array<RouteRecordRaw> = [
{
path: "/:pathMatch(.*)*",
name: "NotFound",
component: NotFound,
},
];

View File

@ -24,7 +24,6 @@ import { useSelectorStore } from "@/store/modules/selectors";
import { NewControl, TextConfig, TimeRangeConfig, ControlsTypes } from "../data"; import { NewControl, TextConfig, TimeRangeConfig, ControlsTypes } from "../data";
import type { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useI18n } from "vue-i18n";
import { EntityType, MetricModes, WidgetType } from "@/views/dashboard/data"; import { EntityType, MetricModes, WidgetType } from "@/views/dashboard/data";
interface DashboardState { interface DashboardState {
showConfig: boolean; showConfig: boolean;

View File

@ -16,7 +16,6 @@
*/ */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "@/store"; import { store } from "@/store";
import type { Service } from "@/types/selector";
import type { Node, Call, HierarchyNode, ServiceHierarchy, InstanceHierarchy } from "@/types/topology"; import type { Node, Call, HierarchyNode, ServiceHierarchy, InstanceHierarchy } from "@/types/topology";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
@ -88,12 +87,9 @@ export const topologyStore = defineStore({
}, },
setTopology(data: { nodes: Node[]; calls: Call[] }) { setTopology(data: { nodes: Node[]; calls: Call[] }) {
const obj = {} as Recordable; const obj = {} as Recordable;
const services = useSelectorStore().services;
const nodes = (data.nodes || []).reduce((prev: Node[], next: Node) => { const nodes = (data.nodes || []).reduce((prev: Node[], next: Node) => {
if (!obj[next.id]) { if (!obj[next.id]) {
obj[next.id] = true; obj[next.id] = true;
const s = services.filter((d: Service) => d.id === next.id)[0] || {};
next.layer = s.layers ? s.layers[0] : null;
prev.push(next); prev.push(next);
} }
return prev; return prev;
@ -603,7 +599,12 @@ export const topologyStore = defineStore({
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const { currentService } = useSelectorStore(); const { currentService } = useSelectorStore();
const id = this.node ? this.node.id : (currentService || {}).id; const id = this.node ? this.node.id : (currentService || {}).id;
const layer = this.node ? this.node.layer : dashboardStore.layerId; let layer = dashboardStore.layerId;
if (this.node) {
layer = this.node.layers.includes(dashboardStore.layerId)
? dashboardStore.layerId
: this.node.layers.filter((d: string) => d !== dashboardStore.layerId)[0];
}
if (!(id && layer)) { if (!(id && layer)) {
return new Promise((resolve) => resolve({})); return new Promise((resolve) => resolve({}));
} }
@ -659,7 +660,7 @@ export const topologyStore = defineStore({
return metrics; return metrics;
}, },
async queryHierarchyNodeExpressions(expressions: string[], layer: string) { async queryHierarchyNodeExpressions(expressions: string[], layer: string) {
const nodes = this.hierarchyServiceNodes.filter((n: Node) => n.layer === layer); const nodes = this.hierarchyServiceNodes.filter((n: HierarchyNode) => n.layer === layer);
if (!nodes.length) { if (!nodes.length) {
this.setHierarchyNodeMetricValue({}, layer); this.setHierarchyNodeMetricValue({}, layer);
return; return;
@ -672,7 +673,7 @@ export const topologyStore = defineStore({
this.setHierarchyNodeMetricValue(metrics, layer); this.setHierarchyNodeMetricValue(metrics, layer);
}, },
async queryHierarchyInstanceNodeExpressions(expressions: string[], layer: string) { async queryHierarchyInstanceNodeExpressions(expressions: string[], layer: string) {
const nodes = this.hierarchyInstanceNodes.filter((n: Node) => n.layer === layer); const nodes = this.hierarchyInstanceNodes.filter((n: HierarchyNode) => n.layer === layer);
if (!expressions.length) { if (!expressions.length) {
this.setHierarchyInstanceNodeMetricValue({}, layer); this.setHierarchyInstanceNodeMetricValue({}, layer);

View File

@ -43,7 +43,7 @@ export interface Node {
name: string; name: string;
type: string; type: string;
isReal: boolean; isReal: boolean;
layer?: string; layers: string[];
serviceName?: string; serviceName?: string;
height?: number; height?: number;
width?: number; width?: number;
@ -52,6 +52,7 @@ export interface Node {
level?: number; level?: number;
l?: number; l?: number;
key?: string; key?: string;
layer?: string;
} }
export interface ServiceHierarchy { export interface ServiceHierarchy {

29
src/utils/debounce.ts Normal file
View File

@ -0,0 +1,29 @@
/**
* 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.
*/
export function debounce(callback: Function, dur: number) {
let timer: any;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
callback();
}, dur);
};
}

33
src/views/NotFound.vue Normal file
View File

@ -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="not-found flex-h">
<Icon size="largest" iconName="logo-light" />
<h1 class="ml-20">404 Page Not Found</h1>
</div>
</template>
<style lang="scss" scoped>
.not-found {
height: 100%;
width: 100%;
align-items: center;
justify-content: center;
}
.icon {
width: 160px;
height: 160px;
}
</style>

View File

@ -81,7 +81,7 @@ limitations under the License. -->
padding: 10px; padding: 10px;
font-size: $font-size-smaller; font-size: $font-size-smaller;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
min-width: 1200px; min-width: 1000px;
} }
.tools { .tools {
@ -101,6 +101,6 @@ limitations under the License. -->
min-height: calc(100% - 150px); min-height: calc(100% - 150px);
width: 100%; width: 100%;
overflow: auto; overflow: auto;
min-width: 1200px; min-width: 1000px;
} }
</style> </style>

View File

@ -124,11 +124,17 @@ limitations under the License. -->
left: operationsPos.x + 5 + 'px', left: operationsPos.x + 5 + 'px',
}" }"
> >
<span v-for="(item, index) of items" :key="index" @click="item.func(item.dashboard)"> <span v-for="(item, index) of items" :key="index" @click="item.func(item)">
{{ item.title }} {{ item.title }}
</span> </span>
</div> </div>
<el-dialog v-model="hierarchyRelated" :destroy-on-close="true" @closed="hierarchyRelated = false" width="640px"> <el-dialog
v-model="hierarchyRelated"
:title="getHierarchyTitle()"
:destroy-on-close="true"
@closed="hierarchyRelated = false"
width="640px"
>
<div class="hierarchy-related"> <div class="hierarchy-related">
<hierarchy-map :config="config" /> <hierarchy-map :config="config" />
</div> </div>
@ -160,6 +166,7 @@ limitations under the License. -->
import { layout, computeLevels, changeNode } from "../components/utils/layout"; import { layout, computeLevels, changeNode } from "../components/utils/layout";
import zoom from "@/views/dashboard/related/components/utils/zoom"; import zoom from "@/views/dashboard/related/components/utils/zoom";
import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor"; import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor";
import { ConfigFieldTypes } from "@/views/dashboard/data";
/*global Nullable, defineProps */ /*global Nullable, defineProps */
const props = defineProps({ const props = defineProps({
config: { config: {
@ -268,6 +275,20 @@ limitations under the License. -->
currentNode.value = null; currentNode.value = null;
} }
function getHierarchyTitle() {
if (!currentNode.value) {
return;
}
if (currentNode.value.layers.includes(dashboardStore.layerId)) {
return `${dashboardStore.layerId} --> ${currentNode.value.name}`;
}
const layer = currentNode.value.layers.filter((d: string) => d !== dashboardStore.layerId);
if (layer.length) {
return `${layer[0]} --> ${currentNode.value.name}`;
}
return "";
}
async function initLegendMetrics() { async function initLegendMetrics() {
if (!topologyStore.nodes.length) { if (!topologyStore.nodes.length) {
return; return;
@ -410,19 +431,15 @@ limitations under the License. -->
topologyStore.setLink(null); topologyStore.setLink(null);
operationsPos.x = event.offsetX; operationsPos.x = event.offsetX;
operationsPos.y = event.offsetY; operationsPos.y = event.offsetY;
if (d.layer === String(dashboardStore.layerId)) { if (d.layers.includes(dashboardStore.layerId)) {
setNodeTools(settings.value.nodeDashboard); setNodeTools(settings.value.nodeDashboard);
return; return;
} }
items.value = [ initNodeMenus();
{ id: "hierarchyServices", title: "Hierarchy Services", func: handleHierarchyRelatedServices },
{ id: "inspect", title: "Inspect", func: handleInspect },
{ id: "alerting", title: "Alerting", func: handleGoAlerting },
];
} }
function handleLinkClick(event: MouseEvent, d: Call) { function handleLinkClick(event: MouseEvent, d: Call) {
event.stopPropagation(); event.stopPropagation();
if (d.sourceObj.layer !== dashboardStore.layerId || d.targetObj.layer !== dashboardStore.layerId) { if (!d.sourceObj.layers.includes(dashboardStore.layerId) || !d.targetObj.layers.includes(dashboardStore.layerId)) {
return; return;
} }
topologyStore.setNode(null); topologyStore.setNode(null);
@ -462,25 +479,34 @@ limitations under the License. -->
topologyStore.setNode(null); topologyStore.setNode(null);
topologyStore.setLink(null); topologyStore.setLink(null);
} }
function handleGoEndpoint(name: string) { function handleGoEndpoint(params: { dashboard: string }) {
if (!params.dashboard) {
return;
}
const origin = dashboardStore.entity; const origin = dashboardStore.entity;
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[2].value}/${topologyStore.node.id}/${name}`; const path = `/dashboard/${dashboardStore.layerId}/${EntityType[2].value}/${topologyStore.node.id}/${params.dashboard}`;
const routeUrl = router.resolve({ path }); const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");
dashboardStore.setEntity(origin); dashboardStore.setEntity(origin);
} }
function handleGoInstance(name: string) { function handleGoInstance(params: { dashboard: string }) {
if (!params.dashboard) {
return;
}
const origin = dashboardStore.entity; const origin = dashboardStore.entity;
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${topologyStore.node.id}/${name}`; const path = `/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${topologyStore.node.id}/${params.dashboard}`;
const routeUrl = router.resolve({ path }); const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");
dashboardStore.setEntity(origin); dashboardStore.setEntity(origin);
} }
function handleGoDashboard(name: string) { function handleGoDashboard(params: { dashboard: string }) {
if (!params.dashboard) {
return;
}
const origin = dashboardStore.entity; const origin = dashboardStore.entity;
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${topologyStore.node.id}/${name}`; const path = `/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${topologyStore.node.id}/${params.dashboard}`;
const routeUrl = router.resolve({ path }); const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");
@ -492,6 +518,28 @@ limitations under the License. -->
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");
} }
function handleGoLayerDashboard(param: { id: string }) {
if (!(param.id && currentNode.value)) {
return;
}
const origin = dashboardStore.entity;
const { dashboard } = getDashboard(
{
layer: param.id,
entity: EntityType[0].value,
},
ConfigFieldTypes.ISDEFAULT,
);
if (!dashboard) {
return ElMessage.info("No Dashboard");
}
const path = `/dashboard/${param.id}/${EntityType[0].value}/${currentNode.value.id}/${dashboard.name}`;
const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank");
dashboardStore.setEntity(origin);
}
async function backToTopology() { async function backToTopology() {
loading.value = true; loading.value = true;
await freshNodes(); await freshNodes();
@ -520,12 +568,26 @@ limitations under the License. -->
settings.value = config; settings.value = config;
setNodeTools(config.nodeDashboard); setNodeTools(config.nodeDashboard);
} }
function setNodeTools(nodeDashboard: any) { function initNodeMenus() {
items.value = [ items.value = [
{ id: "hierarchyServices", title: "Hierarchy Services", func: handleHierarchyRelatedServices }, { id: "hierarchyServices", title: "Hierarchy Services", func: handleHierarchyRelatedServices },
{ id: "inspect", title: "Inspect", func: handleInspect }, { id: "inspect", title: "Inspect", func: handleInspect },
{ id: "alerting", title: "Alerting", func: handleGoAlerting }, { id: "alerting", title: "Alerting", func: handleGoAlerting },
]; ];
if (!currentNode.value) {
return;
}
const diffLayers = currentNode.value.layers.filter((l: string) => l !== dashboardStore.layerId);
for (const l of diffLayers) {
items.value.push({
id: l,
title: `${l} Dashboard`,
func: handleGoLayerDashboard,
});
}
}
function setNodeTools(nodeDashboard: any) {
initNodeMenus();
if (!(nodeDashboard && nodeDashboard.length)) { if (!(nodeDashboard && nodeDashboard.length)) {
return; return;
} }

View File

@ -172,9 +172,8 @@ limitations under the License. -->
} }
.trace-chart { .trace-chart {
height: calc(100% - 100px); height: calc(100% - 95px);
overflow: auto; overflow: auto;
padding-bottom: 20px;
} }
.trace-detail-wrapper { .trace-detail-wrapper {

View File

@ -150,7 +150,13 @@ limitations under the License. -->
ElMessage.error(resp.errors); ElMessage.error(resp.errors);
return; return;
} }
state.service = getCurrentNode(traceStore.services) || traceStore.services[0]; if (props.data.filters && props.data.filters.id === "0") {
state.service = { value: "", label: "" };
return;
} else {
state.service = getCurrentNode(traceStore.services) || traceStore.services[0];
}
emits("get", state.service.id); emits("get", state.service.id);
getEndpoints(state.service.id); getEndpoints(state.service.id);
@ -198,7 +204,7 @@ limitations under the License. -->
if (props.data.filters && props.data.filters.id) { if (props.data.filters && props.data.filters.id) {
param = { param = {
...param, ...param,
serviceId: props.data.filters.id || undefined, serviceId: props.data.filters.id && props.data.filters.id !== "0" ? props.data.filters.id : undefined,
endpointId: state.endpoint.id || undefined, endpointId: state.endpoint.id || undefined,
serviceInstanceId: state.instance.id || undefined, serviceInstanceId: state.instance.id || undefined,
}; };

View File

@ -159,6 +159,7 @@ limitations under the License. -->
.selectors { .selectors {
margin: 2px 2px 0 0; margin: 2px 2px 0 0;
width: 120px;
} }
.trace-t-wrapper { .trace-t-wrapper {
@ -182,11 +183,11 @@ limitations under the License. -->
} }
.trace-t { .trace-t {
width: 420px; width: 300px;
} }
.list { .list {
width: 300px; width: 280px;
} }
.trace-tr { .trace-tr {
@ -226,7 +227,8 @@ limitations under the License. -->
.no-data { .no-data {
padding-top: 50px; padding-top: 50px;
width: 100%; width: 280px;
text-align: center; text-align: center;
height: 100px;
} }
</style> </style>

View File

@ -29,6 +29,7 @@ limitations under the License. -->
import type { Span, Ref } from "@/types/trace"; import type { Span, Ref } from "@/types/trace";
import SpanDetail from "./SpanDetail.vue"; import SpanDetail from "./SpanDetail.vue";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { debounce } from "@/utils/debounce";
/* global defineProps, Nullable, defineExpose,Recordable*/ /* global defineProps, Nullable, defineExpose,Recordable*/
const props = defineProps({ const props = defineProps({
@ -45,6 +46,8 @@ limitations under the License. -->
const refSpans = ref<Array<Ref>>([]); const refSpans = ref<Array<Ref>>([]);
const tree = ref<Nullable<any>>(null); const tree = ref<Nullable<any>>(null);
const traceGraph = ref<Nullable<HTMLDivElement>>(null); const traceGraph = ref<Nullable<HTMLDivElement>>(null);
const debounceFunc = debounce(draw, 500);
defineExpose({ defineExpose({
tree, tree,
}); });
@ -55,6 +58,15 @@ limitations under the License. -->
loading.value = false; loading.value = false;
return; return;
} }
draw();
loading.value = false;
window.addEventListener("resize", debounceFunc);
});
function draw() {
if (!traceGraph.value) {
return;
}
if (props.type === "List") { if (props.type === "List") {
tree.value = new ListGraph(traceGraph.value, handleSelectSpan); tree.value = new ListGraph(traceGraph.value, handleSelectSpan);
tree.value.init({ label: "TRACE_ROOT", children: segmentId.value }, props.data, fixSpansSize.value); tree.value.init({ label: "TRACE_ROOT", children: segmentId.value }, props.data, fixSpansSize.value);
@ -63,11 +75,6 @@ limitations under the License. -->
tree.value = new TreeGraph(traceGraph.value, handleSelectSpan); tree.value = new TreeGraph(traceGraph.value, handleSelectSpan);
tree.value.init({ label: `${props.traceId}`, children: segmentId.value }, props.data); tree.value.init({ label: `${props.traceId}`, children: segmentId.value }, props.data);
} }
loading.value = false;
window.addEventListener("resize", resize);
});
function resize() {
tree.value.resize();
} }
function handleSelectSpan(i: Recordable) { function handleSelectSpan(i: Recordable) {
currentSpan.value = i.data; currentSpan.value = i.data;
@ -132,28 +139,61 @@ limitations under the License. -->
} }
segmentHeaders.forEach((span: Span) => { segmentHeaders.forEach((span: Span) => {
if (span.refs.length) { if (span.refs.length) {
let exit = 0;
span.refs.forEach((ref) => { span.refs.forEach((ref) => {
const index = props.data.findIndex( const i = props.data.findIndex(
(i: Recordable) => ref.parentSegmentId === i.segmentId && ref.parentSpanId === i.spanId, (i: Recordable) => ref.parentSegmentId === i.segmentId && ref.parentSpanId === i.spanId,
); );
if (index === -1) { if (i > -1) {
// create a known broken node. exit = 1;
const i = ref.parentSpanId; }
const fixSpanKeyContent = { });
if (!exit) {
const ref = span.refs[0];
// create a known broken node.
const i = ref.parentSpanId;
const fixSpanKeyContent = {
traceId: ref.traceId,
segmentId: ref.parentSegmentId,
spanId: i,
parentSpanId: i > -1 ? 0 : -1,
};
if (!_.find(fixSpans, fixSpanKeyContent)) {
fixSpans.push({
...fixSpanKeyContent,
refs: [],
endpointName: `VNode: ${ref.parentSegmentId}`,
serviceCode: "VirtualNode",
type: `[Broken] ${ref.type}`,
peer: "",
component: `VirtualNode: #${i}`,
isError: true,
isBroken: true,
layer: "Broken",
tags: [],
logs: [],
startTime: 0,
endTime: 0,
});
}
// if root broken node is not exist, create a root broken node.
if (fixSpanKeyContent.parentSpanId > -1) {
const fixRootSpanKeyContent = {
traceId: ref.traceId, traceId: ref.traceId,
segmentId: ref.parentSegmentId, segmentId: ref.parentSegmentId,
spanId: i, spanId: 0,
parentSpanId: i > -1 ? 0 : -1, parentSpanId: -1,
}; };
if (!_.find(fixSpans, fixSpanKeyContent)) { if (!_.find(fixSpans, fixRootSpanKeyContent)) {
fixSpans.push({ fixSpans.push({
...fixSpanKeyContent, ...fixRootSpanKeyContent,
refs: [], refs: [],
endpointName: `VNode: ${ref.parentSegmentId}`, endpointName: `VNode: ${ref.parentSegmentId}`,
serviceCode: "VirtualNode", serviceCode: "VirtualNode",
type: `[Broken] ${ref.type}`, type: `[Broken] ${ref.type}`,
peer: "", peer: "",
component: `VirtualNode: #${i}`, component: `VirtualNode: #0`,
isError: true, isError: true,
isBroken: true, isBroken: true,
layer: "Broken", layer: "Broken",
@ -163,44 +203,16 @@ limitations under the License. -->
endTime: 0, endTime: 0,
}); });
} }
// if root broken node is not exist, create a root broken node.
if (fixSpanKeyContent.parentSpanId > -1) {
const fixRootSpanKeyContent = {
traceId: ref.traceId,
segmentId: ref.parentSegmentId,
spanId: 0,
parentSpanId: -1,
};
if (!_.find(fixSpans, fixRootSpanKeyContent)) {
fixSpans.push({
...fixRootSpanKeyContent,
refs: [],
endpointName: `VNode: ${ref.parentSegmentId}`,
serviceCode: "VirtualNode",
type: `[Broken] ${ref.type}`,
peer: "",
component: `VirtualNode: #0`,
isError: true,
isBroken: true,
layer: "Broken",
tags: [],
logs: [],
startTime: 0,
endTime: 0,
});
}
}
} }
}); }
} }
}); });
[...fixSpans, ...props.data].forEach((i) => { [...fixSpans, ...props.data].forEach((i) => {
i.label = i.endpointName || "no operation name"; i.label = i.endpointName || "no operation name";
i.children = []; i.children = [];
if (segmentGroup[i.segmentId] === undefined) { if (!segmentGroup[i.segmentId]) {
segmentIdGroup.push(i.segmentId); segmentIdGroup.push(i.segmentId);
segmentGroup[i.segmentId] = []; segmentGroup[i.segmentId] = [i];
segmentGroup[i.segmentId].push(i);
} else { } else {
segmentGroup[i.segmentId].push(i); segmentGroup[i.segmentId].push(i);
} }
@ -273,7 +285,7 @@ limitations under the License. -->
} }
onBeforeUnmount(() => { onBeforeUnmount(() => {
d3.selectAll(".d3-tip").remove(); d3.selectAll(".d3-tip").remove();
window.removeEventListener("resize", resize); window.removeEventListener("resize", debounceFunc);
}); });
watch( watch(
() => props.data, () => props.data,

View File

@ -42,6 +42,12 @@ limitations under the License. -->
<span class="g-sm-4 grey">{{ t("isError") }}:</span> <span class="g-sm-4 grey">{{ t("isError") }}:</span>
<span class="g-sm-8 wba">{{ currentSpan.isError }}</span> <span class="g-sm-8 wba">{{ currentSpan.isError }}</span>
</div> </div>
<h5 class="mb-10" v-if="diffRefs.length"> {{ t("traceID") }}. </h5>
<div class="mb-10 clear item" v-for="item in diffRefs" :key="item.traceId">
<span class="g-sm-12 wba cp link" @click="viewRelateTrace(item)">
{{ item.traceId }}
</span>
</div>
<h5 class="mb-10" v-if="currentSpan.tags && currentSpan.tags.length"> {{ t("tags") }}. </h5> <h5 class="mb-10" v-if="currentSpan.tags && currentSpan.tags.length"> {{ t("tags") }}. </h5>
<div class="mb-10 clear item" v-for="i in currentSpan.tags" :key="i.key"> <div class="mb-10 clear item" v-for="i in currentSpan.tags" :key="i.key">
<span class="g-sm-4 grey">{{ i.key }}:</span> <span class="g-sm-4 grey">{{ i.key }}:</span>
@ -127,7 +133,7 @@ limitations under the License. -->
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, onMounted } from "vue"; import { ref, computed, onMounted, inject } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import type { PropType } from "vue"; import type { PropType } from "vue";
import dayjs from "dayjs"; import dayjs from "dayjs";
@ -138,14 +144,20 @@ limitations under the License. -->
import { useTraceStore } from "@/store/modules/trace"; import { useTraceStore } from "@/store/modules/trace";
import LogTable from "@/views/dashboard/related/log/LogTable/Index.vue"; import LogTable from "@/views/dashboard/related/log/LogTable/Index.vue";
import type { SpanAttachedEvent } from "@/types/trace"; import type { SpanAttachedEvent } from "@/types/trace";
import getDashboard from "@/hooks/useDashboardsSession";
import { useDashboardStore } from "@/store/modules/dashboard";
import { WidgetType } from "@/views/dashboard/data";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps, Nullable, Recordable */ /*global defineProps, Nullable, Recordable */
const props = defineProps({ const props = defineProps({
currentSpan: { type: Object as PropType<Recordable>, default: () => ({}) }, currentSpan: { type: Object as PropType<Recordable>, default: () => ({}) },
traceId: { type: String, default: "" }, traceId: { type: String, default: "" },
}); });
const options: Recordable<LayoutConfig> = inject("options") || {};
const { t } = useI18n(); const { t } = useI18n();
const traceStore = useTraceStore(); const traceStore = useTraceStore();
const dashboardStore = useDashboardStore();
const pageNum = ref<number>(1); const pageNum = ref<number>(1);
const showRelatedLogs = ref<boolean>(false); const showRelatedLogs = ref<boolean>(false);
const showEventDetail = ref<boolean>(false); const showEventDetail = ref<boolean>(false);
@ -154,6 +166,9 @@ limitations under the License. -->
const total = computed(() => const total = computed(() =>
traceStore.traceList.length === pageSize ? pageSize * pageNum.value + 1 : pageSize * pageNum.value, traceStore.traceList.length === pageSize ? pageSize * pageNum.value + 1 : pageSize * pageNum.value,
); );
const diffRefs = computed(() =>
props.currentSpan.refs.filter((d: Recordable) => d.traceId !== props.currentSpan.traceId),
);
const tree = ref<any>(null); const tree = ref<any>(null);
const eventGraph = ref<Nullable<HTMLDivElement>>(null); const eventGraph = ref<Nullable<HTMLDivElement>>(null);
const visDate = (date: number, pattern = "YYYY-MM-DD HH:mm:ss:SSS") => dayjs(date).format(pattern); const visDate = (date: number, pattern = "YYYY-MM-DD HH:mm:ss:SSS") => dayjs(date).format(pattern);
@ -217,6 +232,19 @@ limitations under the License. -->
tree.value.draw(); tree.value.draw();
} }
function viewRelateTrace(item: Recordable) {
const { associationWidget } = getDashboard(dashboardStore.currentDashboard);
associationWidget(
(options.id as any) || "",
{
sourceId: options.id || "",
traceId: item.traceId || "",
id: "0",
},
WidgetType.Trace,
);
}
function selectEvent(i: any) { function selectEvent(i: any) {
currentEvent.value = i.data; currentEvent.value = i.data;
showEventDetail.value = true; showEventDetail.value = true;
@ -259,7 +287,12 @@ limitations under the License. -->
cursor: pointer; cursor: pointer;
} }
.link,
.link-hover:hover { .link-hover:hover {
color: #448dfe; color: var(--el-color-primary);
}
.link {
text-decoration: underline;
} }
</style> </style>

View File

@ -47,6 +47,7 @@ export default class ListGraph {
this.el = el; this.el = el;
this.width = el.getBoundingClientRect().width - 10; this.width = el.getBoundingClientRect().width - 10;
this.height = el.getBoundingClientRect().height - 10; this.height = el.getBoundingClientRect().height - 10;
d3.select(".trace-list-dowanload").remove();
this.svg = d3 this.svg = d3
.select(this.el) .select(this.el)
.append("svg") .append("svg")
@ -384,15 +385,4 @@ export default class ListGraph {
visDate(date: number, pattern = "YYYY-MM-DD HH:mm:ss:SSS") { visDate(date: number, pattern = "YYYY-MM-DD HH:mm:ss:SSS") {
return dayjs(date).format(pattern); return dayjs(date).format(pattern);
} }
resize() {
if (!this.el) {
return;
}
this.width = this.el.getBoundingClientRect().width - 20;
this.height = this.el.getBoundingClientRect().height - 10;
this.svg.attr("width", this.width).attr("height", this.height);
this.svg.select("g").attr("transform", () => `translate(160, 0)`);
const transform = d3.zoomTransform(this.svg).translate(0, 0);
d3.zoom().transform(this.svg, transform);
}
} }

View File

@ -55,6 +55,7 @@ export default class TraceMap {
this.topChild = []; this.topChild = [];
this.width = el.clientWidth - 20; this.width = el.clientWidth - 20;
this.height = el.clientHeight - 30; this.height = el.clientHeight - 30;
d3.select(".d3-trace-tree").remove();
this.body = d3 this.body = d3
.select(this.el) .select(this.el)
.append("svg") .append("svg")
@ -78,17 +79,6 @@ export default class TraceMap {
this.svg = this.body.append("g").attr("transform", () => `translate(120, 0)`); this.svg = this.body.append("g").attr("transform", () => `translate(120, 0)`);
this.svg.call(this.tip); this.svg.call(this.tip);
} }
resize() {
if (!this.el) {
return;
}
this.width = this.el.clientWidth;
this.height = this.el.clientHeight + 100;
this.body.attr("width", this.width).attr("height", this.height);
this.body.select("g").attr("transform", () => `translate(160, 0)`);
const transform = d3.zoomTransform(this.body).translate(0, 0);
d3.zoom().transform(this.body, transform);
}
init(data: Recordable, row: Recordable) { init(data: Recordable, row: Recordable) {
this.treemap = d3.tree().size([row.length * 35, this.width]); this.treemap = d3.tree().size([row.length * 35, this.width]);
this.row = row; this.row = row;