mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-02 09:54:01 +00:00
feat: save and init topology templates (#32)
This commit is contained in:
parent
f1e405fbb4
commit
f9aacb72e1
@ -23,6 +23,8 @@ import { useSelectorStore } from "@/store/modules/selectors";
|
|||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import query from "@/graphql/fetch";
|
import query from "@/graphql/fetch";
|
||||||
|
import { useQueryTopologyMetrics } from "@/hooks/useProcessor";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
interface MetricVal {
|
interface MetricVal {
|
||||||
[key: string]: { values: { id: string; value: unknown }[] };
|
[key: string]: { values: { id: string; value: unknown }[] };
|
||||||
@ -32,7 +34,7 @@ interface TopologyState {
|
|||||||
call: Nullable<Call>;
|
call: Nullable<Call>;
|
||||||
calls: Call[];
|
calls: Call[];
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
nodeMetrics: MetricVal;
|
nodeMetricValue: MetricVal;
|
||||||
linkServerMetrics: MetricVal;
|
linkServerMetrics: MetricVal;
|
||||||
linkClientMetrics: MetricVal;
|
linkClientMetrics: MetricVal;
|
||||||
}
|
}
|
||||||
@ -44,7 +46,7 @@ export const topologyStore = defineStore({
|
|||||||
nodes: [],
|
nodes: [],
|
||||||
node: null,
|
node: null,
|
||||||
call: null,
|
call: null,
|
||||||
nodeMetrics: {},
|
nodeMetricValue: {},
|
||||||
linkServerMetrics: {},
|
linkServerMetrics: {},
|
||||||
linkClientMetrics: {},
|
linkClientMetrics: {},
|
||||||
}),
|
}),
|
||||||
@ -103,8 +105,8 @@ export const topologyStore = defineStore({
|
|||||||
this.calls = calls;
|
this.calls = calls;
|
||||||
this.nodes = nodes;
|
this.nodes = nodes;
|
||||||
},
|
},
|
||||||
setNodeMetrics(m: { id: string; value: unknown }[]) {
|
setNodeMetricValue(m: { id: string; value: unknown }[]) {
|
||||||
this.nodeMetrics = m;
|
this.nodeMetricValue = m;
|
||||||
},
|
},
|
||||||
setLinkServerMetrics(m: { id: string; value: unknown }[]) {
|
setLinkServerMetrics(m: { id: string; value: unknown }[]) {
|
||||||
this.linkServerMetrics = m;
|
this.linkServerMetrics = m;
|
||||||
@ -388,7 +390,7 @@ export const topologyStore = defineStore({
|
|||||||
|
|
||||||
return { calls, nodes };
|
return { calls, nodes };
|
||||||
},
|
},
|
||||||
async getNodeMetrics(param: {
|
async getNodeMetricValue(param: {
|
||||||
queryStr: string;
|
queryStr: string;
|
||||||
conditions: { [key: string]: unknown };
|
conditions: { [key: string]: unknown };
|
||||||
}) {
|
}) {
|
||||||
@ -397,9 +399,52 @@ export const topologyStore = defineStore({
|
|||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.setNodeMetrics(res.data.data);
|
this.setNodeMetricValue(res.data.data);
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
async getLinkClientMetrics(linkClientMetrics: string[]) {
|
||||||
|
if (!linkClientMetrics.length) {
|
||||||
|
this.setLinkClientMetrics({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const idsC = this.calls
|
||||||
|
.filter((i: Call) => i.detectPoints.includes("CLIENT"))
|
||||||
|
.map((b: Call) => b.id);
|
||||||
|
const param = await useQueryTopologyMetrics(linkClientMetrics, idsC);
|
||||||
|
const res = await this.getCallClientMetrics(param);
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getLinkServerMetrics(linkServerMetrics: string[]) {
|
||||||
|
if (!linkServerMetrics.length) {
|
||||||
|
this.setLinkServerMetrics({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const idsS = this.calls
|
||||||
|
.filter((i: Call) => i.detectPoints.includes("SERVER"))
|
||||||
|
.map((b: Call) => b.id);
|
||||||
|
const param = await useQueryTopologyMetrics(linkServerMetrics, idsS);
|
||||||
|
const res = await this.getCallServerMetrics(param);
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async queryNodeMetrics(nodeMetrics: string[]) {
|
||||||
|
if (!nodeMetrics.length) {
|
||||||
|
this.setNodeMetricValue({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ids = this.nodes.map((d: Node) => d.id);
|
||||||
|
const param = await useQueryTopologyMetrics(nodeMetrics, ids);
|
||||||
|
const res = await this.getNodeMetricValue(param);
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
},
|
||||||
async getLegendMetrics(param: {
|
async getLegendMetrics(param: {
|
||||||
queryStr: string;
|
queryStr: string;
|
||||||
conditions: { [key: string]: unknown };
|
conditions: { [key: string]: unknown };
|
||||||
|
@ -46,7 +46,9 @@ limitations under the License. -->
|
|||||||
<el-table-column type="selection" width="55" />
|
<el-table-column type="selection" width="55" />
|
||||||
<el-table-column prop="name" label="Name">
|
<el-table-column prop="name" label="Name">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span @click="handleView(scope.row)">{{ scope.row.name }}</span>
|
<span class="cp" @click="handleView(scope.row)">{{
|
||||||
|
scope.row.name
|
||||||
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="layer" label="Layer" width="200" />
|
<el-table-column prop="layer" label="Layer" width="200" />
|
||||||
|
@ -53,8 +53,9 @@ limitations under the License. -->
|
|||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
class="cp mr-5"
|
class="cp mr-5"
|
||||||
v-show="
|
v-if="
|
||||||
index === states.metrics.length - 1 && states.metrics.length < 5
|
index === states.metrics.length - 1 &&
|
||||||
|
states.metrics.length < defaultLen
|
||||||
"
|
"
|
||||||
iconName="add_circle_outlinecontrol_point"
|
iconName="add_circle_outlinecontrol_point"
|
||||||
size="middle"
|
size="middle"
|
||||||
@ -84,7 +85,7 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive } from "vue";
|
import { reactive, ref } from "vue";
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import {
|
import {
|
||||||
@ -128,6 +129,7 @@ const states = reactive<{
|
|||||||
});
|
});
|
||||||
|
|
||||||
states.isList = ListChartTypes.includes(graph.type);
|
states.isList = ListChartTypes.includes(graph.type);
|
||||||
|
const defaultLen = ref<number>(states.isList ? 5 : 10);
|
||||||
states.visTypes = setVisTypes();
|
states.visTypes = setVisTypes();
|
||||||
|
|
||||||
setDashboards();
|
setDashboards();
|
||||||
@ -241,10 +243,12 @@ function changeChartType(item: Option) {
|
|||||||
});
|
});
|
||||||
states.metrics = [""];
|
states.metrics = [""];
|
||||||
states.metricTypes = [""];
|
states.metricTypes = [""];
|
||||||
|
defaultLen.value = 5;
|
||||||
}
|
}
|
||||||
setMetricType();
|
setMetricType();
|
||||||
setDashboards();
|
setDashboards();
|
||||||
states.dashboardName = "";
|
states.dashboardName = "";
|
||||||
|
defaultLen.value = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeMetrics(
|
function changeMetrics(
|
||||||
|
@ -35,7 +35,7 @@ limitations under the License. -->
|
|||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span
|
<span
|
||||||
class="link"
|
class="link"
|
||||||
@click="clickEndpoint"
|
@click="clickEndpoint(scope)"
|
||||||
:style="{ fontSize: `${config.fontSize}px` }"
|
:style="{ fontSize: `${config.fontSize}px` }"
|
||||||
>
|
>
|
||||||
{{ scope.row.label }}
|
{{ scope.row.label }}
|
||||||
|
@ -35,7 +35,7 @@ limitations under the License. -->
|
|||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span
|
<span
|
||||||
class="link"
|
class="link"
|
||||||
@click="clickInstance"
|
@click="clickInstance(scope)"
|
||||||
:style="{ fontSize: `${config.fontSize}px` }"
|
:style="{ fontSize: `${config.fontSize}px` }"
|
||||||
>
|
>
|
||||||
{{ scope.row.label }}
|
{{ scope.row.label }}
|
||||||
|
@ -13,12 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<PodTopology :config="config" v-if="isSankey" />
|
<Graph :config="config" v-if="isService" />
|
||||||
<Graph :config="config" v-else />
|
<PodTopology :config="config" v-else />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { ref } from "vue";
|
|
||||||
import Graph from "./components/Graph.vue";
|
import Graph from "./components/Graph.vue";
|
||||||
import PodTopology from "./components/PodTopology.vue";
|
import PodTopology from "./components/PodTopology.vue";
|
||||||
import { EntityType } from "../../data";
|
import { EntityType } from "../../data";
|
||||||
@ -32,7 +31,7 @@ defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const isSankey = ref<boolean>(
|
const isService = [EntityType[0].value, EntityType[1].value].includes(
|
||||||
[EntityType[2].value, EntityType[3].value].includes(dashboardStore.entity)
|
dashboardStore.entity
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
@ -20,7 +20,7 @@ limitations under the License. -->
|
|||||||
element-loading-background="rgba(0, 0, 0, 0)"
|
element-loading-background="rgba(0, 0, 0, 0)"
|
||||||
:style="`height: ${height}px`"
|
:style="`height: ${height}px`"
|
||||||
>
|
>
|
||||||
<div class="setting" v-show="showSetting">
|
<div class="setting" v-if="showSetting">
|
||||||
<Settings @update="updateSettings" @updateNodes="freshNodes" />
|
<Settings @update="updateSettings" @updateNodes="freshNodes" />
|
||||||
</div>
|
</div>
|
||||||
<div class="tool">
|
<div class="tool">
|
||||||
@ -34,7 +34,12 @@ limitations under the License. -->
|
|||||||
@change="changeDepth"
|
@change="changeDepth"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="switch-icon ml-5" title="Settings" @click="setConfig">
|
<span
|
||||||
|
class="switch-icon ml-5"
|
||||||
|
title="Settings"
|
||||||
|
@click="setConfig"
|
||||||
|
v-if="dashboardStore.editMode"
|
||||||
|
>
|
||||||
<Icon size="middle" iconName="settings" />
|
<Icon size="middle" iconName="settings" />
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
@ -113,14 +118,11 @@ const anchor = ref<any>(null);
|
|||||||
const arrow = ref<any>(null);
|
const arrow = ref<any>(null);
|
||||||
const legend = ref<any>(null);
|
const legend = ref<any>(null);
|
||||||
const showSetting = ref<boolean>(false);
|
const showSetting = ref<boolean>(false);
|
||||||
const settings = ref<any>({});
|
const settings = ref<any>(props.config);
|
||||||
const operationsPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
|
const operationsPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
|
||||||
const items = ref<
|
const items = ref<
|
||||||
{ id: string; title: string; func: any; dashboard?: string }[]
|
{ id: string; title: string; func: any; dashboard?: string }[]
|
||||||
>([
|
>([]);
|
||||||
{ id: "inspect", title: "Inspect", func: handleInspect },
|
|
||||||
{ id: "alarm", title: "Alarm", func: handleGoAlarm },
|
|
||||||
]);
|
|
||||||
const depth = ref<number>(props.config.graph.depth || 2);
|
const depth = ref<number>(props.config.graph.depth || 2);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
@ -130,6 +132,9 @@ onMounted(async () => {
|
|||||||
if (resp && resp.errors) {
|
if (resp && resp.errors) {
|
||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
}
|
}
|
||||||
|
topologyStore.getLinkClientMetrics(settings.value.linkClientMetrics || []);
|
||||||
|
topologyStore.getLinkServerMetrics(settings.value.linkServerMetrics || []);
|
||||||
|
topologyStore.queryNodeMetrics(settings.value.nodeMetrics || []);
|
||||||
const dom = document.querySelector(".topology")?.getBoundingClientRect() || {
|
const dom = document.querySelector(".topology")?.getBoundingClientRect() || {
|
||||||
height: 40,
|
height: 40,
|
||||||
width: 0,
|
width: 0,
|
||||||
@ -140,6 +145,7 @@ onMounted(async () => {
|
|||||||
svg.value = d3.select(chart.value).append("svg").attr("class", "topo-svg");
|
svg.value = d3.select(chart.value).append("svg").attr("class", "topo-svg");
|
||||||
await init();
|
await init();
|
||||||
update();
|
update();
|
||||||
|
setNodeTools(settings.value.nodeDashboard);
|
||||||
});
|
});
|
||||||
async function init() {
|
async function init() {
|
||||||
tip.value = (d3tip as any)().attr("class", "d3-tip").offset([-8, 0]);
|
tip.value = (d3tip as any)().attr("class", "d3-tip").offset([-8, 0]);
|
||||||
@ -167,6 +173,7 @@ async function init() {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
topologyStore.setNode(null);
|
topologyStore.setNode(null);
|
||||||
topologyStore.setLink(null);
|
topologyStore.setLink(null);
|
||||||
|
dashboardStore.selectWidget(props.config);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function ticked() {
|
function ticked() {
|
||||||
@ -236,6 +243,7 @@ function handleLinkClick(event: any, d: Call) {
|
|||||||
if (!settings.value.linkDashboard) {
|
if (!settings.value.linkDashboard) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const origin = dashboardStore.entity;
|
||||||
const e =
|
const e =
|
||||||
dashboardStore.entity === EntityType[1].value
|
dashboardStore.entity === EntityType[1].value
|
||||||
? EntityType[0].value
|
? EntityType[0].value
|
||||||
@ -251,6 +259,7 @@ function handleLinkClick(event: any, d: Call) {
|
|||||||
}/${p.name.split(" ").join("-")}`;
|
}/${p.name.split(" ").join("-")}`;
|
||||||
const routeUrl = router.resolve({ path });
|
const routeUrl = router.resolve({ path });
|
||||||
window.open(routeUrl.href, "_blank");
|
window.open(routeUrl.href, "_blank");
|
||||||
|
dashboardStore.setEntity(origin);
|
||||||
}
|
}
|
||||||
function update() {
|
function update() {
|
||||||
// node element
|
// node element
|
||||||
@ -271,7 +280,7 @@ function update() {
|
|||||||
const nodeMetrics: string[] = settings.value.nodeMetrics || [];
|
const nodeMetrics: string[] = settings.value.nodeMetrics || [];
|
||||||
const html = nodeMetrics.map((m) => {
|
const html = nodeMetrics.map((m) => {
|
||||||
const metric =
|
const metric =
|
||||||
topologyStore.nodeMetrics[m].values.filter(
|
topologyStore.nodeMetricValue[m].values.filter(
|
||||||
(val: { id: string; value: unknown }) => val.id === data.id
|
(val: { id: string; value: unknown }) => val.id === data.id
|
||||||
)[0] || {};
|
)[0] || {};
|
||||||
const val = m.includes("_sla") ? metric.value / 100 : metric.value;
|
const val = m.includes("_sla") ? metric.value / 100 : metric.value;
|
||||||
@ -380,6 +389,7 @@ async function handleInspect() {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
function handleGoEndpoint(name: string) {
|
function handleGoEndpoint(name: string) {
|
||||||
|
const origin = dashboardStore.entity;
|
||||||
const p = getDashboard({
|
const p = getDashboard({
|
||||||
name,
|
name,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
@ -392,8 +402,10 @@ function handleGoEndpoint(name: string) {
|
|||||||
const routeUrl = router.resolve({ path });
|
const routeUrl = router.resolve({ path });
|
||||||
|
|
||||||
window.open(routeUrl.href, "_blank");
|
window.open(routeUrl.href, "_blank");
|
||||||
|
dashboardStore.setEntity(origin);
|
||||||
}
|
}
|
||||||
function handleGoInstance(name: string) {
|
function handleGoInstance(name: string) {
|
||||||
|
const origin = dashboardStore.entity;
|
||||||
const p = getDashboard({
|
const p = getDashboard({
|
||||||
name,
|
name,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
@ -406,8 +418,10 @@ function handleGoInstance(name: string) {
|
|||||||
const routeUrl = router.resolve({ path });
|
const routeUrl = router.resolve({ path });
|
||||||
|
|
||||||
window.open(routeUrl.href, "_blank");
|
window.open(routeUrl.href, "_blank");
|
||||||
|
dashboardStore.setEntity(origin);
|
||||||
}
|
}
|
||||||
function handleGoDashboard(name: string) {
|
function handleGoDashboard(name: string) {
|
||||||
|
const origin = dashboardStore.entity;
|
||||||
const p = getDashboard({
|
const p = getDashboard({
|
||||||
name,
|
name,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
@ -420,6 +434,7 @@ function handleGoDashboard(name: string) {
|
|||||||
const routeUrl = router.resolve({ path });
|
const routeUrl = router.resolve({ path });
|
||||||
|
|
||||||
window.open(routeUrl.href, "_blank");
|
window.open(routeUrl.href, "_blank");
|
||||||
|
dashboardStore.setEntity(origin);
|
||||||
}
|
}
|
||||||
function handleGoAlarm() {
|
function handleGoAlarm() {
|
||||||
const path = `/alarm`;
|
const path = `/alarm`;
|
||||||
@ -455,6 +470,7 @@ async function getTopology() {
|
|||||||
}
|
}
|
||||||
function setConfig() {
|
function setConfig() {
|
||||||
showSetting.value = !showSetting.value;
|
showSetting.value = !showSetting.value;
|
||||||
|
dashboardStore.selectWidget(props.config);
|
||||||
}
|
}
|
||||||
function resize() {
|
function resize() {
|
||||||
height.value = document.body.clientHeight;
|
height.value = document.body.clientHeight;
|
||||||
@ -462,16 +478,19 @@ function resize() {
|
|||||||
svg.value.attr("height", height.value).attr("width", width.value);
|
svg.value.attr("height", height.value).attr("width", width.value);
|
||||||
}
|
}
|
||||||
function updateSettings(config: any) {
|
function updateSettings(config: any) {
|
||||||
|
settings.value = config;
|
||||||
|
setNodeTools(config.nodeDashboard);
|
||||||
|
}
|
||||||
|
function setNodeTools(nodeDashboard: any) {
|
||||||
items.value = [
|
items.value = [
|
||||||
{ id: "inspect", title: "Inspect", func: handleInspect },
|
{ id: "inspect", title: "Inspect", func: handleInspect },
|
||||||
{ id: "alarm", title: "Alarm", func: handleGoAlarm },
|
{ id: "alarm", title: "Alarm", func: handleGoAlarm },
|
||||||
];
|
];
|
||||||
settings.value = config;
|
for (const item of nodeDashboard) {
|
||||||
for (const item of config.nodeDashboard) {
|
|
||||||
if (item.scope === EntityType[0].value) {
|
if (item.scope === EntityType[0].value) {
|
||||||
items.value.push({
|
items.value.push({
|
||||||
id: "dashboard",
|
id: "dashboard",
|
||||||
title: "Dashboard",
|
title: "Service Dashboard",
|
||||||
func: handleGoDashboard,
|
func: handleGoDashboard,
|
||||||
...item,
|
...item,
|
||||||
});
|
});
|
||||||
@ -479,7 +498,7 @@ function updateSettings(config: any) {
|
|||||||
if (item.scope === EntityType[2].value) {
|
if (item.scope === EntityType[2].value) {
|
||||||
items.value.push({
|
items.value.push({
|
||||||
id: "endpoint",
|
id: "endpoint",
|
||||||
title: "Endpoint",
|
title: "Endpoint Dashboard",
|
||||||
func: handleGoEndpoint,
|
func: handleGoEndpoint,
|
||||||
...item,
|
...item,
|
||||||
});
|
});
|
||||||
@ -487,7 +506,7 @@ function updateSettings(config: any) {
|
|||||||
if (item.scope === EntityType[3].value) {
|
if (item.scope === EntityType[3].value) {
|
||||||
items.value.push({
|
items.value.push({
|
||||||
id: "instance",
|
id: "instance",
|
||||||
title: "Service Instance",
|
title: "Service Instance Dashboard",
|
||||||
func: handleGoInstance,
|
func: handleGoInstance,
|
||||||
...item,
|
...item,
|
||||||
});
|
});
|
||||||
@ -567,7 +586,6 @@ watch(
|
|||||||
span {
|
span {
|
||||||
display: block;
|
display: block;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 140px;
|
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,12 @@ limitations under the License. -->
|
|||||||
@change="changeDepth"
|
@change="changeDepth"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="switch-icon ml-5" title="Settings" @click="setConfig">
|
<span
|
||||||
|
class="switch-icon ml-5"
|
||||||
|
title="Settings"
|
||||||
|
@click="setConfig"
|
||||||
|
v-if="dashboardStore.editMode"
|
||||||
|
>
|
||||||
<Icon size="middle" iconName="settings" />
|
<Icon size="middle" iconName="settings" />
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
@ -38,7 +43,7 @@ limitations under the License. -->
|
|||||||
>
|
>
|
||||||
<Icon size="middle" iconName="keyboard_backspace" />
|
<Icon size="middle" iconName="keyboard_backspace" />
|
||||||
</span>
|
</span>
|
||||||
<div class="settings" v-show="showSettings">
|
<div class="settings" v-if="showSettings">
|
||||||
<Settings @update="updateConfig" />
|
<Settings @update="updateConfig" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -104,7 +109,7 @@ const loading = ref<boolean>(false);
|
|||||||
const height = ref<number>(100);
|
const height = ref<number>(100);
|
||||||
const width = ref<number>(100);
|
const width = ref<number>(100);
|
||||||
const showSettings = ref<boolean>(false);
|
const showSettings = ref<boolean>(false);
|
||||||
const settings = ref<any>({});
|
const settings = ref<any>(props.config);
|
||||||
const operationsPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
|
const operationsPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
|
||||||
const depth = ref<number>(props.config.graph.depth || 3);
|
const depth = ref<number>(props.config.graph.depth || 3);
|
||||||
const items = [
|
const items = [
|
||||||
@ -130,6 +135,9 @@ async function loadTopology(id: string) {
|
|||||||
};
|
};
|
||||||
height.value = dom.height - 70;
|
height.value = dom.height - 70;
|
||||||
width.value = dom.width - 5;
|
width.value = dom.width - 5;
|
||||||
|
topologyStore.getLinkClientMetrics(settings.value.linkClientMetrics || []);
|
||||||
|
topologyStore.getLinkServerMetrics(settings.value.linkServerMetrics || []);
|
||||||
|
topologyStore.queryNodeMetrics(settings.value.nodeMetrics || []);
|
||||||
}
|
}
|
||||||
|
|
||||||
function inspect() {
|
function inspect() {
|
||||||
@ -158,7 +166,9 @@ function goDashboard() {
|
|||||||
});
|
});
|
||||||
dashboardStore.setEntity(entity);
|
dashboardStore.setEntity(entity);
|
||||||
dashboardStore.setCurrentDashboard(d);
|
dashboardStore.setCurrentDashboard(d);
|
||||||
const path = `/dashboard/${d.layer}/${entity}/${topologyStore.node.serviceId}/${topologyStore.node.id}/${d.name}`;
|
const path = `/dashboard/${d.layer}/${entity}/${
|
||||||
|
topologyStore.node.serviceId
|
||||||
|
}/${topologyStore.node.id}/${d.name.split(" ").join("-")}`;
|
||||||
const routeUrl = router.resolve({ path });
|
const routeUrl = router.resolve({ path });
|
||||||
window.open(routeUrl.href, "_blank");
|
window.open(routeUrl.href, "_blank");
|
||||||
topologyStore.setNode(null);
|
topologyStore.setNode(null);
|
||||||
@ -167,6 +177,7 @@ function goDashboard() {
|
|||||||
function setConfig() {
|
function setConfig() {
|
||||||
topologyStore.setNode(null);
|
topologyStore.setNode(null);
|
||||||
showSettings.value = !showSettings.value;
|
showSettings.value = !showSettings.value;
|
||||||
|
dashboardStore.selectWidget(props.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateConfig(config: any) {
|
function updateConfig(config: any) {
|
||||||
@ -196,7 +207,9 @@ function selectNodeLink(d: any) {
|
|||||||
entity,
|
entity,
|
||||||
});
|
});
|
||||||
dashboardStore.setEntity(entity);
|
dashboardStore.setEntity(entity);
|
||||||
const path = `/dashboard/${p.layer}/${entity}/${sourceObj.serviceId}/${sourceObj.id}/${targetObj.serviceId}/${targetObj.id}/${p.name}`;
|
const path = `/dashboard/${p.layer}/${entity}/${sourceObj.serviceId}/${
|
||||||
|
sourceObj.id
|
||||||
|
}/${targetObj.serviceId}/${targetObj.id}/${p.name.split(" ").join("-")}`;
|
||||||
const routeUrl = router.resolve({ path });
|
const routeUrl = router.resolve({ path });
|
||||||
window.open(routeUrl.href, "_blank");
|
window.open(routeUrl.href, "_blank");
|
||||||
return;
|
return;
|
||||||
@ -221,7 +234,7 @@ async function getTopology(id: string) {
|
|||||||
Number(depth.value)
|
Number(depth.value)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case EntityType[3].value:
|
case EntityType[4].value:
|
||||||
resp = await topologyStore.getInstanceTopology();
|
resp = await topologyStore.getInstanceTopology();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -231,6 +244,7 @@ function handleClick(event: any) {
|
|||||||
if (event.target.nodeName === "svg") {
|
if (event.target.nodeName === "svg") {
|
||||||
topologyStore.setNode(null);
|
topologyStore.setNode(null);
|
||||||
topologyStore.setLink(null);
|
topologyStore.setLink(null);
|
||||||
|
dashboardStore.selectWidget(props.config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
watch(
|
watch(
|
||||||
@ -262,10 +276,10 @@ watch(
|
|||||||
top: 60px;
|
top: 60px;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
height: 500px;
|
height: 600px;
|
||||||
background-color: #2b3037;
|
background-color: #2b3037;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 0 15px;
|
padding: 10px 15px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
transition: all 0.5ms linear;
|
transition: all 0.5ms linear;
|
||||||
|
@ -105,10 +105,10 @@ function linkTooltip(data: Call) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function nodeTooltip(data: Node) {
|
function nodeTooltip(data: Node) {
|
||||||
const nodeMetrics: string[] = Object.keys(topologyStore.nodeMetrics);
|
const nodeMetrics: string[] = Object.keys(topologyStore.nodeMetricValue);
|
||||||
const html = nodeMetrics.map((m) => {
|
const html = nodeMetrics.map((m) => {
|
||||||
const metric =
|
const metric =
|
||||||
topologyStore.nodeMetrics[m].values.filter(
|
topologyStore.nodeMetricValue[m].values.filter(
|
||||||
(val: { id: string; value: unknown }) => val.id === data.id
|
(val: { id: string; value: unknown }) => val.id === data.id
|
||||||
)[0] || {};
|
)[0] || {};
|
||||||
const val = m.includes("_sla") ? metric.value / 100 : metric.value;
|
const val = m.includes("_sla") ? metric.value / 100 : metric.value;
|
||||||
|
@ -186,7 +186,7 @@ import { ElMessage } from "element-plus";
|
|||||||
import { MetricCatalog, ScopeType, MetricConditions } from "../../../data";
|
import { MetricCatalog, ScopeType, MetricConditions } from "../../../data";
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import { useQueryTopologyMetrics } from "@/hooks/useProcessor";
|
import { useQueryTopologyMetrics } from "@/hooks/useProcessor";
|
||||||
import { Node, Call } from "@/types/topology";
|
import { Node } from "@/types/topology";
|
||||||
import { DashboardItem } from "@/types/dashboard";
|
import { DashboardItem } from "@/types/dashboard";
|
||||||
import { EntityType, LegendOpt, MetricsType } from "../../../data";
|
import { EntityType, LegendOpt, MetricsType } from "../../../data";
|
||||||
|
|
||||||
@ -195,12 +195,16 @@ const emit = defineEmits(["update", "updateNodes"]);
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const topologyStore = useTopologyStore();
|
const topologyStore = useTopologyStore();
|
||||||
|
const { selectedGrid } = dashboardStore;
|
||||||
|
const isService = [EntityType[0].value, EntityType[1].value].includes(
|
||||||
|
dashboardStore.entity
|
||||||
|
);
|
||||||
const items = reactive<
|
const items = reactive<
|
||||||
{
|
{
|
||||||
scope: string;
|
scope: string;
|
||||||
dashboard: string;
|
dashboard: string;
|
||||||
}[]
|
}[]
|
||||||
>([{ scope: "", dashboard: "" }]);
|
>((isService && selectedGrid.nodeDashboard) || [{ scope: "", dashboard: "" }]);
|
||||||
const states = reactive<{
|
const states = reactive<{
|
||||||
linkDashboard: string;
|
linkDashboard: string;
|
||||||
nodeDashboard: {
|
nodeDashboard: {
|
||||||
@ -215,23 +219,19 @@ const states = reactive<{
|
|||||||
linkDashboards: (DashboardItem & { label: string; value: string })[];
|
linkDashboards: (DashboardItem & { label: string; value: string })[];
|
||||||
nodeDashboards: (DashboardItem & { label: string; value: string })[];
|
nodeDashboards: (DashboardItem & { label: string; value: string })[];
|
||||||
}>({
|
}>({
|
||||||
linkDashboard: "",
|
linkDashboard: selectedGrid.linkDashboard || "",
|
||||||
nodeDashboard: [],
|
nodeDashboard: selectedGrid.nodeDashboard || [],
|
||||||
linkServerMetrics: [],
|
linkServerMetrics: selectedGrid.linkServerMetrics || [],
|
||||||
linkClientMetrics: [],
|
linkClientMetrics: selectedGrid.linkClientMetrics || [],
|
||||||
nodeMetrics: [],
|
nodeMetrics: selectedGrid.nodeMetrics || [],
|
||||||
nodeMetricList: [],
|
nodeMetricList: [],
|
||||||
linkMetricList: [],
|
linkMetricList: [],
|
||||||
linkDashboards: [],
|
linkDashboards: [],
|
||||||
nodeDashboards: [],
|
nodeDashboards: [],
|
||||||
});
|
});
|
||||||
console.log(dashboardStore.selectedGrid);
|
|
||||||
const isService = [EntityType[0].value, EntityType[1].value].includes(
|
|
||||||
dashboardStore.entity
|
|
||||||
);
|
|
||||||
const legend = reactive<{
|
const legend = reactive<{
|
||||||
metric: { name: string; condition: string; value: string }[];
|
metric: { name: string; condition: string; value: string }[];
|
||||||
}>({ metric: [{ name: "", condition: "", value: "" }] });
|
}>({ metric: selectedGrid.legend || [{ name: "", condition: "", value: "" }] });
|
||||||
|
|
||||||
getMetricList();
|
getMetricList();
|
||||||
async function getMetricList() {
|
async function getMetricList() {
|
||||||
@ -270,24 +270,26 @@ async function getMetricList() {
|
|||||||
entity + "Relation" === (MetricCatalog as any)[d.catalog] &&
|
entity + "Relation" === (MetricCatalog as any)[d.catalog] &&
|
||||||
d.type === MetricsType.REGULAR_VALUE
|
d.type === MetricsType.REGULAR_VALUE
|
||||||
);
|
);
|
||||||
|
if (isService) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
states.nodeDashboards = list.reduce(
|
||||||
|
(
|
||||||
|
prev: (DashboardItem & { label: string; value: string })[],
|
||||||
|
d: DashboardItem
|
||||||
|
) => {
|
||||||
|
if (d.layer === dashboardStore.layerId && d.entity === entity) {
|
||||||
|
prev.push({ ...d, label: d.name, value: d.name });
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
async function setLegend() {
|
async function setLegend() {
|
||||||
const metrics = legend.metric.filter(
|
updateSettings();
|
||||||
(d: any) => d.name && d.value && d.condition
|
|
||||||
);
|
|
||||||
const names = metrics.map((d: any) => d.name);
|
|
||||||
|
|
||||||
emit("update", {
|
|
||||||
linkDashboard: states.linkDashboard,
|
|
||||||
nodeDashboard: isService
|
|
||||||
? items.filter((d: { scope: string; dashboard: string }) => d.dashboard)
|
|
||||||
: states.nodeDashboard,
|
|
||||||
linkServerMetrics: states.linkServerMetrics,
|
|
||||||
linkClientMetrics: states.linkClientMetrics,
|
|
||||||
nodeMetrics: states.nodeMetrics,
|
|
||||||
legend: metrics,
|
|
||||||
});
|
|
||||||
const ids = topologyStore.nodes.map((d: Node) => d.id);
|
const ids = topologyStore.nodes.map((d: Node) => d.id);
|
||||||
|
const names = dashboardStore.selectedGrid.legend.map((d: any) => d.name);
|
||||||
const param = await useQueryTopologyMetrics(names, ids);
|
const param = await useQueryTopologyMetrics(names, ids);
|
||||||
const res = await topologyStore.getLegendMetrics(param);
|
const res = await topologyStore.getLegendMetrics(param);
|
||||||
|
|
||||||
@ -298,9 +300,11 @@ async function setLegend() {
|
|||||||
}
|
}
|
||||||
function changeNodeDashboard(opt: any) {
|
function changeNodeDashboard(opt: any) {
|
||||||
states.nodeDashboard = opt[0].value;
|
states.nodeDashboard = opt[0].value;
|
||||||
|
updateSettings();
|
||||||
}
|
}
|
||||||
function changeLinkDashboard(opt: any) {
|
function changeLinkDashboard(opt: any) {
|
||||||
states.linkDashboard = opt[0].value;
|
states.linkDashboard = opt[0].value;
|
||||||
|
updateSettings();
|
||||||
}
|
}
|
||||||
function changeLegend(type: string, opt: any, index: number) {
|
function changeLegend(type: string, opt: any, index: number) {
|
||||||
(legend.metric[index] as any)[type] = opt[0].value || opt;
|
(legend.metric[index] as any)[type] = opt[0].value || opt;
|
||||||
@ -321,6 +325,7 @@ function changeScope(index: number, opt: Option[] | any) {
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
items[index].dashboard = states.nodeDashboards[0].value;
|
items[index].dashboard = states.nodeDashboards[0].value;
|
||||||
|
updateSettings();
|
||||||
}
|
}
|
||||||
function updateNodeDashboards(index: number, content: Option[] | any) {
|
function updateNodeDashboards(index: number, content: Option[] | any) {
|
||||||
items[index].dashboard = content[0].value;
|
items[index].dashboard = content[0].value;
|
||||||
@ -334,7 +339,10 @@ function deleteItem(index: number) {
|
|||||||
updateSettings();
|
updateSettings();
|
||||||
}
|
}
|
||||||
function updateSettings() {
|
function updateSettings() {
|
||||||
emit("update", {
|
const metrics = legend.metric.filter(
|
||||||
|
(d: any) => d.name && d.value && d.condition
|
||||||
|
);
|
||||||
|
const param = {
|
||||||
linkDashboard: states.linkDashboard,
|
linkDashboard: states.linkDashboard,
|
||||||
nodeDashboard: isService
|
nodeDashboard: isService
|
||||||
? items.filter((d: { scope: string; dashboard: string }) => d.dashboard)
|
? items.filter((d: { scope: string; dashboard: string }) => d.dashboard)
|
||||||
@ -342,8 +350,11 @@ function updateSettings() {
|
|||||||
linkServerMetrics: states.linkServerMetrics,
|
linkServerMetrics: states.linkServerMetrics,
|
||||||
linkClientMetrics: states.linkClientMetrics,
|
linkClientMetrics: states.linkClientMetrics,
|
||||||
nodeMetrics: states.nodeMetrics,
|
nodeMetrics: states.nodeMetrics,
|
||||||
legend: legend.metric,
|
legend: metrics,
|
||||||
});
|
};
|
||||||
|
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, ...param });
|
||||||
|
dashboardStore.setConfigs({ ...dashboardStore.selectedGrid, ...param });
|
||||||
|
emit("update", param);
|
||||||
}
|
}
|
||||||
async function changeLinkServerMetrics(options: Option[] | any) {
|
async function changeLinkServerMetrics(options: Option[] | any) {
|
||||||
states.linkServerMetrics = options.map((d: Option) => d.value);
|
states.linkServerMetrics = options.map((d: Option) => d.value);
|
||||||
@ -352,15 +363,7 @@ async function changeLinkServerMetrics(options: Option[] | any) {
|
|||||||
topologyStore.setLinkServerMetrics({});
|
topologyStore.setLinkServerMetrics({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const idsS = topologyStore.calls
|
topologyStore.getLinkServerMetrics(states.linkServerMetrics);
|
||||||
.filter((i: Call) => i.detectPoints.includes("SERVER"))
|
|
||||||
.map((b: Call) => b.id);
|
|
||||||
const param = await useQueryTopologyMetrics(states.linkServerMetrics, idsS);
|
|
||||||
const res = await topologyStore.getCallServerMetrics(param);
|
|
||||||
|
|
||||||
if (res.errors) {
|
|
||||||
ElMessage.error(res.errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
async function changeLinkClientMetrics(options: Option[] | any) {
|
async function changeLinkClientMetrics(options: Option[] | any) {
|
||||||
states.linkClientMetrics = options.map((d: Option) => d.value);
|
states.linkClientMetrics = options.map((d: Option) => d.value);
|
||||||
@ -369,30 +372,16 @@ async function changeLinkClientMetrics(options: Option[] | any) {
|
|||||||
topologyStore.setLinkClientMetrics({});
|
topologyStore.setLinkClientMetrics({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const idsC = topologyStore.calls
|
topologyStore.getLinkClientMetrics(states.linkClientMetrics);
|
||||||
.filter((i: Call) => i.detectPoints.includes("CLIENT"))
|
|
||||||
.map((b: Call) => b.id);
|
|
||||||
const param = await useQueryTopologyMetrics(states.linkClientMetrics, idsC);
|
|
||||||
const res = await topologyStore.getCallClientMetrics(param);
|
|
||||||
|
|
||||||
if (res.errors) {
|
|
||||||
ElMessage.error(res.errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
async function changeNodeMetrics(options: Option[] | any) {
|
async function changeNodeMetrics(options: Option[] | any) {
|
||||||
states.nodeMetrics = options.map((d: Option) => d.value);
|
states.nodeMetrics = options.map((d: Option) => d.value);
|
||||||
updateSettings();
|
updateSettings();
|
||||||
if (!states.nodeMetrics.length) {
|
if (!states.nodeMetrics.length) {
|
||||||
topologyStore.setNodeMetrics({});
|
topologyStore.setNodeMetricValue({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ids = topologyStore.nodes.map((d: Node) => d.id);
|
topologyStore.queryNodeMetrics(states.nodeMetrics);
|
||||||
const param = await useQueryTopologyMetrics(states.nodeMetrics, ids);
|
|
||||||
const res = await topologyStore.getNodeMetrics(param);
|
|
||||||
|
|
||||||
if (res.errors) {
|
|
||||||
ElMessage.error(res.errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
function deleteMetric(index: number) {
|
function deleteMetric(index: number) {
|
||||||
legend.metric.splice(index, 1);
|
legend.metric.splice(index, 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user