mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-03 03:23:37 +00:00
feat: Implement an association between widgets(line, bar, area graphs) with time (#115)
This commit is contained in:
parent
3ff3d5d1cd
commit
7fbd6170de
@ -44,6 +44,13 @@ const props = defineProps({
|
|||||||
type: Object as PropType<{ [key: string]: any }>,
|
type: Object as PropType<{ [key: string]: any }>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
|
filters: {
|
||||||
|
type: Object as PropType<{
|
||||||
|
value: number | string;
|
||||||
|
dataIndex: number;
|
||||||
|
sourceId: string;
|
||||||
|
}>,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const available = computed(
|
const available = computed(
|
||||||
() =>
|
() =>
|
||||||
@ -61,9 +68,25 @@ onMounted(async () => {
|
|||||||
if (!instance) {
|
if (!instance) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
instance.on("click", (params: any) => {
|
instance.on("click", (params: unknown) => {
|
||||||
emits("select", params);
|
emits("select", params);
|
||||||
});
|
});
|
||||||
|
document.addEventListener(
|
||||||
|
"click",
|
||||||
|
() => {
|
||||||
|
if (instance.isDisposed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instance.dispatchAction({
|
||||||
|
type: "hideTip",
|
||||||
|
});
|
||||||
|
instance.dispatchAction({
|
||||||
|
type: "updateAxisPointer",
|
||||||
|
currTrigger: "leave",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -79,6 +102,22 @@ watch(
|
|||||||
setOptions(newVal);
|
setOptions(newVal);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
watch(
|
||||||
|
() => props.filters,
|
||||||
|
() => {
|
||||||
|
const instance = getInstance();
|
||||||
|
if (!instance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (props.filters) {
|
||||||
|
instance.dispatchAction({
|
||||||
|
type: "showTip",
|
||||||
|
dataIndex: props.filters.dataIndex,
|
||||||
|
seriesIndex: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
removeResizeListener(unref(chartRef), resize);
|
removeResizeListener(unref(chartRef), resize);
|
||||||
|
@ -14,12 +14,13 @@
|
|||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
export default function getDashboard(param: {
|
export default function getDashboard(param: {
|
||||||
name: string;
|
name: string;
|
||||||
layer: string;
|
layer: string;
|
||||||
entity: string;
|
entity: string;
|
||||||
}) {
|
}) {
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
||||||
const dashboard = list.find(
|
const dashboard = list.find(
|
||||||
(d: { name: string; layer: string; entity: string }) =>
|
(d: { name: string; layer: string; entity: string }) =>
|
||||||
@ -27,6 +28,20 @@ export default function getDashboard(param: {
|
|||||||
d.entity === param.entity &&
|
d.entity === param.entity &&
|
||||||
d.layer === param.layer
|
d.layer === param.layer
|
||||||
);
|
);
|
||||||
|
const all = dashboardStore.layout;
|
||||||
return dashboard;
|
const widgets = [];
|
||||||
|
for (const item of all) {
|
||||||
|
if (item.type === "Tab") {
|
||||||
|
if (item.children && item.children.length) {
|
||||||
|
for (const child of item.children) {
|
||||||
|
if (child.children && child.children.length) {
|
||||||
|
widgets.push(...child.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
widgets.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { dashboard, widgets };
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,10 @@ export function useSourceProcessor(
|
|||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
if (!resp.data) {
|
||||||
|
ElMessage.error("The query is wrong");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
const source: { [key: string]: unknown } = {};
|
const source: { [key: string]: unknown } = {};
|
||||||
const keys = Object.keys(resp.data);
|
const keys = Object.keys(resp.data);
|
||||||
|
|
||||||
|
@ -142,6 +142,11 @@ const msg = {
|
|||||||
interval: "Refresh Interval",
|
interval: "Refresh Interval",
|
||||||
pause: "Pause",
|
pause: "Pause",
|
||||||
begin: "Start",
|
begin: "Start",
|
||||||
|
associateOptions: "Association Options",
|
||||||
|
widget: "Widget",
|
||||||
|
nameTip:
|
||||||
|
"The name only supports Chinese and English, horizontal lines and underscores",
|
||||||
|
duplicateName: "Duplicate name",
|
||||||
seconds: "Seconds",
|
seconds: "Seconds",
|
||||||
hourTip: "Select Hour",
|
hourTip: "Select Hour",
|
||||||
minuteTip: "Select Minute",
|
minuteTip: "Select Minute",
|
||||||
|
@ -142,6 +142,11 @@ const msg = {
|
|||||||
interval: "Intervalo de actualización",
|
interval: "Intervalo de actualización",
|
||||||
pause: "Pausa",
|
pause: "Pausa",
|
||||||
begin: "Inicio",
|
begin: "Inicio",
|
||||||
|
associateOptions: "Opciones de asociación",
|
||||||
|
widget: "Dispositivo pequeño",
|
||||||
|
duplicateName: "Nombre duplicado",
|
||||||
|
nameTip:
|
||||||
|
"Este nombre sólo admite chino e inglés, líneas cruzadas y subrayado",
|
||||||
seconds: "Segundos",
|
seconds: "Segundos",
|
||||||
hourTip: "Seleccione Hora",
|
hourTip: "Seleccione Hora",
|
||||||
minuteTip: "Seleccione Minuto",
|
minuteTip: "Seleccione Minuto",
|
||||||
|
@ -140,6 +140,10 @@ const msg = {
|
|||||||
interval: "刷新间隔时间",
|
interval: "刷新间隔时间",
|
||||||
pause: "暂停",
|
pause: "暂停",
|
||||||
begin: "开始",
|
begin: "开始",
|
||||||
|
associateOptions: "关联选项",
|
||||||
|
widget: "部件",
|
||||||
|
nameTip: "该名称仅支持中文和英文、横线和下划线",
|
||||||
|
duplicateName: "重复的名称",
|
||||||
seconds: "秒",
|
seconds: "秒",
|
||||||
hourTip: "选择小时",
|
hourTip: "选择小时",
|
||||||
minuteTip: "选择分钟",
|
minuteTip: "选择分钟",
|
||||||
|
@ -80,6 +80,7 @@ export const dashboardStore = defineStore({
|
|||||||
const newItem: LayoutConfig = {
|
const newItem: LayoutConfig = {
|
||||||
...NewControl,
|
...NewControl,
|
||||||
i: index,
|
i: index,
|
||||||
|
id: index,
|
||||||
type,
|
type,
|
||||||
metricTypes: [""],
|
metricTypes: [""],
|
||||||
metrics: [""],
|
metrics: [""],
|
||||||
@ -152,9 +153,11 @@ export const dashboardStore = defineStore({
|
|||||||
if (!children.length) {
|
if (!children.length) {
|
||||||
index = "0";
|
index = "0";
|
||||||
}
|
}
|
||||||
|
const id = `${activedGridItem}-${tabIndex}-${index}`;
|
||||||
const newItem: LayoutConfig = {
|
const newItem: LayoutConfig = {
|
||||||
...NewControl,
|
...NewControl,
|
||||||
i: index,
|
i: index,
|
||||||
|
id,
|
||||||
type,
|
type,
|
||||||
metricTypes: [""],
|
metricTypes: [""],
|
||||||
metrics: [""],
|
metrics: [""],
|
||||||
@ -275,6 +278,28 @@ export const dashboardStore = defineStore({
|
|||||||
};
|
};
|
||||||
this.selectedGrid = this.layout[index];
|
this.selectedGrid = this.layout[index];
|
||||||
},
|
},
|
||||||
|
setWidget(param: LayoutConfig) {
|
||||||
|
for (let i = 0; i < this.layout.length; i++) {
|
||||||
|
if (this.layout[i].type === "Tab") {
|
||||||
|
if (this.layout[i].children && this.layout[i].children.length) {
|
||||||
|
for (const child of this.layout[i].children) {
|
||||||
|
if (child.children && child.children.length) {
|
||||||
|
for (let c = 0; c < child.children.length; c++) {
|
||||||
|
if (child.children[c].id === param.id) {
|
||||||
|
child.children.splice(c, 1, param);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.layout[i].id === param.id) {
|
||||||
|
this.layout.splice(i, 1, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
async fetchMetricType(item: string) {
|
async fetchMetricType(item: string) {
|
||||||
const res: AxiosResponse = await graphql
|
const res: AxiosResponse = await graphql
|
||||||
.query("queryTypeOfMetrics")
|
.query("queryTypeOfMetrics")
|
||||||
|
16
src/types/dashboard.d.ts
vendored
16
src/types/dashboard.d.ts
vendored
@ -36,6 +36,9 @@ export interface LayoutConfig {
|
|||||||
children?: { name: string; children: LayoutConfig[] }[];
|
children?: { name: string; children: LayoutConfig[] }[];
|
||||||
activedTabIndex?: number;
|
activedTabIndex?: number;
|
||||||
metricConfig?: MetricConfigOpt[];
|
metricConfig?: MetricConfigOpt[];
|
||||||
|
id?: string;
|
||||||
|
associate?: { widgetId: string }[];
|
||||||
|
filters?: { dataIndex: number; sourceId: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MetricConfigOpt = {
|
export type MetricConfigOpt = {
|
||||||
@ -48,6 +51,7 @@ export type MetricConfigOpt = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface WidgetConfig {
|
export interface WidgetConfig {
|
||||||
|
name?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
tips?: string;
|
tips?: string;
|
||||||
}
|
}
|
||||||
@ -137,3 +141,15 @@ export interface TopologyConfig {
|
|||||||
depth?: number;
|
depth?: number;
|
||||||
showDepth?: boolean;
|
showDepth?: boolean;
|
||||||
}
|
}
|
||||||
|
export type EventParams = {
|
||||||
|
componentType: string;
|
||||||
|
seriesType: string;
|
||||||
|
seriesIndex: number;
|
||||||
|
seriesName: string;
|
||||||
|
name: string;
|
||||||
|
dataIndex: number;
|
||||||
|
data: Record<string, unknown>;
|
||||||
|
dataType: string;
|
||||||
|
value: number | number[];
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
@ -41,6 +41,7 @@ import Tool from "./panel/Tool.vue";
|
|||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import Configuration from "./configuration";
|
import Configuration from "./configuration";
|
||||||
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Dashboard",
|
name: "Dashboard",
|
||||||
@ -66,7 +67,8 @@ export default defineComponent({
|
|||||||
sessionStorage.getItem(layoutKey.value) || "{}"
|
sessionStorage.getItem(layoutKey.value) || "{}"
|
||||||
);
|
);
|
||||||
const layout: any = c.configuration || {};
|
const layout: any = c.configuration || {};
|
||||||
dashboardStore.setLayout(layout.children || []);
|
|
||||||
|
dashboardStore.setLayout(setWidgetsID(layout.children || []));
|
||||||
appStore.setPageTitle(layout.name);
|
appStore.setPageTitle(layout.name);
|
||||||
if (p.entity) {
|
if (p.entity) {
|
||||||
dashboardStore.setCurrentDashboard({
|
dashboardStore.setCurrentDashboard({
|
||||||
@ -78,6 +80,24 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function setWidgetsID(widgets: LayoutConfig[]) {
|
||||||
|
for (const item of widgets) {
|
||||||
|
item.id = item.i;
|
||||||
|
if (item.type === "Tab") {
|
||||||
|
if (item.children && item.children.length) {
|
||||||
|
for (const [index, child] of item.children.entries()) {
|
||||||
|
if (child.children && child.children.length) {
|
||||||
|
child.children.map((d: { i: string; index: string } | any) => {
|
||||||
|
d.id = `${item.i}-${index}-${d.i}`;
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return widgets;
|
||||||
|
}
|
||||||
function handleClick(e: any) {
|
function handleClick(e: any) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (e.target.className === "ds-main") {
|
if (e.target.className === "ds-main") {
|
||||||
|
@ -232,12 +232,16 @@ function exportTemplates() {
|
|||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
function optimizeTemplate(
|
function optimizeTemplate(
|
||||||
children: (LayoutConfig & { moved?: boolean; standard?: unknown })[]
|
children: (LayoutConfig & {
|
||||||
|
moved?: boolean;
|
||||||
|
standard?: unknown;
|
||||||
|
})[]
|
||||||
) {
|
) {
|
||||||
for (const child of children || []) {
|
for (const child of children || []) {
|
||||||
delete child.moved;
|
delete child.moved;
|
||||||
delete child.activedTabIndex;
|
delete child.activedTabIndex;
|
||||||
delete child.standard;
|
delete child.standard;
|
||||||
|
delete child.id;
|
||||||
if (isEmptyObject(child.graph)) {
|
if (isEmptyObject(child.graph)) {
|
||||||
delete child.graph;
|
delete child.graph;
|
||||||
}
|
}
|
||||||
@ -402,6 +406,7 @@ async function updateName(d: DashboardItem, value: string) {
|
|||||||
name: value,
|
name: value,
|
||||||
};
|
};
|
||||||
delete c.id;
|
delete c.id;
|
||||||
|
delete c.filters;
|
||||||
const setting = {
|
const setting = {
|
||||||
id: d.id,
|
id: d.id,
|
||||||
configuration: JSON.stringify(c),
|
configuration: JSON.stringify(c),
|
||||||
|
@ -58,6 +58,13 @@ limitations under the License. -->
|
|||||||
<el-collapse-item :title="t('widgetOptions')" name="3">
|
<el-collapse-item :title="t('widgetOptions')" name="3">
|
||||||
<WidgetOptions />
|
<WidgetOptions />
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
|
<el-collapse-item
|
||||||
|
:title="t('associateOptions')"
|
||||||
|
name="4"
|
||||||
|
v-if="hasAssociate"
|
||||||
|
>
|
||||||
|
<AssociateOptions />
|
||||||
|
</el-collapse-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
@ -77,17 +84,13 @@ import { useDashboardStore } from "@/store/modules/dashboard";
|
|||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import graphs from "../graphs";
|
import graphs from "../graphs";
|
||||||
import configs from "./widget/graph-styles";
|
import CustomOptions from "./widget/index";
|
||||||
import WidgetOptions from "./widget/WidgetOptions.vue";
|
|
||||||
import MetricOptions from "./widget/metric/Index.vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "WidgetEdit",
|
name: "WidgetEdit",
|
||||||
components: {
|
components: {
|
||||||
...graphs,
|
...graphs,
|
||||||
...configs,
|
...CustomOptions,
|
||||||
WidgetOptions,
|
|
||||||
MetricOptions,
|
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const configHeight = document.documentElement.clientHeight - 520;
|
const configHeight = document.documentElement.clientHeight - 520;
|
||||||
@ -111,6 +114,12 @@ export default defineComponent({
|
|||||||
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
|
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
|
||||||
const title = computed(() => encodeURIComponent(widget.value.title || ""));
|
const title = computed(() => encodeURIComponent(widget.value.title || ""));
|
||||||
const tips = computed(() => encodeURIComponent(widget.value.tips || ""));
|
const tips = computed(() => encodeURIComponent(widget.value.tips || ""));
|
||||||
|
const hasAssociate = computed(() =>
|
||||||
|
["Bar", "Line", "Area"].includes(
|
||||||
|
dashboardStore.selectedGrid.graph &&
|
||||||
|
dashboardStore.selectedGrid.graph.type
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
function getSource(source: unknown) {
|
function getSource(source: unknown) {
|
||||||
states.source = source;
|
states.source = source;
|
||||||
@ -145,6 +154,7 @@ export default defineComponent({
|
|||||||
graph,
|
graph,
|
||||||
title,
|
title,
|
||||||
tips,
|
tips,
|
||||||
|
hasAssociate,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
125
src/views/dashboard/configuration/widget/AssociateOptions.vue
Normal file
125
src/views/dashboard/configuration/widget/AssociateOptions.vue
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<!-- 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="item">
|
||||||
|
<span class="label">{{ t("widget") }}</span>
|
||||||
|
<Selector
|
||||||
|
:multiple="true"
|
||||||
|
:value="widgetIds"
|
||||||
|
:options="widgets"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a widget"
|
||||||
|
class="selectors"
|
||||||
|
@change="updateWidgetConfig"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
|
import { Option } from "@/types/app";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const associate = dashboardStore.selectedGrid.associate || [];
|
||||||
|
const widgetIds = ref<string[]>(
|
||||||
|
associate.map((d: { widgetId: string }) => d.widgetId)
|
||||||
|
);
|
||||||
|
const widgets = computed(() => {
|
||||||
|
const isLinear = ["Bar", "Line", "Area"].includes(
|
||||||
|
dashboardStore.selectedGrid.graph && dashboardStore.selectedGrid.graph.type
|
||||||
|
);
|
||||||
|
// const isRank = ["TopList"].includes(
|
||||||
|
// dashboardStore.selectedGrid.graph && dashboardStore.selectedGrid.graph.type
|
||||||
|
// );
|
||||||
|
const { widgets } = getDashboard(dashboardStore.currentDashboard);
|
||||||
|
const items = widgets.filter(
|
||||||
|
(d: { value: string; label: string } & LayoutConfig) => {
|
||||||
|
if (dashboardStore.selectedGrid.id !== d.id) {
|
||||||
|
if (isLinear && d.type === "Widget" && d.widget && d.id) {
|
||||||
|
d.value = d.id;
|
||||||
|
d.label = d.widget.name || d.id;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
// if (isRank && d.type !== "Widget" && d.widget && d.id) {
|
||||||
|
// d.value = d.id;
|
||||||
|
// d.label = d.widget.name || d.id;
|
||||||
|
// return d;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return items;
|
||||||
|
});
|
||||||
|
function updateWidgetConfig(options: Option[]) {
|
||||||
|
const { widgets } = getDashboard(dashboardStore.currentDashboard);
|
||||||
|
const opt = options.map((d: Option) => {
|
||||||
|
return { widgetId: d.value };
|
||||||
|
});
|
||||||
|
const newVal = options.map((d: Option) => d.value);
|
||||||
|
// add association options in the source widget
|
||||||
|
const widget = {
|
||||||
|
...dashboardStore.selectedGrid,
|
||||||
|
associate: opt,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...widget });
|
||||||
|
// remove unuse association widget option
|
||||||
|
for (const id of widgetIds.value) {
|
||||||
|
if (!newVal.includes(id)) {
|
||||||
|
const w = widgets.find((d: { id: string }) => d.id === id);
|
||||||
|
const config = {
|
||||||
|
...w,
|
||||||
|
associate: [],
|
||||||
|
};
|
||||||
|
dashboardStore.setWidget(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add association options in target widgets
|
||||||
|
for (let i = 0; i < opt.length; i++) {
|
||||||
|
const item = JSON.parse(JSON.stringify(opt));
|
||||||
|
item[i] = { widgetId: dashboardStore.selectedGrid.id };
|
||||||
|
const w = widgets.find((d: { id: string }) => d.id === opt[i].widgetId);
|
||||||
|
const config = {
|
||||||
|
...w,
|
||||||
|
associate: item,
|
||||||
|
};
|
||||||
|
dashboardStore.setWidget(config);
|
||||||
|
}
|
||||||
|
widgetIds.value = newVal;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectors {
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -13,6 +13,16 @@ 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>
|
||||||
|
<div class="item">
|
||||||
|
<span class="label">{{ t("name") }}</span>
|
||||||
|
<el-input
|
||||||
|
class="input"
|
||||||
|
v-model="name"
|
||||||
|
size="small"
|
||||||
|
placeholder="Please input name"
|
||||||
|
@change="updateWidgetName({ name: encodeURIComponent(name) })"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<span class="label">{{ t("title") }}</span>
|
<span class="label">{{ t("title") }}</span>
|
||||||
<el-input
|
<el-input
|
||||||
@ -37,13 +47,17 @@ limitations under the License. -->
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const widget = dashboardStore.selectedGrid.widget || {};
|
const widget = dashboardStore.selectedGrid.widget || {};
|
||||||
const title = ref<string>(widget.title || "");
|
const title = ref<string>(widget.title || "");
|
||||||
const tips = ref<string>(widget.tips || "");
|
const tips = ref<string>(widget.tips || "");
|
||||||
|
const name = ref<string>(widget.name || "");
|
||||||
|
|
||||||
function updateWidgetConfig(param: { [key: string]: string }) {
|
function updateWidgetConfig(param: { [key: string]: string }) {
|
||||||
const key = Object.keys(param)[0];
|
const key = Object.keys(param)[0];
|
||||||
@ -57,6 +71,24 @@ function updateWidgetConfig(param: { [key: string]: string }) {
|
|||||||
};
|
};
|
||||||
dashboardStore.selectWidget({ ...selectedGrid, widget });
|
dashboardStore.selectWidget({ ...selectedGrid, widget });
|
||||||
}
|
}
|
||||||
|
function updateWidgetName(param: { [key: string]: string }) {
|
||||||
|
const key = Object.keys(param)[0];
|
||||||
|
const n = decodeURIComponent(param[key]);
|
||||||
|
const pattern = /^[A-Za-z0-9-_\u4e00-\u9fa5]{1,30}$/;
|
||||||
|
if (!pattern.test(n)) {
|
||||||
|
ElMessage.error(t("nameTip"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { widgets } = getDashboard(dashboardStore.currentDashboard);
|
||||||
|
const item = widgets.find(
|
||||||
|
(d: LayoutConfig) => d.widget && d.widget.name === n
|
||||||
|
);
|
||||||
|
if (item) {
|
||||||
|
ElMessage.error(t("duplicateName"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateWidgetConfig(param);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.label {
|
.label {
|
||||||
|
28
src/views/dashboard/configuration/widget/index.ts
Normal file
28
src/views/dashboard/configuration/widget/index.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* 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 StyleOptions from "./graph-styles";
|
||||||
|
import WidgetOptions from "./WidgetOptions.vue";
|
||||||
|
import MetricOptions from "./metric/Index.vue";
|
||||||
|
import AssociateOptions from "./AssociateOptions.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
...StyleOptions,
|
||||||
|
WidgetOptions,
|
||||||
|
MetricOptions,
|
||||||
|
AssociateOptions,
|
||||||
|
};
|
@ -22,7 +22,9 @@ limitations under the License. -->
|
|||||||
size="small"
|
size="small"
|
||||||
placeholder="Please input unit"
|
placeholder="Please input unit"
|
||||||
@change="
|
@change="
|
||||||
updateConfig(index, { unit: encodeURIComponent(currentMetric.unit) })
|
updateConfig(index, {
|
||||||
|
unit: encodeURIComponent(currentMetric.unit || ''),
|
||||||
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -35,7 +37,7 @@ limitations under the License. -->
|
|||||||
placeholder="Please input a name"
|
placeholder="Please input a name"
|
||||||
@change="
|
@change="
|
||||||
updateConfig(index, {
|
updateConfig(index, {
|
||||||
label: encodeURIComponent(currentMetric.label),
|
label: encodeURIComponent(currentMetric.label || ''),
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
@ -61,9 +61,12 @@ limitations under the License. -->
|
|||||||
metrics: data.metrics || [''],
|
metrics: data.metrics || [''],
|
||||||
metricTypes: data.metricTypes || [''],
|
metricTypes: data.metricTypes || [''],
|
||||||
i: data.i,
|
i: data.i,
|
||||||
|
id: data.id,
|
||||||
metricConfig: data.metricConfig,
|
metricConfig: data.metricConfig,
|
||||||
|
filters: data.filters || {},
|
||||||
}"
|
}"
|
||||||
:needQuery="needQuery"
|
:needQuery="needQuery"
|
||||||
|
@click="clickHandle"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="no-data">{{ t("noGraph") }}</div>
|
<div v-else class="no-data">{{ t("noGraph") }}</div>
|
||||||
@ -84,6 +87,8 @@ import {
|
|||||||
useGetMetricEntity,
|
useGetMetricEntity,
|
||||||
} from "@/hooks/useProcessor";
|
} from "@/hooks/useProcessor";
|
||||||
import { EntityType, ListChartTypes } from "../data";
|
import { EntityType, ListChartTypes } from "../data";
|
||||||
|
import { EventParams } from "@/types/dashboard";
|
||||||
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
data: {
|
data: {
|
||||||
@ -93,6 +98,7 @@ const props = {
|
|||||||
activeIndex: { type: String, default: "" },
|
activeIndex: { type: String, default: "" },
|
||||||
needQuery: { type: Boolean, default: false },
|
needQuery: { type: Boolean, default: false },
|
||||||
};
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Widget",
|
name: "Widget",
|
||||||
components: { ...graphs },
|
components: { ...graphs },
|
||||||
@ -156,6 +162,24 @@ export default defineComponent({
|
|||||||
dashboardStore.activeGridItem(props.data.i);
|
dashboardStore.activeGridItem(props.data.i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function clickHandle(params: EventParams | any) {
|
||||||
|
const { widgets } = getDashboard(dashboardStore.currentDashboard);
|
||||||
|
const associate = (props.data.associate && props.data.associate) || [];
|
||||||
|
|
||||||
|
for (const item of associate) {
|
||||||
|
const widget = widgets.find(
|
||||||
|
(d: { id: string }) => d.id === item.widgetId
|
||||||
|
);
|
||||||
|
if (widget) {
|
||||||
|
widget.filters = {
|
||||||
|
dataIndex: params.dataIndex,
|
||||||
|
sourceId: props.data.id || "",
|
||||||
|
};
|
||||||
|
|
||||||
|
dashboardStore.setWidget(widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
watch(
|
watch(
|
||||||
() => [props.data.metricTypes, props.data.metrics],
|
() => [props.data.metricTypes, props.data.metrics],
|
||||||
() => {
|
() => {
|
||||||
@ -221,6 +245,7 @@ export default defineComponent({
|
|||||||
t,
|
t,
|
||||||
graph,
|
graph,
|
||||||
widget,
|
widget,
|
||||||
|
clickHandle,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -14,14 +14,20 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Line :data="data" :intervalTime="intervalTime" :config="config" />
|
<Line
|
||||||
|
:data="data"
|
||||||
|
:intervalTime="intervalTime"
|
||||||
|
:config="config"
|
||||||
|
@click="clickEvent"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import Line from "./Line.vue";
|
import Line from "./Line.vue";
|
||||||
import { AreaConfig } from "@/types/dashboard";
|
import { AreaConfig, EventParams } from "@/types/dashboard";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps, defineEmits */
|
||||||
|
const emits = defineEmits(["click"]);
|
||||||
defineProps({
|
defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number[] }>,
|
type: Object as PropType<{ [key: string]: number[] }>,
|
||||||
@ -29,8 +35,19 @@ defineProps({
|
|||||||
},
|
},
|
||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<AreaConfig>,
|
type: Object as PropType<
|
||||||
|
AreaConfig & {
|
||||||
|
filters: {
|
||||||
|
value: number | string;
|
||||||
|
dataIndex: number;
|
||||||
|
sourceId: string;
|
||||||
|
};
|
||||||
|
} & { id: string }
|
||||||
|
>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
function clickEvent(params: EventParams) {
|
||||||
|
emits("click", params);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -13,15 +13,16 @@ 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>
|
||||||
<Graph :option="option" />
|
<Graph :option="option" @select="clickEvent" :filters="config.filters" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { Event } from "@/types/events";
|
import { Event } from "@/types/events";
|
||||||
import { BarConfig } from "@/types/dashboard";
|
import { BarConfig, EventParams } from "@/types/dashboard";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps, defineEmits */
|
||||||
|
const emits = defineEmits(["click"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number[] }>,
|
type: Object as PropType<{ [key: string]: number[] }>,
|
||||||
@ -31,7 +32,15 @@ const props = defineProps({
|
|||||||
theme: { type: String, default: "light" },
|
theme: { type: String, default: "light" },
|
||||||
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
|
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<BarConfig>,
|
type: Object as PropType<
|
||||||
|
BarConfig & {
|
||||||
|
filters: {
|
||||||
|
value: number | string;
|
||||||
|
dataIndex: number;
|
||||||
|
sourceId: string;
|
||||||
|
};
|
||||||
|
} & { id: string }
|
||||||
|
>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -139,11 +148,10 @@ function getOption() {
|
|||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
zlevel: 1000,
|
zlevel: 1000,
|
||||||
z: 60,
|
z: 60,
|
||||||
backgroundColor: "rgb(50,50,50)",
|
|
||||||
confine: true,
|
confine: true,
|
||||||
textStyle: {
|
textStyle: {
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: "#ccc",
|
color: "#333",
|
||||||
},
|
},
|
||||||
enterable: true,
|
enterable: true,
|
||||||
extraCssText: "max-height: 300px; overflow: auto; border: none",
|
extraCssText: "max-height: 300px; overflow: auto; border: none",
|
||||||
@ -186,4 +194,7 @@ function getOption() {
|
|||||||
series: temp,
|
series: temp,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
function clickEvent(params: EventParams) {
|
||||||
|
emits("click", params);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -147,17 +147,17 @@ async function queryEndpointMetrics(currentPods: Endpoint[]) {
|
|||||||
endpoints.value = currentPods;
|
endpoints.value = currentPods;
|
||||||
}
|
}
|
||||||
function clickEndpoint(scope: any) {
|
function clickEndpoint(scope: any) {
|
||||||
const d = getDashboard({
|
const { dashboard } = getDashboard({
|
||||||
name: props.config.dashboardName,
|
name: props.config.dashboardName,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
entity: EntityType[2].value,
|
entity: EntityType[2].value,
|
||||||
});
|
});
|
||||||
if (!d) {
|
if (!dashboard) {
|
||||||
ElMessage.error("No this dashboard");
|
ElMessage.error("No this dashboard");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
router.push(
|
router.push(
|
||||||
`/dashboard/${d.layer}/${d.entity}/${selectorStore.currentService.id}/${scope.row.id}/${d.name}`
|
`/dashboard/${dashboard.layer}/${dashboard.entity}/${selectorStore.currentService.id}/${scope.row.id}/${dashboard.name}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
async function searchList() {
|
async function searchList() {
|
||||||
|
@ -180,19 +180,19 @@ async function queryInstanceMetrics(currentInstances: Instance[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clickInstance(scope: any) {
|
function clickInstance(scope: any) {
|
||||||
const d = getDashboard({
|
const { dashboard } = getDashboard({
|
||||||
name: props.config.dashboardName,
|
name: props.config.dashboardName,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
entity: EntityType[3].value,
|
entity: EntityType[3].value,
|
||||||
});
|
});
|
||||||
if (!d) {
|
if (!dashboard) {
|
||||||
ElMessage.error("No this dashboard");
|
ElMessage.error("No this dashboard");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
router.push(
|
router.push(
|
||||||
`/dashboard/${d.layer}/${d.entity}/${selectorStore.currentService.id}/${
|
`/dashboard/${dashboard.layer}/${dashboard.entity}/${
|
||||||
scope.row.id
|
selectorStore.currentService.id
|
||||||
}/${d.name.split(" ").join("-")}`
|
}/${scope.row.id}/${dashboard.name.split(" ").join("-")}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,15 +13,16 @@ 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>
|
||||||
<Graph :option="option" />
|
<Graph :option="option" @select="clickEvent" :filters="config.filters" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { Event } from "@/types/events";
|
import { Event } from "@/types/events";
|
||||||
import { LineConfig } from "@/types/dashboard";
|
import { LineConfig, EventParams } from "@/types/dashboard";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps, defineEmits */
|
||||||
|
const emits = defineEmits(["click"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number[] }>,
|
type: Object as PropType<{ [key: string]: number[] }>,
|
||||||
@ -31,7 +32,15 @@ const props = defineProps({
|
|||||||
theme: { type: String, default: "light" },
|
theme: { type: String, default: "light" },
|
||||||
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
|
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<LineConfig>,
|
type: Object as PropType<
|
||||||
|
LineConfig & {
|
||||||
|
filters: {
|
||||||
|
value: number | string;
|
||||||
|
dataIndex: number;
|
||||||
|
sourceId: string;
|
||||||
|
};
|
||||||
|
} & { id: string }
|
||||||
|
>,
|
||||||
default: () => ({
|
default: () => ({
|
||||||
step: false,
|
step: false,
|
||||||
smooth: false,
|
smooth: false,
|
||||||
@ -81,7 +90,7 @@ function getOption() {
|
|||||||
name: i,
|
name: i,
|
||||||
type: "line",
|
type: "line",
|
||||||
symbol: "circle",
|
symbol: "circle",
|
||||||
symbolSize: 6,
|
symbolSize: 8,
|
||||||
showSymbol: props.config.showSymbol,
|
showSymbol: props.config.showSymbol,
|
||||||
step: props.config.step,
|
step: props.config.step,
|
||||||
smooth: props.config.smooth,
|
smooth: props.config.smooth,
|
||||||
@ -145,10 +154,9 @@ function getOption() {
|
|||||||
}
|
}
|
||||||
const tooltip = {
|
const tooltip = {
|
||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
backgroundColor: "rgb(50,50,50)",
|
|
||||||
textStyle: {
|
textStyle: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: "#ccc",
|
color: "#333",
|
||||||
},
|
},
|
||||||
enterable: true,
|
enterable: true,
|
||||||
confine: true,
|
confine: true,
|
||||||
@ -215,4 +223,8 @@ function getOption() {
|
|||||||
series: temp,
|
series: temp,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clickEvent(params: EventParams) {
|
||||||
|
emits("click", params);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
|
||||||
this work for additional information regarding copyright ownership.
|
|
||||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
(the "License"); you may not use this file except in compliance with
|
|
||||||
the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License. -->
|
|
||||||
<template>
|
|
||||||
<Graph :option="option" />
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed } from "vue";
|
|
||||||
import type { PropType } from "vue";
|
|
||||||
|
|
||||||
/*global defineProps */
|
|
||||||
const props = defineProps({
|
|
||||||
data: {
|
|
||||||
type: Array as PropType<{ name: string; value: number }[]>,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
type: Object as PropType<{ sortOrder: string }>,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const option = computed(() => getOption());
|
|
||||||
function getOption() {
|
|
||||||
return {
|
|
||||||
tooltip: {
|
|
||||||
trigger: "item",
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
type: "scroll",
|
|
||||||
show: props.data.length === 1 ? false : true,
|
|
||||||
icon: "circle",
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
itemWidth: 12,
|
|
||||||
textStyle: {
|
|
||||||
color: "#333",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
type: "pie",
|
|
||||||
radius: "50%",
|
|
||||||
data: props.data,
|
|
||||||
emphasis: {
|
|
||||||
itemStyle: {
|
|
||||||
shadowBlur: 10,
|
|
||||||
shadowOffsetX: 0,
|
|
||||||
shadowColor: "rgba(0, 0, 0, 0.5)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -179,16 +179,16 @@ function setServices(arr: (Service & { merge: boolean })[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clickService(scope: any) {
|
function clickService(scope: any) {
|
||||||
const d = getDashboard({
|
const { dashboard } = getDashboard({
|
||||||
name: props.config.dashboardName,
|
name: props.config.dashboardName,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
entity: EntityType[0].value,
|
entity: EntityType[0].value,
|
||||||
});
|
});
|
||||||
if (!d) {
|
if (!dashboard) {
|
||||||
ElMessage.error("No this dashboard");
|
ElMessage.error("No this dashboard");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const path = `/dashboard/${d.layer}/${d.entity}/${scope.row.id}/${d.name}`;
|
const path = `/dashboard/${dashboard.layer}/${dashboard.entity}/${scope.row.id}/${dashboard.name}`;
|
||||||
|
|
||||||
router.push(path);
|
router.push(path);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ import Bar from "./Bar.vue";
|
|||||||
import HeatMap from "./HeatMap.vue";
|
import HeatMap from "./HeatMap.vue";
|
||||||
import TopList from "./TopList.vue";
|
import TopList from "./TopList.vue";
|
||||||
import Table from "./Table.vue";
|
import Table from "./Table.vue";
|
||||||
import Pie from "./Pie.vue";
|
|
||||||
import Card from "./Card.vue";
|
import Card from "./Card.vue";
|
||||||
import InstanceList from "./InstanceList.vue";
|
import InstanceList from "./InstanceList.vue";
|
||||||
import EndpointList from "./EndpointList.vue";
|
import EndpointList from "./EndpointList.vue";
|
||||||
@ -34,7 +33,6 @@ export default {
|
|||||||
TopList,
|
TopList,
|
||||||
Area,
|
Area,
|
||||||
Table,
|
Table,
|
||||||
Pie,
|
|
||||||
Card,
|
Card,
|
||||||
EndpointList,
|
EndpointList,
|
||||||
InstanceList,
|
InstanceList,
|
||||||
|
@ -272,19 +272,19 @@ function handleLinkClick(event: any, d: Call) {
|
|||||||
dashboardStore.entity === EntityType[1].value
|
dashboardStore.entity === EntityType[1].value
|
||||||
? EntityType[0].value
|
? EntityType[0].value
|
||||||
: dashboardStore.entity;
|
: dashboardStore.entity;
|
||||||
const p = getDashboard({
|
const { dashboard } = getDashboard({
|
||||||
name: settings.value.linkDashboard,
|
name: settings.value.linkDashboard,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
entity: `${e}Relation`,
|
entity: `${e}Relation`,
|
||||||
});
|
});
|
||||||
if (!p) {
|
if (!dashboard) {
|
||||||
ElMessage.error(
|
ElMessage.error(
|
||||||
`The dashboard named ${settings.value.linkDashboard} doesn't exist`
|
`The dashboard named ${settings.value.linkDashboard} doesn't exist`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dashboardStore.setEntity(p.entity);
|
dashboardStore.setEntity(dashboard.entity);
|
||||||
const path = `/dashboard/related/${p.layer}/${e}Relation/${d.source.id}/${d.target.id}/${p.name}`;
|
const path = `/dashboard/related/${dashboard.layer}/${e}Relation/${d.source.id}/${d.target.id}/${dashboard.name}`;
|
||||||
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);
|
||||||
|
@ -173,18 +173,18 @@ function goDashboard() {
|
|||||||
dashboardStore.entity === EntityType[2].value
|
dashboardStore.entity === EntityType[2].value
|
||||||
? EntityType[2].value
|
? EntityType[2].value
|
||||||
: EntityType[3].value;
|
: EntityType[3].value;
|
||||||
const d = getDashboard({
|
const { dashboard } = getDashboard({
|
||||||
name: settings.value.nodeDashboard,
|
name: settings.value.nodeDashboard,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
entity,
|
entity,
|
||||||
});
|
});
|
||||||
if (!d) {
|
if (!dashboard) {
|
||||||
ElMessage.error(
|
ElMessage.error(
|
||||||
`The dashboard named ${settings.value.nodeDashboard} doesn't exist`
|
`The dashboard named ${settings.value.nodeDashboard} doesn't exist`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const path = `/dashboard/${d.layer}/${entity}/${topologyStore.node.serviceId}/${topologyStore.node.id}/${d.name}`;
|
const path = `/dashboard/${dashboard.layer}/${entity}/${topologyStore.node.serviceId}/${topologyStore.node.id}/${dashboard.name}`;
|
||||||
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);
|
||||||
@ -217,18 +217,18 @@ function selectNodeLink(d: any) {
|
|||||||
dashboardStore.entity === EntityType[2].value
|
dashboardStore.entity === EntityType[2].value
|
||||||
? EntityType[6].value
|
? EntityType[6].value
|
||||||
: EntityType[5].value;
|
: EntityType[5].value;
|
||||||
const p = getDashboard({
|
const { dashboard } = getDashboard({
|
||||||
name: settings.value.linkDashboard,
|
name: settings.value.linkDashboard,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
entity,
|
entity,
|
||||||
});
|
});
|
||||||
if (!p) {
|
if (!dashboard) {
|
||||||
ElMessage.error(
|
ElMessage.error(
|
||||||
`The dashboard named ${settings.value.linkDashboard} doesn't exist`
|
`The dashboard named ${settings.value.linkDashboard} doesn't exist`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const path = `/dashboard/${p.layer}/${entity}/${sourceObj.serviceId}/${sourceObj.id}/${targetObj.serviceId}/${targetObj.id}/${p.name}`;
|
const path = `/dashboard/${dashboard.layer}/${entity}/${sourceObj.serviceId}/${sourceObj.id}/${targetObj.serviceId}/${targetObj.id}/${dashboard.name}`;
|
||||||
const routeUrl = router.resolve({ path });
|
const routeUrl = router.resolve({ path });
|
||||||
window.open(routeUrl.href, "_blank");
|
window.open(routeUrl.href, "_blank");
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user