This is an automated email from the ASF dual-hosted git repository.
qiuxiafan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-booster-ui.git
The following commit(s) were added to refs/heads/main by this push:
new 767c92c fix: polish pages and validate data (#46)
767c92c is described below
commit 767c92c60d2e4e0e6f819b450cb59bd6c3747bfa
Author: Fine0830 <[email protected]>
AuthorDate: Wed Mar 30 16:29:19 2022 +0800
fix: polish pages and validate data (#46)
---
src/components/Graph.vue | 37 ++++++++-
src/hooks/data.ts | 2 +
src/hooks/useProcessor.ts | 17 ++++-
src/locales/lang/en.ts | 5 +-
src/locales/lang/zh.ts | 1 +
src/store/data.ts | 8 --
src/types/dashboard.ts | 25 ++----
src/views/dashboard/configuration/Text.vue | 11 +--
src/views/dashboard/configuration/Topology.vue | 6 +-
src/views/dashboard/configuration/Widget.vue | 20 +++--
.../configuration/widget/WidgetOptions.vue | 7 +-
.../configuration/widget/graph-styles/HeatMap.vue | 3 +-
.../configuration/widget/metric/Index.vue | 89 +++++++++++-----------
.../configuration/widget/metric/Standard.vue | 14 ++--
src/views/dashboard/controls/Widget.vue | 51 ++++++++-----
src/views/dashboard/data.ts | 4 +-
src/views/dashboard/graphs/Bar.vue | 16 ++--
src/views/dashboard/graphs/Card.vue | 17 +++--
src/views/dashboard/graphs/EndpointList.vue | 38 +++------
src/views/dashboard/graphs/HeatMap.vue | 7 +-
src/views/dashboard/graphs/InstanceList.vue | 4 +-
src/views/dashboard/graphs/Line.vue | 2 +-
src/views/dashboard/graphs/ServiceList.vue | 4 +-
src/views/dashboard/graphs/TopList.vue | 21 ++++-
.../related/topology/components/Graph.vue | 16 +++-
.../dashboard/related/topology/utils/legend.ts | 8 +-
26 files changed, 241 insertions(+), 192 deletions(-)
diff --git a/src/components/Graph.vue b/src/components/Graph.vue
index e70b7a1..c83f9db 100644
--- a/src/components/Graph.vue
+++ b/src/components/Graph.vue
@@ -13,10 +13,23 @@ 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 ref="chartRef" :style="`height:${height};width:${width};`"></div>
+ <div
+ v-if="available"
+ ref="chartRef"
+ :style="`height:${height};width:${width};`"
+ ></div>
+ <div v-else class="no-data">No Data</div>
</template>
<script lang="ts" setup>
-import { watch, ref, Ref, onMounted, onBeforeUnmount, unref } from "vue";
+import {
+ watch,
+ ref,
+ Ref,
+ onMounted,
+ onBeforeUnmount,
+ unref,
+ computed,
+} from "vue";
import type { PropType } from "vue";
import { useECharts } from "@/hooks/useEcharts";
import { addResizeListener, removeResizeListener } from "@/utils/event";
@@ -31,11 +44,16 @@ const props = defineProps({
height: { type: String, default: "100%" },
width: { type: String, default: "100%" },
option: {
- type: Object as PropType<{ [key: string]: unknown }>,
+ type: Object as PropType<{ [key: string]: any }>,
default: () => ({}),
},
});
-
+const available = computed(
+ () =>
+ Array.isArray(props.option.series) &&
+ props.option.series[0] &&
+ props.option.series[0].data
+);
onMounted(async () => {
await setOptions(props.option);
chartRef.value && addResizeListener(unref(chartRef), resize);
@@ -65,3 +83,14 @@ onBeforeUnmount(() => {
removeResizeListener(unref(chartRef), resize);
});
</script>
+<style lang="scss" scoped>
+.no-data {
+ font-size: 12px;
+ height: 100%;
+ box-sizing: border-box;
+ display: -webkit-box;
+ -webkit-box-orient: horizontal;
+ -webkit-box-pack: center;
+ -webkit-box-align: center;
+}
+</style>
diff --git a/src/hooks/data.ts b/src/hooks/data.ts
index 5f1fdd8..4bc394f 100644
--- a/src/hooks/data.ts
+++ b/src/hooks/data.ts
@@ -26,6 +26,8 @@ export enum MetricQueryTypes {
export enum Calculations {
Percentage = "percentage",
ByteToKB = "byteToKB",
+ ByteToMB = "ByteToMB",
+ ByteToGB = "ByteToGB",
Apdex = "apdex",
Precision = "precision",
ConvertSeconds = "convertSeconds",
diff --git a/src/hooks/useProcessor.ts b/src/hooks/useProcessor.ts
index e928b30..b1ed0e9 100644
--- a/src/hooks/useProcessor.ts
+++ b/src/hooks/useProcessor.ts
@@ -28,6 +28,9 @@ export function useQueryProcessor(config: any) {
if (!(config.metrics && config.metrics[0])) {
return;
}
+ if (!(config.metricTypes && config.metricTypes[0])) {
+ return;
+ }
const appStore = useAppStoreWithOut();
const dashboardStore = useDashboardStore();
const selectorStore = useSelectorStore();
@@ -221,13 +224,19 @@ export function useQueryPodsMetrics(
config: { metrics: string[]; metricTypes: string[] },
scope: string
) {
+ if (!(config.metrics && config.metrics[0])) {
+ return;
+ }
+ if (!(config.metricTypes && config.metricTypes[0])) {
+ return;
+ }
const appStore = useAppStoreWithOut();
const selectorStore = useSelectorStore();
const conditions: { [key: string]: unknown } = {
duration: appStore.durationTime,
};
const variables: string[] = [`$duration: Duration!`];
- const { currentService } = selectorStore;
+ const currentService = selectorStore.currentService || {};
const fragmentList = pods.map(
(
d: (Instance | Endpoint | Service) & { normal: boolean },
@@ -324,6 +333,12 @@ export function aggregation(val: number, config: any):
number | string {
case Calculations.ByteToKB:
data = val / 1024;
break;
+ case Calculations.ByteToMB:
+ data = val / 1024 / 1024;
+ break;
+ case Calculations.ByteToGB:
+ data = val / 1024 / 1024 / 1024;
+ break;
case Calculations.Apdex:
data = val / 10000;
break;
diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts
index 609c05e..0f19874 100644
--- a/src/locales/lang/en.ts
+++ b/src/locales/lang/en.ts
@@ -38,8 +38,8 @@ const msg = {
health: "Health",
groupName: "Group Name",
topologies: "Topologies",
- dataPanel: "Data Panel",
- controlPanel: "Control Panel",
+ dataPanel: "Data Plane",
+ controlPanel: "Control Plane",
eventList: "Event List",
databasePanel: "Database Panel",
meshServicePanel: "Service Panel",
@@ -129,6 +129,7 @@ const msg = {
textAlign: "Text Align",
metricLabel: "Metric Label",
showUnit: "Show Unit",
+ noGraph: "No Graph",
hourTip: "Select Hour",
minuteTip: "Select Minute",
secondTip: "Select Second",
diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts
index 43f09eb..c607407 100644
--- a/src/locales/lang/zh.ts
+++ b/src/locales/lang/zh.ts
@@ -129,6 +129,7 @@ const msg = {
textAlign: "文本对齐",
metricLabel: "指标标签",
showUnit: "显示单位",
+ noGraph: "无图表",
hourTip: "选择小时",
minuteTip: "选择分钟",
secondTip: "选择秒数",
diff --git a/src/store/data.ts b/src/store/data.ts
index eba3c3b..d6d3e01 100644
--- a/src/store/data.ts
+++ b/src/store/data.ts
@@ -21,14 +21,6 @@ export const NewControl = {
h: 12,
i: "0",
type: "Widget",
- widget: {
- title: "",
- },
- graph: {},
- standard: {},
- metrics: [""],
- metricTypes: [""],
- metricConfig: [],
};
export const TextConfig = {
fontColor: "white",
diff --git a/src/types/dashboard.ts b/src/types/dashboard.ts
index fc56a4d..d06213b 100644
--- a/src/types/dashboard.ts
+++ b/src/types/dashboard.ts
@@ -28,13 +28,12 @@ export interface LayoutConfig {
w: number;
h: number;
i: string;
- widget: WidgetConfig;
- graph: GraphConfig;
- standard: StandardConfig;
- metrics: string[];
+ widget?: WidgetConfig;
+ graph?: GraphConfig;
+ metrics?: string[];
type: string;
- metricTypes: string[];
- children?: any;
+ metricTypes?: string[];
+ children?: { name: string; children: LayoutConfig[] }[];
activedTabIndex?: number;
metricConfig?: MetricConfigOpt[];
}
@@ -53,20 +52,6 @@ export interface WidgetConfig {
tips?: string;
}
-export interface StandardConfig {
- sortOrder?: string;
- unit?: string;
- labelsIndex?: string;
- metricLabels?: string;
- plus?: string;
- minus?: string;
- multiply?: string;
- divide?: string;
- milliseconds?: string;
- seconds?: string;
- maxItemNum?: number;
-}
-
export type GraphConfig =
| BarConfig
| LineConfig
diff --git a/src/views/dashboard/configuration/Text.vue
b/src/views/dashboard/configuration/Text.vue
index 2e29815..722dfd3 100644
--- a/src/views/dashboard/configuration/Text.vue
+++ b/src/views/dashboard/configuration/Text.vue
@@ -91,12 +91,13 @@ import { useDashboardStore } from
"@/store/modules/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const originConfig = dashboardStore.selectedGrid;
+const graph = originConfig.graph || {};
const url = ref(originConfig.graph.url || "");
-const backgroundColor = ref(originConfig.graph.backgroundColor || "green");
-const fontColor = ref(originConfig.graph.fontColor || "white");
-const content = ref<string>(originConfig.graph.content || "");
-const fontSize = ref<number>(originConfig.graph.fontSize || 12);
-const textAlign = ref(originConfig.graph.textAlign || "left");
+const backgroundColor = ref(graph.backgroundColor || "green");
+const fontColor = ref(graph.fontColor || "white");
+const content = ref<string>(graph.content || "");
+const fontSize = ref<number>(graph.fontSize || 12);
+const textAlign = ref(graph.textAlign || "left");
const Colors = [
{
label: "Green",
diff --git a/src/views/dashboard/configuration/Topology.vue
b/src/views/dashboard/configuration/Topology.vue
index e9b2800..dac5d4d 100644
--- a/src/views/dashboard/configuration/Topology.vue
+++ b/src/views/dashboard/configuration/Topology.vue
@@ -48,9 +48,9 @@ import { Option } from "@/types/app";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
-const { selectedGrid } = dashboardStore;
-const showDepth = ref<boolean>(selectedGrid.graph.showDepth);
-const depth = ref<number>(selectedGrid.graph.depth || 2);
+const graph = dashboardStore.selectedGrid.graph || {};
+const showDepth = ref<boolean>(graph.showDepth);
+const depth = ref<number>(graph.depth || 2);
function applyConfig() {
dashboardStore.setConfigs(dashboardStore.selectedGrid);
diff --git a/src/views/dashboard/configuration/Widget.vue
b/src/views/dashboard/configuration/Widget.vue
index 13239a6..6e60c63 100644
--- a/src/views/dashboard/configuration/Widget.vue
+++ b/src/views/dashboard/configuration/Widget.vue
@@ -16,20 +16,20 @@ limitations under the License. -->
<div class="widget-config flex-v">
<div class="graph" v-loading="loading">
<div class="header">
- <span>{{ dashboardStore.selectedGrid.widget.title || "" }}</span>
- <div class="tips" v-show="dashboardStore.selectedGrid.widget.tips">
- <el-tooltip :content="dashboardStore.selectedGrid.widget.tips || ''">
+ <span>{{ widget.title || "" }}</span>
+ <div class="tips" v-show="widget.tips">
+ <el-tooltip :content="widget.tips || ''">
<Icon iconName="info_outline" size="sm" />
</el-tooltip>
</div>
</div>
<div class="render-chart">
<component
- :is="dashboardStore.selectedGrid.graph.type"
+ :is="graph.type"
:intervalTime="appStoreWithOut.intervalTime"
:data="states.source"
:config="{
- ...dashboardStore.selectedGrid.graph,
+ ...graph,
i: dashboardStore.selectedGrid.i,
metrics: dashboardStore.selectedGrid.metrics,
metricTypes: dashboardStore.selectedGrid.metricTypes,
@@ -38,7 +38,7 @@ limitations under the License. -->
:isEdit="isEdit"
@changeOpt="setStatus"
/>
- <div v-show="!dashboardStore.selectedGrid.graph.type" class="no-data">
+ <div v-show="!graph.type" class="no-data">
{{ t("noData") }}
</div>
</div>
@@ -56,7 +56,7 @@ limitations under the License. -->
/>
</el-collapse-item>
<el-collapse-item :title="t('graphStyles')" name="2">
- <component :is="`${dashboardStore.selectedGrid.graph.type}Config`" />
+ <component :is="`${graph.type}Config`" />
</el-collapse-item>
<el-collapse-item :title="t('widgetOptions')" name="3">
<WidgetOptions />
@@ -74,7 +74,7 @@ limitations under the License. -->
</div>
</template>
<script lang="ts">
-import { reactive, defineComponent, ref } from "vue";
+import { reactive, defineComponent, ref, computed } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app";
@@ -111,6 +111,8 @@ export default defineComponent({
visType: [],
});
const originConfig = dashboardStore.selectedGrid;
+ const widget = computed(() => dashboardStore.selectedGrid.widget || {});
+ const graph = computed(() => dashboardStore.selectedGrid.graph || {});
function getSource(source: unknown) {
states.source = source;
@@ -148,6 +150,8 @@ export default defineComponent({
setLoading,
setStatus,
isEdit,
+ widget,
+ graph,
};
},
});
diff --git a/src/views/dashboard/configuration/widget/WidgetOptions.vue
b/src/views/dashboard/configuration/widget/WidgetOptions.vue
index 0d38ffe..b9d707e 100644
--- a/src/views/dashboard/configuration/widget/WidgetOptions.vue
+++ b/src/views/dashboard/configuration/widget/WidgetOptions.vue
@@ -42,12 +42,13 @@ import { useDashboardStore } from
"@/store/modules/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const { selectedGrid } = dashboardStore;
-const title = ref<string>(selectedGrid.widget.title || "");
-const tips = ref<string>(selectedGrid.widget.tips || "");
+const widget = dashboardStore.selectedGrid.widget || {};
+const title = ref<string>(widget.title || "");
+const tips = ref<string>(widget.tips || "");
function updateWidgetConfig(param: { [key: string]: unknown }) {
const widget = {
- ...selectedGrid.widget,
+ ...dashboardStore.selectedGrid.widget,
...param,
};
dashboardStore.selectWidget({ ...selectedGrid, widget });
diff --git a/src/views/dashboard/configuration/widget/graph-styles/HeatMap.vue
b/src/views/dashboard/configuration/widget/graph-styles/HeatMap.vue
index de9a4da..66b10f9 100644
--- a/src/views/dashboard/configuration/widget/graph-styles/HeatMap.vue
+++ b/src/views/dashboard/configuration/widget/graph-styles/HeatMap.vue
@@ -34,7 +34,8 @@ import { useDashboardStore } from "@/store/modules/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
-const fontSize = ref(dashboardStore.selectedGrid.graph.fontSize);
+const graph = dashboardStore.selectedGrid.graph || {};
+const fontSize = ref(graph.fontSize);
function updateConfig(param: { [key: string]: unknown }) {
const graph = {
diff --git a/src/views/dashboard/configuration/widget/metric/Index.vue
b/src/views/dashboard/configuration/widget/metric/Index.vue
index adad743..e84e7f4 100644
--- a/src/views/dashboard/configuration/widget/metric/Index.vue
+++ b/src/views/dashboard/configuration/widget/metric/Index.vue
@@ -43,9 +43,7 @@ limitations under the License. -->
:value="states.metricTypes[index]"
:options="states.metricTypeList[index]"
size="small"
- :disabled="
- dashboardStore.selectedGrid.graph.type && !states.isList && index !== 0
- "
+ :disabled="graph.type && !states.isList && index !== 0"
@change="changeMetricType(index, $event)"
class="selectors"
/>
@@ -85,11 +83,11 @@ limitations under the License. -->
<div>{{ t("visualization") }}</div>
<div class="chart-types">
<span
- v-for="(type, index) in states.visTypes"
+ v-for="(type, index) in setVisTypes"
:key="index"
@click="changeChartType(type)"
:class="{
- active: type.value === dashboardStore.selectedGrid.graph.type,
+ active: type.value === graph.type,
}"
>
{{ type.label }}
@@ -97,7 +95,7 @@ limitations under the License. -->
</div>
</template>
<script lang="ts" setup>
-import { reactive, ref } from "vue";
+import { reactive, ref, computed } from "vue";
import { Option } from "@/types/app";
import { useDashboardStore } from "@/store/modules/dashboard";
import {
@@ -124,24 +122,26 @@ import Standard from "./Standard.vue";
const { t } = useI18n();
const emit = defineEmits(["update", "loading", "changeOpt"]);
const dashboardStore = useDashboardStore();
-const { metrics, metricTypes, graph } = dashboardStore.selectedGrid;
+const metrics = computed(() => dashboardStore.selectedGrid.metrics || []);
+const graph = computed(() => dashboardStore.selectedGrid.graph || {});
+const metricTypes = computed(
+ () => dashboardStore.selectedGrid.metricTypes || []
+);
const states = reactive<{
metrics: string[];
metricTypes: string[];
metricTypeList: Option[][];
- visTypes: Option[];
isList: boolean;
metricList: (Option & { type: string })[];
dashboardName: string;
dashboardList: ((DashboardItem & { label: string; value: string }) | any)[];
}>({
- metrics: metrics && metrics.length ? metrics : [""],
- metricTypes: metricTypes && metricTypes.length ? metricTypes : [""],
+ metrics: metrics.value.length ? metrics.value : [""],
+ metricTypes: metricTypes.value.length ? metricTypes.value : [""],
metricTypeList: [],
- visTypes: [],
isList: false,
metricList: [],
- dashboardName: graph.dashboardName,
+ dashboardName: graph.value.dashboardName,
dashboardList: [{ label: "", value: "" }],
});
const currentMetricConfig = ref<MetricConfigOpt>({
@@ -152,15 +152,33 @@ const currentMetricConfig = ref<MetricConfigOpt>({
sortOrder: "DES",
});
-states.isList = ListChartTypes.includes(graph.type);
+states.isList = ListChartTypes.includes(graph.value.type);
const defaultLen = ref<number>(states.isList ? 5 : 20);
-states.visTypes = setVisTypes();
-
setDashboards();
setMetricType();
+const setVisTypes = computed(() => {
+ let graphs = [];
+ if (dashboardStore.entity === EntityType[0].value) {
+ graphs = ChartTypes.filter(
+ (d: Option) =>
+ ![ChartTypes[7].value, ChartTypes[8].value].includes(d.value)
+ );
+ } else if (dashboardStore.entity === EntityType[1].value) {
+ graphs = ChartTypes.filter(
+ (d: Option) => !PodsChartTypes.includes(d.value)
+ );
+ } else {
+ graphs = ChartTypes.filter(
+ (d: Option) => !ListChartTypes.includes(d.value)
+ );
+ }
+
+ return graphs;
+});
+
async function setMetricType(chart?: any) {
- const graph = chart || dashboardStore.selectedGrid.graph;
+ const g = chart || dashboardStore.selectedGrid.graph || {};
const json = await dashboardStore.fetchMetricList();
if (json.errors) {
ElMessage.error(json.errors);
@@ -172,7 +190,7 @@ async function setMetricType(chart?: any) {
if (d.type === MetricsType.REGULAR_VALUE) {
return d;
}
- } else if (graph.type === "Table") {
+ } else if (g.type === "Table") {
if (
d.type === MetricsType.LABELED_VALUE ||
d.type === MetricsType.REGULAR_VALUE
@@ -203,7 +221,7 @@ async function setMetricType(chart?: any) {
...dashboardStore.selectedGrid,
metrics: states.metrics,
metricTypes: states.metricTypes,
- graph,
+ graph: g,
});
states.metricTypeList = [];
for (const metric of metrics) {
@@ -220,7 +238,7 @@ async function setMetricType(chart?: any) {
}
function setDashboards(type?: string) {
- const graph = type || dashboardStore.selectedGrid.graph;
+ const chart = type || dashboardStore.selectedGrid.graph || {};
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
const arr = list.reduce(
(
@@ -229,9 +247,9 @@ function setDashboards(type?: string) {
) => {
if (d.layer === dashboardStore.layerId) {
if (
- (d.entity === EntityType[0].value && graph.type === "ServiceList") ||
- (d.entity === EntityType[2].value && graph.type === "EndpointList")
||
- (d.entity === EntityType[3].value && graph.type === "InstanceList")
+ (d.entity === EntityType[0].value && chart.type === "ServiceList") ||
+ (d.entity === EntityType[2].value && chart.type === "EndpointList")
||
+ (d.entity === EntityType[3].value && chart.type === "InstanceList")
) {
prev.push({
...d,
@@ -248,26 +266,9 @@ function setDashboards(type?: string) {
states.dashboardList = arr.length ? arr : [{ label: "", value: "" }];
}
-function setVisTypes() {
- let graphs = [];
- if (dashboardStore.entity === EntityType[0].value) {
- graphs = ChartTypes.filter((d: Option) => d.value !== ChartTypes[7].value);
- } else if (dashboardStore.entity === EntityType[1].value) {
- graphs = ChartTypes.filter(
- (d: Option) => !PodsChartTypes.includes(d.value)
- );
- } else {
- graphs = ChartTypes.filter(
- (d: Option) => !ListChartTypes.includes(d.value)
- );
- }
-
- return graphs;
-}
-
function changeChartType(item: Option) {
- const graph = DefaultGraphConfig[item.value];
- states.isList = ListChartTypes.includes(graph.type);
+ const chart = DefaultGraphConfig[item.value] || {};
+ states.isList = ListChartTypes.includes(chart.type);
if (states.isList) {
dashboardStore.selectWidget({
...dashboardStore.selectedGrid,
@@ -278,8 +279,8 @@ function changeChartType(item: Option) {
states.metricTypes = [""];
defaultLen.value = 5;
}
- setMetricType(graph);
- setDashboards(graph.type);
+ setMetricType(chart);
+ setDashboards(chart.type);
states.dashboardName = "";
defaultLen.value = 10;
}
@@ -415,7 +416,7 @@ function setMetricTypeList(type: string) {
if (type !== MetricsType.REGULAR_VALUE) {
return MetricTypes[type];
}
- if (states.isList || dashboardStore.selectedGrid.graph.type === "Table") {
+ if (states.isList || graph.value.type === "Table") {
return [
{ label: "read all values in the duration", value: "readMetricsValues" },
{
diff --git a/src/views/dashboard/configuration/widget/metric/Standard.vue
b/src/views/dashboard/configuration/widget/metric/Standard.vue
index 6f873d8..046a938 100644
--- a/src/views/dashboard/configuration/widget/metric/Standard.vue
+++ b/src/views/dashboard/configuration/widget/metric/Standard.vue
@@ -56,7 +56,7 @@ limitations under the License. -->
:clearable="true"
/>
</div>
- <div class="item" v-show="isTopn">
+ <div class="item mb-10" v-show="isTopn">
<span class="label">{{ t("sortOrder") }}</span>
<SelectSingle
:value="currentMetric.sortOrder || 'DES'"
@@ -67,11 +67,12 @@ limitations under the License. -->
</div>
<div class="item" v-show="isTopn">
<span class="label">{{ t("maxItemNum") }}</span>
- <el-input-number
+ <el-input
class="selectors"
v-model="currentMetric.topN"
size="small"
placeholder="none"
+ type="number"
:min="1"
:max="100"
@change="changeConfigs(index, { topN: currentMetric.topN || 10 })"
@@ -102,13 +103,10 @@ const currentMetric = ref<MetricConfigOpt>({
...props.currentMetricConfig,
topN: props.currentMetricConfig.topN || 10,
});
-const metricType = ref<string>(
- dashboardStore.selectedGrid.metricTypes[props.index]
-);
+const metricTypes = dashboardStore.selectedGrid.metricTypes || [];
+const metricType = ref<string>(metricTypes[props.index]);
const isTopn = computed(() =>
- ["sortMetrics", "readSampledRecords"].includes(
- dashboardStore.selectedGrid.metricTypes[props.index]
- )
+ ["sortMetrics", "readSampledRecords"].includes(metricTypes[props.index])
);
function changeConfigs(
index: number,
diff --git a/src/views/dashboard/controls/Widget.vue
b/src/views/dashboard/controls/Widget.vue
index 511f59c..29c5079 100644
--- a/src/views/dashboard/controls/Widget.vue
+++ b/src/views/dashboard/controls/Widget.vue
@@ -17,17 +17,17 @@ limitations under the License. -->
<div class="header flex-h">
<div>
<span>
- {{ data.widget?.title || "" }}
+ {{ widget.title || "" }}
</span>
</div>
<div>
- <el-tooltip :content="data.widget?.tips">
+ <el-tooltip :content="widget.tips || ''">
<span>
<Icon
iconName="info_outline"
size="sm"
class="operation"
- v-show="data.widget?.tips"
+ v-show="widget.tips"
/>
</span>
</el-tooltip>
@@ -51,26 +51,26 @@ limitations under the License. -->
</el-popover>
</div>
</div>
- <div class="body" v-if="data.graph?.type" v-loading="loading">
+ <div class="body" v-if="graph.type" v-loading="loading">
<component
- :is="data.graph.type"
+ :is="graph.type"
:intervalTime="appStore.intervalTime"
:data="state.source"
:config="{
...data.graph,
- metrics: data.metrics,
- metricTypes: data.metricTypes,
+ metrics: data.metrics || [''],
+ metricTypes: data.metricTypes || [''],
i: data.i,
metricConfig: data.metricConfig,
}"
:needQuery="needQuery"
/>
</div>
- <div v-else class="no-data">{{ t("noData") }}</div>
+ <div v-else class="no-data">{{ t("noGraph") }}</div>
</div>
</template>
<script lang="ts">
-import { toRefs, reactive, defineComponent, ref, watch } from "vue";
+import { toRefs, reactive, defineComponent, ref, watch, computed } from "vue";
import type { PropType } from "vue";
import { LayoutConfig } from "@/types/dashboard";
import { useDashboardStore } from "@/store/modules/dashboard";
@@ -88,7 +88,7 @@ import { EntityType, ListChartTypes } from "../data";
const props = {
data: {
type: Object as PropType<LayoutConfig>,
- default: () => ({ widget: {} }),
+ default: () => ({ widget: {}, graph: {} }),
},
activeIndex: { type: String, default: "" },
needQuery: { type: Boolean, default: false },
@@ -107,14 +107,19 @@ export default defineComponent({
const appStore = useAppStoreWithOut();
const dashboardStore = useDashboardStore();
const selectorStore = useSelectorStore();
- const isList = ListChartTypes.includes(props.data.graph.type || "");
+ const graph = computed(() => props.data.graph || {});
+ const widget = computed(() => props.data.widget || {});
+ const isList = ListChartTypes.includes(
+ (props.data.graph && props.data.graph.type) || ""
+ );
if ((props.needQuery || !dashboardStore.currentDashboard.id) && !isList) {
queryMetrics();
}
async function queryMetrics() {
- const { metricTypes, metrics } = props.data;
+ const metricTypes = props.data.metricTypes || [];
+ const metrics = props.data.metrics || [];
const catalog = await useGetMetricEntity(metrics[0], metricTypes[0]);
const params = await useQueryProcessor({ ...props.data, catalog });
@@ -129,8 +134,8 @@ export default defineComponent({
return;
}
const d = {
- metrics: props.data.metrics,
- metricTypes: props.data.metricTypes,
+ metrics: props.data.metrics || [],
+ metricTypes: props.data.metricTypes || [],
metricConfig: props.data.metricConfig || [],
};
state.source = useSourceProcessor(json, d);
@@ -149,7 +154,7 @@ export default defineComponent({
}
}
watch(
- () => [props.data.metricTypes, props.data.metrics, props.data.standard],
+ () => [props.data.metricTypes, props.data.metrics],
() => {
if (!dashboardStore.selectedGrid) {
return;
@@ -157,11 +162,11 @@ export default defineComponent({
if (props.data.i !== dashboardStore.selectedGrid.i) {
return;
}
- const isList = ListChartTypes.includes(props.data.graph.type || "");
- if (
- ListChartTypes.includes(dashboardStore.selectedGrid.graph.type) ||
- isList
- ) {
+ const isList = ListChartTypes.includes(
+ (props.data.graph && props.data.graph.type) || ""
+ );
+ const chart = dashboardStore.selectedGrid.graph || {};
+ if (ListChartTypes.includes(chart.type) || isList) {
return;
}
queryMetrics();
@@ -170,7 +175,9 @@ export default defineComponent({
watch(
() => [selectorStore.currentService, selectorStore.currentDestService],
() => {
- const isList = ListChartTypes.includes(props.data.graph.type || "");
+ const isList = ListChartTypes.includes(
+ (props.data.graph && props.data.graph.type) || ""
+ );
if (isList) {
return;
}
@@ -209,6 +216,8 @@ export default defineComponent({
loading,
dashboardStore,
t,
+ graph,
+ widget,
};
},
});
diff --git a/src/views/dashboard/data.ts b/src/views/dashboard/data.ts
index 9c57902..e1b0d4f 100644
--- a/src/views/dashboard/data.ts
+++ b/src/views/dashboard/data.ts
@@ -269,8 +269,10 @@ export const TextColors: { [key: string]: string } = {
export const CalculationOpts = [
{ label: "Percentage", value: "percentage" },
- { label: "Byte to KB", value: "byteToKB" },
{ label: "Apdex", value: "apdex" },
+ { label: "Byte to KB", value: "byteToKB" },
+ { label: "Byte to MB", value: "byteToMB" },
+ { label: "Byte to GB", value: "byteToGB" },
{
label: "Convert milliseconds to YYYY-MM-DD HH:mm:ss",
value: "convertMilliseconds",
diff --git a/src/views/dashboard/graphs/Bar.vue
b/src/views/dashboard/graphs/Bar.vue
index a6737b0..8a7012a 100644
--- a/src/views/dashboard/graphs/Bar.vue
+++ b/src/views/dashboard/graphs/Bar.vue
@@ -137,13 +137,15 @@ function getOption() {
color,
tooltip: {
trigger: "axis",
- // backgroundColor: "rgb(50,50,50)",
- // textStyle: {
- // fontSize: 13,
- // color: "#ccc",
- // },
- // enterable: true,
- // extraCssText: "max-height: 300px; overflow: auto;",
+ zlevel: 1000,
+ z: 60,
+ backgroundColor: "rgb(50,50,50)",
+ textStyle: {
+ fontSize: 13,
+ color: "#ccc",
+ },
+ enterable: true,
+ extraCssText: "max-height: 300px; overflow: auto; border: none",
},
legend: {
type: "scroll",
diff --git a/src/views/dashboard/graphs/Card.vue
b/src/views/dashboard/graphs/Card.vue
index b715881..2c33eaf 100644
--- a/src/views/dashboard/graphs/Card.vue
+++ b/src/views/dashboard/graphs/Card.vue
@@ -15,21 +15,17 @@ limitations under the License. -->
<template>
<div
+ v-if="!isNaN(singleVal)"
class="chart-card"
:class="{ center: config.textAlign === 'center' }"
:style="{ fontSize: `${config.fontSize}px`, textAlign: config.textAlign }"
>
- {{
- typeof singleVal === "string"
- ? singleVal
- : isNaN(singleVal)
- ? null
- : singleVal.toFixed(2)
- }}
+ {{ singleVal.toFixed(2) }}
<span v-show="config.showUnit">
{{ metricConfig[0]?.unit }}
</span>
</div>
+ <div class="center no-data" v-else>No Data</div>
</template>
<script lang="ts" setup>
import { computed, PropType } from "vue";
@@ -53,7 +49,7 @@ const props = defineProps({
});
const metricConfig = computed(() => props.config.metricConfig || []);
const key = computed(() => Object.keys(props.data)[0]);
-const singleVal = computed(() => props.data[key.value]);
+const singleVal = computed(() => Number(props.data[key.value]));
</script>
<style lang="scss" scoped>
.chart-card {
@@ -68,4 +64,9 @@ const singleVal = computed(() => props.data[key.value]);
-webkit-box-pack: center;
-webkit-box-align: center;
}
+
+.no-data {
+ height: 100%;
+ color: #666;
+}
</style>
diff --git a/src/views/dashboard/graphs/EndpointList.vue
b/src/views/dashboard/graphs/EndpointList.vue
index fe08b8e..9101137 100644
--- a/src/views/dashboard/graphs/EndpointList.vue
+++ b/src/views/dashboard/graphs/EndpointList.vue
@@ -65,17 +65,6 @@ limitations under the License. -->
</el-table-column>
</el-table>
</div>
- <el-pagination
- class="pagination"
- background
- small
- layout="prev, pager, next"
- :page-size="pageSize"
- :total="selectorStore.pods.length"
- @current-change="changePage"
- @prev-click="changePage"
- @next-click="changePage"
- />
</div>
</template>
<script setup lang="ts">
@@ -107,7 +96,13 @@ const props = defineProps({
metricTypes: string[];
} & { metricConfig: MetricConfigOpt[] }
>,
- default: () => ({ dashboardName: "", fontSize: 12, i: "" }),
+ default: () => ({
+ metrics: [],
+ metricTypes: [],
+ dashboardName: "",
+ fontSize: 12,
+ i: "",
+ }),
},
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
isEdit: { type: Boolean, default: false },
@@ -117,7 +112,6 @@ const selectorStore = useSelectorStore();
const dashboardStore = useDashboardStore();
const chartLoading = ref<boolean>(false);
const endpoints = ref<Endpoint[]>([]);
-const pageSize = 10;
const searchText = ref<string>("");
queryEndpoints();
@@ -133,18 +127,16 @@ async function queryEndpoints() {
ElMessage.error(resp.errors);
return;
}
- endpoints.value = selectorStore.pods.filter(
- (d: unknown, index: number) => index < pageSize
- );
+ endpoints.value = selectorStore.pods;
queryEndpointMetrics(endpoints.value);
}
async function queryEndpointMetrics(currentPods: Endpoint[]) {
if (!currentPods.length) {
return;
}
- const metrics = props.config.metrics.filter((d: string) => d);
-
- if (metrics.length && metrics[0]) {
+ const metrics = (props.config.metrics || []).filter((d: string) => d);
+ const metricTypes = props.config.metricTypes || [];
+ if (metrics.length && metrics[0] && metricTypes.length && metricTypes[0]) {
const params = await useQueryPodsMetrics(
currentPods,
props.config,
@@ -180,14 +172,6 @@ function clickEndpoint(scope: any) {
`/dashboard/${d.layer}/${d.entity}/${selectorStore.currentService.id}/${scope.row.id}/${d.name}`
);
}
-function changePage(pageIndex: number) {
- endpoints.value = selectorStore.pods.filter((d: unknown, index: number) => {
- if (index >= (pageIndex - 1) * pageSize && index < pageIndex * pageSize) {
- return d;
- }
- });
- queryEndpointMetrics(endpoints.value);
-}
async function searchList() {
await queryEndpoints();
}
diff --git a/src/views/dashboard/graphs/HeatMap.vue
b/src/views/dashboard/graphs/HeatMap.vue
index 76036c6..80e1f73 100644
--- a/src/views/dashboard/graphs/HeatMap.vue
+++ b/src/views/dashboard/graphs/HeatMap.vue
@@ -18,7 +18,6 @@ limitations under the License. -->
<script lang="ts" setup>
import { computed } from "vue";
import type { PropType } from "vue";
-import { StandardConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
@@ -31,11 +30,7 @@ const props = defineProps({
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
config: {
type: Object as PropType<any>,
- default: () => ({}),
- },
- standard: {
- type: Object as PropType<StandardConfig>,
- default: () => ({}),
+ default: () => ({ metrics: [] }),
},
});
const option = computed(() => getOption());
diff --git a/src/views/dashboard/graphs/InstanceList.vue
b/src/views/dashboard/graphs/InstanceList.vue
index ff608a6..65d76ba 100644
--- a/src/views/dashboard/graphs/InstanceList.vue
+++ b/src/views/dashboard/graphs/InstanceList.vue
@@ -166,9 +166,9 @@ async function queryInstanceMetrics(currentInstances:
Instance[]) {
if (!currentInstances.length) {
return;
}
- const { metrics } = props.config;
+ const { metrics, metricTypes } = props.config;
- if (metrics.length && metrics[0]) {
+ if (metrics.length && metrics[0] && metricTypes.length && metricTypes[0]) {
const params = await useQueryPodsMetrics(
currentInstances,
props.config,
diff --git a/src/views/dashboard/graphs/Line.vue
b/src/views/dashboard/graphs/Line.vue
index 2df370f..978aa10 100644
--- a/src/views/dashboard/graphs/Line.vue
+++ b/src/views/dashboard/graphs/Line.vue
@@ -153,7 +153,7 @@ function getOption() {
color: "#ccc",
},
enterable: true,
- extraCssText: "max-height: 300px; overflow: auto;",
+ extraCssText: "max-height: 300px; overflow: auto; border: none",
},
legend: {
type: "scroll",
diff --git a/src/views/dashboard/graphs/ServiceList.vue
b/src/views/dashboard/graphs/ServiceList.vue
index 7bcac74..8be7cd6 100644
--- a/src/views/dashboard/graphs/ServiceList.vue
+++ b/src/views/dashboard/graphs/ServiceList.vue
@@ -210,9 +210,9 @@ async function queryServiceMetrics(currentServices:
Service[]) {
if (!currentServices.length) {
return;
}
- const { metrics } = props.config;
+ const { metrics, metricTypes } = props.config;
- if (metrics.length && metrics[0]) {
+ if (metrics.length && metrics[0] && metricTypes.length && metricTypes[0]) {
const params = await useQueryPodsMetrics(
currentServices,
props.config,
diff --git a/src/views/dashboard/graphs/TopList.vue
b/src/views/dashboard/graphs/TopList.vue
index 0b2fc18..8fe0f72 100644
--- a/src/views/dashboard/graphs/TopList.vue
+++ b/src/views/dashboard/graphs/TopList.vue
@@ -14,7 +14,7 @@ See the License for the specific language governing
permissions and
limitations under the License. -->
<template>
- <div class="top-list">
+ <div class="top-list" v-if="available">
<div class="chart-slow-i" v-for="(i, index) in data[key]" :key="index">
<div class="ell tools flex-h">
<div>
@@ -35,11 +35,12 @@ limitations under the License. -->
<el-progress
:stroke-width="6"
:percentage="(i.value / maxValue) * 100"
- :color="TextColors[config.color]"
+ :color="TextColors[config.color || 'purple']"
:show-text="false"
/>
</div>
</div>
+ <div class="center no-data" v-else>No Data</div>
</template>
<script lang="ts" setup>
import type { PropType } from "vue";
@@ -61,6 +62,12 @@ const props = defineProps({
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
});
const key = computed(() => Object.keys(props.data)[0] || "");
+const available = computed(
+ () =>
+ Array.isArray(props.data[key.value]) &&
+ props.data[key.value][0] &&
+ props.data[key.value][0].value
+);
const maxValue = computed(() => {
if (!(props.data[key.value] && props.data[key.value].length)) {
return 0;
@@ -114,4 +121,14 @@ function handleClick(i: string) {
will-change: opacity, background-color;
transition: opacity 0.3s, background-color 0.3s;
}
+
+.no-data {
+ height: 100%;
+ color: #666;
+ box-sizing: border-box;
+ display: -webkit-box;
+ -webkit-box-orient: horizontal;
+ -webkit-box-pack: center;
+ -webkit-box-align: center;
+}
</style>
diff --git a/src/views/dashboard/related/topology/components/Graph.vue
b/src/views/dashboard/related/topology/components/Graph.vue
index d8d1279..aed1c8a 100644
--- a/src/views/dashboard/related/topology/components/Graph.vue
+++ b/src/views/dashboard/related/topology/components/Graph.vue
@@ -24,7 +24,7 @@ limitations under the License. -->
<Settings @update="updateSettings" @updateNodes="freshNodes" />
</div>
<div class="tool">
- <span v-show="config.graph.showDepth">
+ <span v-show="graphConfig.showDepth">
<span class="label">{{ t("currentDepth") }}</span>
<Selector
class="inputs"
@@ -69,7 +69,14 @@ limitations under the License. -->
</template>
<script lang="ts" setup>
import type { PropType } from "vue";
-import { ref, onMounted, onBeforeUnmount, reactive, watch } from "vue";
+import {
+ ref,
+ onMounted,
+ onBeforeUnmount,
+ reactive,
+ watch,
+ computed,
+} from "vue";
import { useI18n } from "vue-i18n";
import * as d3 from "d3";
import d3tip from "d3-tip";
@@ -111,7 +118,7 @@ const loading = ref<boolean>(false);
const simulation = ref<any>(null);
const svg = ref<Nullable<any>>(null);
const chart = ref<Nullable<HTMLDivElement>>(null);
-const tip = ref<any>(null);
+const tip = ref<Nullable<HTMLDivElement>>(null);
const graph = ref<any>(null);
const node = ref<any>(null);
const link = ref<any>(null);
@@ -124,7 +131,8 @@ const operationsPos = reactive<{ x: number; y: number }>({
x: NaN, y: NaN });
const items = ref<
{ id: string; title: string; func: any; dashboard?: string }[]
>([]);
-const depth = ref<number>(props.config.graph.depth || 2);
+const graphConfig = computed(() => props.config.graph || {});
+const depth = ref<number>(graphConfig.value.depth || 2);
onMounted(async () => {
loading.value = true;
diff --git a/src/views/dashboard/related/topology/utils/legend.ts
b/src/views/dashboard/related/topology/utils/legend.ts
index bb88673..929f879 100644
--- a/src/views/dashboard/related/topology/utils/legend.ts
+++ b/src/views/dashboard/related/topology/utils/legend.ts
@@ -27,15 +27,15 @@ export default function topoLegend(
.append("image")
.attr("width", 30)
.attr("height", 30)
- .attr("x", clientWidth - (item === "CUBEERROR" ? 200 : 410))
- .attr("y", clientHeight + 50)
+ .attr("x", clientWidth - 140)
+ .attr("y", clientHeight + (item === "CUBEERROR" ? 50 : 0))
.attr("xlink:href", () =>
item === "CUBEERROR" ? icons.CUBEERROR : icons.CUBE
);
graph
.append("text")
- .attr("x", clientWidth - (item === "CUBEERROR" ? 170 : 380))
- .attr("y", clientHeight + 70)
+ .attr("x", clientWidth - 110)
+ .attr("y", clientHeight + (item === "CUBEERROR" ? 70 : 20))
.text(() => {
const desc = description || {};
return item === "CUBEERROR" ? desc.unhealthy || "" : desc.healthy ||
"";