mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-12 15:52:57 +00:00
feat: update
This commit is contained in:
parent
e556ae39ee
commit
2912a6c030
@ -703,7 +703,7 @@ limitations under the License. -->
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.hierarchy-related {
|
.hierarchy-related {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@ -14,14 +14,13 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
ref="chart"
|
class="hierarchy-services-topo"
|
||||||
class="micro-topo-chart"
|
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
element-loading-background="rgba(0, 0, 0, 0)"
|
element-loading-background="rgba(0, 0, 0, 0)"
|
||||||
:style="`height: ${height}px`"
|
:style="`height: ${height}px`"
|
||||||
>
|
>
|
||||||
<svg class="svg-topology" :width="width - 100" :height="height" @click="svgEvent">
|
<svg class="hierarchy-services-svg" :width="width - 100" :height="height" @click="svgEvent">
|
||||||
<g class="svg-graph" :transform="`translate(${diff[0]}, ${diff[1]})`">
|
<g class="hierarchy-services-graph" :transform="`translate(${diff[0]}, ${diff[1]})`">
|
||||||
<g
|
<g
|
||||||
class="topo-node"
|
class="topo-node"
|
||||||
v-for="(n, index) in topologyLayout.nodes"
|
v-for="(n, index) in topologyLayout.nodes"
|
||||||
@ -63,7 +62,6 @@ limitations under the License. -->
|
|||||||
:cy="(l.sourceY + l.targetY) / 2"
|
:cy="(l.sourceY + l.targetY) / 2"
|
||||||
r="4"
|
r="4"
|
||||||
fill="#97B0F8"
|
fill="#97B0F8"
|
||||||
@click="handleLinkClick($event, l)"
|
|
||||||
@mouseover="showLinkTip($event, l)"
|
@mouseover="showLinkTip($event, l)"
|
||||||
@mouseout="hideTip"
|
@mouseout="hideTip"
|
||||||
/>
|
/>
|
||||||
@ -91,19 +89,19 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { ref, onMounted, onBeforeUnmount, reactive, watch, computed, nextTick } from "vue";
|
import { ref, onMounted, onBeforeUnmount, watch, computed, nextTick } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
import type { Node, Call } from "@/types/topology";
|
import type { Node, Call } from "@/types/topology";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { useTopologyStore } from "@/store/modules/topology";
|
import { useTopologyStore } from "@/store/modules/topology";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { EntityType, MetricModes, CallTypes } from "../../../data";
|
import { EntityType, MetricModes } from "../../../data";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import type { Service } from "@/types/selector";
|
import type { Service } from "@/types/selector";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import getDashboard from "@/hooks/useDashboardsSession";
|
// import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
import type { MetricConfigOpt } from "@/types/dashboard";
|
import type { MetricConfigOpt } from "@/types/dashboard";
|
||||||
import { aggregation } from "@/hooks/useMetricsProcessor";
|
import { aggregation } from "@/hooks/useMetricsProcessor";
|
||||||
import icons from "@/assets/img/icons";
|
import icons from "@/assets/img/icons";
|
||||||
@ -129,11 +127,7 @@ limitations under the License. -->
|
|||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
const svg = ref<Nullable<any>>(null);
|
const svg = ref<Nullable<any>>(null);
|
||||||
const graph = ref<Nullable<any>>(null);
|
const graph = ref<Nullable<any>>(null);
|
||||||
const chart = ref<Nullable<HTMLDivElement>>(null);
|
|
||||||
const showSetting = ref<boolean>(false);
|
|
||||||
const settings = ref<any>(props.config);
|
const settings = ref<any>(props.config);
|
||||||
const operationsPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
|
|
||||||
const items = ref<{ id: string; title: string; func: any; dashboard?: string }[]>([]);
|
|
||||||
const graphConfig = computed(() => props.config.graph || {});
|
const graphConfig = computed(() => props.config.graph || {});
|
||||||
const depth = ref<number>(graphConfig.value.depth || 2);
|
const depth = ref<number>(graphConfig.value.depth || 2);
|
||||||
const topologyLayout = ref<any>({});
|
const topologyLayout = ref<any>({});
|
||||||
@ -156,8 +150,8 @@ limitations under the License. -->
|
|||||||
};
|
};
|
||||||
height.value = dom.height - 40;
|
height.value = dom.height - 40;
|
||||||
width.value = dom.width;
|
width.value = dom.width;
|
||||||
svg.value = d3.select(".svg-topology");
|
svg.value = d3.select(".hierarchy-services-svg");
|
||||||
graph.value = d3.select(".svg-graph");
|
graph.value = d3.select(".hierarchy-services-graph");
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const json = await selectorStore.fetchServices(dashboardStore.layerId);
|
const json = await selectorStore.fetchServices(dashboardStore.layerId);
|
||||||
if (json.errors) {
|
if (json.errors) {
|
||||||
@ -180,21 +174,10 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function update() {
|
async function update() {
|
||||||
if (settings.value.metricMode === MetricModes.Expression) {
|
|
||||||
topologyStore.queryNodeExpressions(settings.value.nodeExpressions || []);
|
|
||||||
topologyStore.getLinkExpressions(settings.value.linkClientExpressions || [], CallTypes.Client);
|
|
||||||
topologyStore.getLinkExpressions(settings.value.linkServerExpressions || [], CallTypes.Server);
|
|
||||||
} else {
|
|
||||||
topologyStore.queryNodeMetrics(settings.value.nodeMetrics || []);
|
|
||||||
topologyStore.getLinkClientMetrics(settings.value.linkClientMetrics || []);
|
|
||||||
topologyStore.getLinkServerMetrics(settings.value.linkServerMetrics || []);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("resize", resize);
|
window.addEventListener("resize", resize);
|
||||||
await initLegendMetrics();
|
await initLegendMetrics();
|
||||||
draw();
|
draw();
|
||||||
tooltip.value = d3.select("#tooltip");
|
tooltip.value = d3.select("#tooltip");
|
||||||
setNodeTools(settings.value.nodeDashboard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeLevels(calls: Call[], nodeList: Node[], levels: any[]) {
|
function computeLevels(calls: Call[], nodeList: Node[], levels: any[]) {
|
||||||
@ -416,41 +399,7 @@ limitations under the License. -->
|
|||||||
.html(tipHtml);
|
.html(tipHtml);
|
||||||
}
|
}
|
||||||
function showLinkTip(event: MouseEvent, data: Call) {
|
function showLinkTip(event: MouseEvent, data: Call) {
|
||||||
const linkClientMetrics: string[] =
|
const html = `<div><span class="grey">${t("detectPoint")}:</span>${data.detectPoints.join(" | ")}</div>`;
|
||||||
settings.value.metricMode === MetricModes.Expression
|
|
||||||
? settings.value.linkClientExpressions
|
|
||||||
: settings.value.linkClientMetrics || [];
|
|
||||||
const linkServerMetricConfig: MetricConfigOpt[] = settings.value.linkServerMetricConfig || [];
|
|
||||||
const linkClientMetricConfig: MetricConfigOpt[] = settings.value.linkClientMetricConfig || [];
|
|
||||||
const linkServerMetrics: string[] =
|
|
||||||
settings.value.metricMode === MetricModes.Expression
|
|
||||||
? settings.value.linkServerExpressions
|
|
||||||
: settings.value.linkServerMetrics || [];
|
|
||||||
const htmlServer = linkServerMetrics.map((m, index) => {
|
|
||||||
const metric = topologyStore.linkServerMetrics[m].values.find(
|
|
||||||
(val: { id: string; value: unknown }) => val.id === data.id,
|
|
||||||
);
|
|
||||||
if (metric) {
|
|
||||||
const opt: MetricConfigOpt = linkServerMetricConfig[index] || {};
|
|
||||||
const v = aggregation(metric.value, opt);
|
|
||||||
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${v} ${opt.unit || ""}</div>`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const htmlClient = linkClientMetrics.map((m: string, index: number) => {
|
|
||||||
const opt: MetricConfigOpt = linkClientMetricConfig[index] || {};
|
|
||||||
const metric = topologyStore.linkClientMetrics[m].values.find(
|
|
||||||
(val: { id: string; value: unknown }) => val.id === data.id,
|
|
||||||
);
|
|
||||||
if (metric) {
|
|
||||||
const v = aggregation(metric.value, opt);
|
|
||||||
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${v} ${opt.unit || ""}</div>`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const html = [
|
|
||||||
...htmlServer,
|
|
||||||
...htmlClient,
|
|
||||||
`<div><span class="grey">${t("detectPoint")}:</span>${data.detectPoints.join(" | ")}</div>`,
|
|
||||||
].join(" ");
|
|
||||||
|
|
||||||
tooltip.value
|
tooltip.value
|
||||||
.style("top", event.offsetY + "px")
|
.style("top", event.offsetY + "px")
|
||||||
@ -467,69 +416,7 @@ limitations under the License. -->
|
|||||||
hideTip();
|
hideTip();
|
||||||
topologyStore.setNode(d);
|
topologyStore.setNode(d);
|
||||||
topologyStore.setLink(null);
|
topologyStore.setLink(null);
|
||||||
operationsPos.x = event.offsetX;
|
handleGoDashboard(d.name);
|
||||||
operationsPos.y = event.offsetY;
|
|
||||||
if (d.layer === String(dashboardStore.layerId)) {
|
|
||||||
setNodeTools(settings.value.nodeDashboard);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
items.value = [
|
|
||||||
{ id: "inspect", title: "Inspect", func: handleInspect },
|
|
||||||
{ id: "alerting", title: "Alerting", func: handleGoAlerting },
|
|
||||||
];
|
|
||||||
}
|
|
||||||
function handleLinkClick(event: MouseEvent, d: Call) {
|
|
||||||
event.stopPropagation();
|
|
||||||
if (d.sourceObj.layer !== dashboardStore.layerId || d.targetObj.layer !== dashboardStore.layerId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
topologyStore.setNode(null);
|
|
||||||
topologyStore.setLink(d);
|
|
||||||
if (!settings.value.linkDashboard) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const origin = dashboardStore.entity;
|
|
||||||
const e = dashboardStore.entity === EntityType[1].value ? EntityType[0].value : dashboardStore.entity;
|
|
||||||
const { dashboard } = getDashboard({
|
|
||||||
name: settings.value.linkDashboard,
|
|
||||||
layer: dashboardStore.layerId,
|
|
||||||
entity: `${e}Relation`,
|
|
||||||
});
|
|
||||||
if (!dashboard) {
|
|
||||||
ElMessage.error(`The dashboard named ${settings.value.linkDashboard} doesn't exist`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dashboardStore.setEntity(dashboard.entity);
|
|
||||||
const path = `/dashboard/related/${dashboard.layer}/${e}Relation/${d.sourceObj.id}/${d.targetObj.id}/${dashboard.name}`;
|
|
||||||
const routeUrl = router.resolve({ path });
|
|
||||||
window.open(routeUrl.href, "_blank");
|
|
||||||
dashboardStore.setEntity(origin);
|
|
||||||
}
|
|
||||||
async function handleInspect() {
|
|
||||||
const id = topologyStore.node.id;
|
|
||||||
loading.value = true;
|
|
||||||
const resp = await topologyStore.getDepthServiceTopology([id], Number(depth.value));
|
|
||||||
loading.value = false;
|
|
||||||
if (resp && resp.errors) {
|
|
||||||
ElMessage.error(resp.errors);
|
|
||||||
}
|
|
||||||
await update();
|
|
||||||
topologyStore.setNode(null);
|
|
||||||
topologyStore.setLink(null);
|
|
||||||
}
|
|
||||||
function handleGoEndpoint(name: string) {
|
|
||||||
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[2].value}/${topologyStore.node.id}/${name}`;
|
|
||||||
const routeUrl = router.resolve({ path });
|
|
||||||
|
|
||||||
window.open(routeUrl.href, "_blank");
|
|
||||||
dashboardStore.setEntity(origin);
|
|
||||||
}
|
|
||||||
function handleGoInstance(name: string) {
|
|
||||||
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${topologyStore.node.id}/${name}`;
|
|
||||||
const routeUrl = router.resolve({ path });
|
|
||||||
|
|
||||||
window.open(routeUrl.href, "_blank");
|
|
||||||
dashboardStore.setEntity(origin);
|
|
||||||
}
|
}
|
||||||
function handleGoDashboard(name: string) {
|
function handleGoDashboard(name: string) {
|
||||||
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${topologyStore.node.id}/${name}`;
|
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${topologyStore.node.id}/${name}`;
|
||||||
@ -544,22 +431,12 @@ limitations under the License. -->
|
|||||||
|
|
||||||
window.open(routeUrl.href, "_blank");
|
window.open(routeUrl.href, "_blank");
|
||||||
}
|
}
|
||||||
async function backToTopology() {
|
|
||||||
loading.value = true;
|
|
||||||
await freshNodes();
|
|
||||||
topologyStore.setNode(null);
|
|
||||||
topologyStore.setLink(null);
|
|
||||||
}
|
|
||||||
async function getTopology() {
|
async function getTopology() {
|
||||||
const ids = selectorStore.services.map((d: Service) => d.id);
|
const ids = selectorStore.services.map((d: Service) => d.id);
|
||||||
const serviceIds = dashboardStore.entity === EntityType[0].value ? [selectorStore.currentService.id] : ids;
|
const serviceIds = dashboardStore.entity === EntityType[0].value ? [selectorStore.currentService.id] : ids;
|
||||||
const resp = await topologyStore.getDepthServiceTopology(serviceIds, Number(depth.value));
|
const resp = await topologyStore.getDepthServiceTopology(serviceIds, Number(depth.value));
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
function setConfig() {
|
|
||||||
showSetting.value = !showSetting.value;
|
|
||||||
dashboardStore.selectWidget(props.config);
|
|
||||||
}
|
|
||||||
function resize() {
|
function resize() {
|
||||||
const dom = document.querySelector(".topology")?.getBoundingClientRect() || {
|
const dom = document.querySelector(".topology")?.getBoundingClientRect() || {
|
||||||
height: 40,
|
height: 40,
|
||||||
@ -568,45 +445,6 @@ limitations under the License. -->
|
|||||||
height.value = dom.height - 40;
|
height.value = dom.height - 40;
|
||||||
width.value = dom.width;
|
width.value = dom.width;
|
||||||
}
|
}
|
||||||
function updateSettings(config: any) {
|
|
||||||
settings.value = config;
|
|
||||||
setNodeTools(config.nodeDashboard);
|
|
||||||
}
|
|
||||||
function setNodeTools(nodeDashboard: any) {
|
|
||||||
items.value = [
|
|
||||||
{ id: "inspect", title: "Inspect", func: handleInspect },
|
|
||||||
{ id: "alerting", title: "Alerting", func: handleGoAlerting },
|
|
||||||
];
|
|
||||||
if (!(nodeDashboard && nodeDashboard.length)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const item of nodeDashboard) {
|
|
||||||
if (item.scope === EntityType[0].value) {
|
|
||||||
items.value.push({
|
|
||||||
id: "dashboard",
|
|
||||||
title: "Service Dashboard",
|
|
||||||
func: handleGoDashboard,
|
|
||||||
...item,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (item.scope === EntityType[2].value) {
|
|
||||||
items.value.push({
|
|
||||||
id: "endpoint",
|
|
||||||
title: "Endpoint Dashboard",
|
|
||||||
func: handleGoEndpoint,
|
|
||||||
...item,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (item.scope === EntityType[3].value) {
|
|
||||||
items.value.push({
|
|
||||||
id: "instance",
|
|
||||||
title: "Service Instance Dashboard",
|
|
||||||
func: handleGoInstance,
|
|
||||||
...item,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function svgEvent() {
|
function svgEvent() {
|
||||||
topologyStore.setNode(null);
|
topologyStore.setNode(null);
|
||||||
topologyStore.setLink(null);
|
topologyStore.setLink(null);
|
||||||
@ -637,8 +475,8 @@ limitations under the License. -->
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.micro-topo-chart {
|
.hierarchy-services-topo {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
@ -658,7 +496,7 @@ limitations under the License. -->
|
|||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-topology {
|
.hierarchy-services-svg {
|
||||||
cursor: move;
|
cursor: move;
|
||||||
background-color: $layout-background;
|
background-color: $layout-background;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user