fix: update pagination for service list, endpoint list, instance list and add legend configs (#45)

This commit is contained in:
Fine0830 2022-03-29 19:20:16 +08:00 committed by GitHub
parent 355fe215a3
commit 61d182b986
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 168 additions and 121 deletions

View File

@ -66,7 +66,7 @@ export function useQueryProcessor(config: any) {
? selectorStore.currentService.normal ? selectorStore.currentService.normal
: true, : true,
scope: config.catalog || dashboardStore.entity, scope: config.catalog || dashboardStore.entity,
topN: 10, topN: c.topN || 10,
order: c.sortOrder || "DES", order: c.sortOrder || "DES",
}; };
} else { } else {

View File

@ -217,12 +217,10 @@ export const dashboardStore = defineStore({
} }
if (actived.length === 3) { if (actived.length === 3) {
const tabIndex = Number(actived[1]); const tabIndex = Number(actived[1]);
const itemIndex = this.layout[index].children[ this.currentTabItems = this.currentTabItems.filter(
tabIndex (d: LayoutConfig) => actived[2] !== d.i
].children.findIndex((d: LayoutConfig) => actived[2] === d.i); );
this.layout[index].children[tabIndex].children = this.currentTabItems;
this.layout[index].children[tabIndex].children.splice(itemIndex, 1);
this.setCurrentTabItems(this.layout[index].children[tabIndex].children);
return; return;
} }
this.layout = this.layout.filter((d: LayoutConfig) => d.i !== item.i); this.layout = this.layout.filter((d: LayoutConfig) => d.i !== item.i);
@ -260,7 +258,6 @@ export const dashboardStore = defineStore({
const index = this.layout.findIndex( const index = this.layout.findIndex(
(d: LayoutConfig) => actived[0] === d.i (d: LayoutConfig) => actived[0] === d.i
); );
if (actived.length === 3) { if (actived.length === 3) {
const tabIndex = Number(actived[1]); const tabIndex = Number(actived[1]);
const itemIndex = this.layout[index].children[ const itemIndex = this.layout[index].children[

View File

@ -45,6 +45,7 @@ export type MetricConfigOpt = {
calculation: string; calculation: string;
labelsIndex: string; labelsIndex: string;
sortOrder: string; sortOrder: string;
topN?: number;
}; };
export interface WidgetConfig { export interface WidgetConfig {

View File

@ -16,9 +16,9 @@ limitations under the License. -->
<div class="widget-config flex-v"> <div class="widget-config flex-v">
<div class="graph" v-loading="loading"> <div class="graph" v-loading="loading">
<div class="header"> <div class="header">
<span>{{ dashboardStore.selectedGrid.widget.title }}</span> <span>{{ dashboardStore.selectedGrid.widget.title || "" }}</span>
<div class="tips" v-show="dashboardStore.selectedGrid.widget.tips"> <div class="tips" v-show="dashboardStore.selectedGrid.widget.tips">
<el-tooltip :content="dashboardStore.selectedGrid.widget.tips"> <el-tooltip :content="dashboardStore.selectedGrid.widget.tips || ''">
<Icon iconName="info_outline" size="sm" /> <Icon iconName="info_outline" size="sm" />
</el-tooltip> </el-tooltip>
</div> </div>

View File

@ -13,17 +13,15 @@ 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> <div class="item">
<span class="label">{{ t("maxItemNum") }}</span> <span class="label">{{ t("backgroundColors") }}</span>
<el-input <Selector
class="input" :value="color"
v-model="topN" :options="Colors"
size="small" size="small"
placeholder="none" placeholder="Select a color"
type="number" class="input"
:min="1" @change="updateConfig({ color: $event[0].value })"
:max="100"
@change="updateConfig({ topN })"
/> />
</div> </div>
</template> </template>
@ -35,14 +33,24 @@ import { useDashboardStore } from "@/store/modules/dashboard";
const { t } = useI18n(); const { t } = useI18n();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const { selectedGrid } = dashboardStore; const { selectedGrid } = dashboardStore;
const topN = ref(selectedGrid.graph.topN); const color = ref(selectedGrid.graph.color || "purple");
const Colors = [
{ label: "Purple", value: "purple" },
{
label: "Green",
value: "green",
},
{ label: "Blue", value: "blue" },
{ label: "Red", value: "red" },
{ label: "Orange", value: "orange" },
];
function updateConfig(param: { [key: string]: unknown }) { function updateConfig(param: { [key: string]: unknown }) {
const graph = { const graph = {
...selectedGrid.graph, ...dashboardStore.selectedGrid.graph,
...param, ...param,
}; };
dashboardStore.selectWidget({ ...selectedGrid, graph }); dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -52,4 +60,8 @@ function updateConfig(param: { [key: string]: unknown }) {
display: block; display: block;
margin-bottom: 5px; margin-bottom: 5px;
} }
.input {
width: 500px;
}
</style> </style>

View File

@ -410,7 +410,6 @@ function deleteMetric(index: number) {
...{ metricTypes: states.metricTypes, metrics: states.metrics }, ...{ metricTypes: states.metricTypes, metrics: states.metrics },
metricConfig, metricConfig,
}); });
console.log(dashboardStore.selectedGrid);
} }
function setMetricTypeList(type: string) { function setMetricTypeList(type: string) {
if (type !== MetricsType.REGULAR_VALUE) { if (type !== MetricsType.REGULAR_VALUE) {

View File

@ -56,10 +56,7 @@ limitations under the License. -->
:clearable="true" :clearable="true"
/> />
</div> </div>
<div <div class="item" v-show="isTopn">
class="item"
v-show="['sortMetrics', 'readSampledRecords'].includes(metricType)"
>
<span class="label">{{ t("sortOrder") }}</span> <span class="label">{{ t("sortOrder") }}</span>
<SelectSingle <SelectSingle
:value="currentMetric.sortOrder || 'DES'" :value="currentMetric.sortOrder || 'DES'"
@ -68,10 +65,22 @@ limitations under the License. -->
@change="changeConfigs(index, { sortOrder: $event })" @change="changeConfigs(index, { sortOrder: $event })"
/> />
</div> </div>
<div class="item" v-show="isTopn">
<span class="label">{{ t("maxItemNum") }}</span>
<el-input-number
class="selectors"
v-model="currentMetric.topN"
size="small"
placeholder="none"
:min="1"
:max="100"
@change="changeConfigs(index, { topN: currentMetric.topN || 10 })"
/>
</div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch } from "vue"; import { ref, watch, computed } from "vue";
import type { PropType } from "vue"; import type { PropType } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { SortOrder, CalculationOpts } from "../../../data"; import { SortOrder, CalculationOpts } from "../../../data";
@ -89,12 +98,22 @@ const props = defineProps({
const { t } = useI18n(); const { t } = useI18n();
const emit = defineEmits(["update"]); const emit = defineEmits(["update"]);
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const currentMetric = ref<MetricConfigOpt>(props.currentMetricConfig); const currentMetric = ref<MetricConfigOpt>({
...props.currentMetricConfig,
topN: props.currentMetricConfig.topN || 10,
});
const metricType = ref<string>( const metricType = ref<string>(
dashboardStore.selectedGrid.metricTypes[props.index] dashboardStore.selectedGrid.metricTypes[props.index]
); );
const isTopn = computed(() =>
function changeConfigs(index: number, param: { [key: string]: string }) { ["sortMetrics", "readSampledRecords"].includes(
dashboardStore.selectedGrid.metricTypes[props.index]
)
);
function changeConfigs(
index: number,
param: { [key: string]: string | number }
) {
const metricConfig = dashboardStore.selectedGrid.metricConfig || []; const metricConfig = dashboardStore.selectedGrid.metricConfig || [];
metricConfig[index] = { ...metricConfig[index], ...param }; metricConfig[index] = { ...metricConfig[index], ...param };
@ -107,7 +126,10 @@ function changeConfigs(index: number, param: { [key: string]: string }) {
watch( watch(
() => props.currentMetricConfig, () => props.currentMetricConfig,
() => { () => {
currentMetric.value = props.currentMetricConfig; currentMetric.value = {
...props.currentMetricConfig,
topN: props.currentMetricConfig.topN || 10,
};
} }
); );
</script> </script>

View File

@ -77,6 +77,7 @@ export const DefaultGraphConfig: { [key: string]: any } = {
}, },
TopList: { TopList: {
type: "TopList", type: "TopList",
color: "purple",
}, },
InstanceList: { InstanceList: {
type: "InstanceList", type: "InstanceList",
@ -263,6 +264,7 @@ export const TextColors: { [key: string]: string } = {
white: "#fff", white: "#fff",
black: "#000", black: "#000",
orange: "#E6A23C", orange: "#E6A23C",
purple: "#bf99f8",
}; };
export const CalculationOpts = [ export const CalculationOpts = [

View File

@ -117,16 +117,14 @@ const selectorStore = useSelectorStore();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const chartLoading = ref<boolean>(false); const chartLoading = ref<boolean>(false);
const endpoints = ref<Endpoint[]>([]); const endpoints = ref<Endpoint[]>([]);
const pageSize = 15; const pageSize = 10;
const total = 15;
const searchText = ref<string>(""); const searchText = ref<string>("");
queryEndpoints(total); queryEndpoints();
async function queryEndpoints(limit?: number) { async function queryEndpoints() {
chartLoading.value = true; chartLoading.value = true;
const resp = await selectorStore.getEndpoints({ const resp = await selectorStore.getEndpoints({
limit,
keyword: searchText.value, keyword: searchText.value,
}); });
@ -135,8 +133,10 @@ async function queryEndpoints(limit?: number) {
ElMessage.error(resp.errors); ElMessage.error(resp.errors);
return; return;
} }
endpoints.value = selectorStore.pods.splice(0, pageSize); endpoints.value = selectorStore.pods.filter(
await queryEndpointMetrics(endpoints.value); (d: unknown, index: number) => index < pageSize
);
queryEndpointMetrics(endpoints.value);
} }
async function queryEndpointMetrics(currentPods: Endpoint[]) { async function queryEndpointMetrics(currentPods: Endpoint[]) {
if (!currentPods.length) { if (!currentPods.length) {
@ -181,14 +181,15 @@ function clickEndpoint(scope: any) {
); );
} }
function changePage(pageIndex: number) { function changePage(pageIndex: number) {
endpoints.value = selectorStore.pods.splice( endpoints.value = selectorStore.pods.filter((d: unknown, index: number) => {
(pageIndex - 1 || 0) * pageSize, if (index >= (pageIndex - 1) * pageSize && index < pageIndex * pageSize) {
pageSize * (pageIndex || 1) return d;
); }
});
queryEndpointMetrics(endpoints.value);
} }
async function searchList() { async function searchList() {
const limit = searchText.value ? undefined : total; await queryEndpoints();
await queryEndpoints(limit);
} }
function getUnit(index: number) { function getUnit(index: number) {
const u = const u =
@ -211,7 +212,7 @@ watch(
watch( watch(
() => selectorStore.currentService, () => selectorStore.currentService,
() => { () => {
queryEndpoints(total); queryEndpoints();
} }
); );
</script> </script>

View File

@ -90,7 +90,7 @@ limitations under the License. -->
small small
layout="prev, pager, next" layout="prev, pager, next"
:page-size="pageSize" :page-size="pageSize"
:total="searchInstances.length" :total="selectorStore.pods.length"
@current-change="changePage" @current-change="changePage"
@prev-click="changePage" @prev-click="changePage"
@next-click="changePage" @next-click="changePage"
@ -142,8 +142,7 @@ const selectorStore = useSelectorStore();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const chartLoading = ref<boolean>(false); const chartLoading = ref<boolean>(false);
const instances = ref<Instance[]>([]); // current instances const instances = ref<Instance[]>([]); // current instances
const searchInstances = ref<Instance[]>([]); // all instances const pageSize = 10;
const pageSize = 15;
const searchText = ref<string>(""); const searchText = ref<string>("");
queryInstance(); queryInstance();
@ -154,12 +153,12 @@ async function queryInstance() {
chartLoading.value = false; chartLoading.value = false;
if (resp && resp.errors) { if (resp && resp.errors) {
ElMessage.error(resp.errors); ElMessage.error(resp.errors);
searchInstances.value = [];
instances.value = []; instances.value = [];
return; return;
} }
searchInstances.value = selectorStore.pods; instances.value = selectorStore.pods.filter(
instances.value = searchInstances.value.splice(0, pageSize); (d: unknown, index: number) => index < pageSize
);
queryInstanceMetrics(instances.value); queryInstanceMetrics(instances.value);
} }
@ -209,14 +208,22 @@ function clickInstance(scope: any) {
} }
function changePage(pageIndex: number) { function changePage(pageIndex: number) {
instances.value = searchInstances.value.splice(pageIndex - 1, pageSize); instances.value = selectorStore.pods.filter((d: unknown, index: number) => {
if (index >= (pageIndex - 1) * pageSize && index < pageIndex * pageSize) {
return d;
}
});
queryInstanceMetrics(instances.value);
} }
function searchList() { function searchList() {
searchInstances.value = selectorStore.pods.filter((d: { label: string }) => const searchInstances = selectorStore.pods.filter((d: { label: string }) =>
d.label.includes(searchText.value) d.label.includes(searchText.value)
); );
instances.value = searchInstances.value.splice(0, pageSize); instances.value = searchInstances.filter(
(d: unknown, index: number) => index < pageSize
);
queryInstanceMetrics(instances.value);
} }
function getUnit(index: number) { function getUnit(index: number) {

View File

@ -128,7 +128,7 @@ const props = defineProps({
const selectorStore = useSelectorStore(); const selectorStore = useSelectorStore();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const chartLoading = ref<boolean>(false); const chartLoading = ref<boolean>(false);
const pageSize = 15; const pageSize = 10;
const services = ref<Service[]>([]); const services = ref<Service[]>([]);
const searchText = ref<string>(""); const searchText = ref<string>("");
const groups = ref<any>({}); const groups = ref<any>({});
@ -144,8 +144,21 @@ async function queryServices() {
if (resp.errors) { if (resp.errors) {
ElMessage.error(resp.errors); ElMessage.error(resp.errors);
} }
setServices(selectorStore.services); sortServices.value = selectorStore.services.sort((a: any, b: any) => {
queryServiceMetrics(services.value); const groupA = a.group.toUpperCase();
const groupB = b.group.toUpperCase();
if (groupA < groupB) {
return -1;
}
if (groupA > groupB) {
return 1;
}
return 0;
});
const s = sortServices.value.filter(
(d: Service, index: number) => index < pageSize
);
setServices(s);
} }
function setServices(arr: (Service & { merge: boolean })[]) { function setServices(arr: (Service & { merge: boolean })[]) {
@ -164,23 +177,19 @@ function setServices(arr: (Service & { merge: boolean })[]) {
}, },
{} {}
); );
sortServices.value = Object.values(map).flat(1); const list = Object.values(map).flat(1);
const obj = {} as any; const obj = {} as any;
for (const s of sortServices.value) { for (const s of list) {
s.group = s.group || ""; s.group = s.group || "";
if (!obj[s.group]) { if (!obj[s.group]) {
obj[s.group] = 1; obj[s.group] = 1;
} else { } else {
if (obj[s.group] % 5 === 0) {
s.merge = false;
}
obj[s.group]++; obj[s.group]++;
} }
groups.value[s.group] = obj[s.group]; groups.value[s.group] = obj[s.group];
} }
services.value = sortServices.value.filter( services.value = list;
(d: Service, index: number) => index < pageSize queryServiceMetrics(services.value);
);
} }
function clickService(scope: any) { function clickService(scope: any) {
@ -240,20 +249,22 @@ function objectSpanMethod(param: any): any {
return { rowspan: groups.value[param.row.group], colspan: 1 }; return { rowspan: groups.value[param.row.group], colspan: 1 };
} }
function changePage(pageIndex: number) { function changePage(pageIndex: number) {
services.value = sortServices.value.filter((d: Service, index: number) => { const arr = sortServices.value.filter((d: Service, index: number) => {
if ( if (index >= (pageIndex - 1) * pageSize && index < pageSize * pageIndex) {
index >= (pageIndex - 1 || 0) * pageSize &&
index < pageSize * (pageIndex || 1)
) {
return d; return d;
} }
}); });
setServices(arr);
} }
function searchList() { function searchList() {
const searchServices = sortServices.value.filter((d: { label: string }) => const searchServices = sortServices.value.filter((d: { label: string }) =>
d.label.includes(searchText.value) d.label.includes(searchText.value)
); );
services.value = searchServices.splice(0, pageSize); const services = searchServices.filter(
(d: unknown, index: number) => index < pageSize
);
setServices(services);
} }
function getUnit(index: number) { function getUnit(index: number) {
const u = const u =

View File

@ -15,12 +15,12 @@ limitations under the License. -->
<template> <template>
<div class="top-list"> <div class="top-list">
<div class="chart-slow-i" v-for="(i, index) in datas" :key="index"> <div class="chart-slow-i" v-for="(i, index) in data[key]" :key="index">
<div class="ell tools flex-h"> <div class="ell tools flex-h">
<div> <div>
<span class="calls mr-10">{{ i.value }}</span> <span class="calls mr-10">{{ i.value }}</span>
<span class="cp mr-20"> <span class="cp mr-20">
{{ i.name + getTraceId(i) }} {{ i.name }}
</span> </span>
</div> </div>
<div> <div>
@ -28,14 +28,14 @@ limitations under the License. -->
iconName="review-list" iconName="review-list"
size="middle" size="middle"
class="cp" class="cp"
@click="handleClick((i.traceIds && i.traceIds[0]) || i.name)" @click="handleClick(i.name)"
/> />
</div> </div>
</div> </div>
<el-progress <el-progress
:stroke-width="6" :stroke-width="6"
:percentage="(i.value / maxValue) * 100" :percentage="(i.value / maxValue) * 100"
color="#bf99f8" :color="TextColors[config.color]"
:show-text="false" :show-text="false"
/> />
</div> </div>
@ -45,6 +45,7 @@ limitations under the License. -->
import type { PropType } from "vue"; import type { PropType } from "vue";
import { computed } from "vue"; import { computed } from "vue";
import copy from "@/utils/copy"; import copy from "@/utils/copy";
import { TextColors } from "@/views/dashboard/data";
/*global defineProps */ /*global defineProps */
const props = defineProps({ const props = defineProps({
data: { data: {
@ -54,12 +55,12 @@ const props = defineProps({
default: () => ({}), default: () => ({}),
}, },
config: { config: {
type: Object as PropType<{ sortOrder: string }>, type: Object as PropType<{ color: string }>,
default: () => ({}), default: () => ({ color: "purple" }),
}, },
intervalTime: { type: Array as PropType<string[]>, default: () => [] }, intervalTime: { type: Array as PropType<string[]>, default: () => [] },
}); });
const key = computed(() => Object.keys(props.data)[0]); const key = computed(() => Object.keys(props.data)[0] || "");
const maxValue = computed(() => { const maxValue = computed(() => {
if (!(props.data[key.value] && props.data[key.value].length)) { if (!(props.data[key.value] && props.data[key.value].length)) {
return 0; return 0;
@ -67,30 +68,6 @@ const maxValue = computed(() => {
const temp: number[] = props.data[key.value].map((i: any) => i.value); const temp: number[] = props.data[key.value].map((i: any) => i.value);
return Math.max.apply(null, temp); return Math.max.apply(null, temp);
}); });
const getTraceId = (i: { [key: string]: (number | string)[] }): string => {
return i.traceIds && i.traceIds[0] ? ` - ${i.traceIds[0]}` : "";
};
const datas = computed(() => {
if (!(props.data[key.value] && props.data[key.value].length)) {
return [];
}
const { sortOrder } = props.config;
const val: any = props.data[key.value];
switch (sortOrder) {
case "DES":
val.sort((a: any, b: any) => b.value - a.value);
break;
case "ASC":
val.sort((a: any, b: any) => a.value - b.value);
break;
default:
val.sort((a: any, b: any) => b.value - a.value);
break;
}
return val;
});
function handleClick(i: string) { function handleClick(i: string) {
copy(i); copy(i);
} }

View File

@ -168,7 +168,12 @@ async function init() {
svg.value.call(zoom(d3, graph.value)); svg.value.call(zoom(d3, graph.value));
// legend // legend
legend.value = graph.value.append("g").attr("class", "topo-legend"); legend.value = graph.value.append("g").attr("class", "topo-legend");
topoLegend(legend.value, height.value, width.value, settings.value.legend); topoLegend(
legend.value,
height.value,
width.value,
settings.value.description
);
svg.value.on("click", (event: any) => { svg.value.on("click", (event: any) => {
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();

View File

@ -192,6 +192,7 @@ limitations under the License. -->
<el-input <el-input
v-model="metric.value" v-model="metric.value"
placeholder="Please input a value" placeholder="Please input a value"
type="number"
@change="changeLegend(LegendOpt.VALUE, $event, index)" @change="changeLegend(LegendOpt.VALUE, $event, index)"
size="small" size="small"
class="item" class="item"
@ -215,6 +216,20 @@ limitations under the License. -->
</span> </span>
<div v-show="index !== legend.metric.length - 1">&&</div> <div v-show="index !== legend.metric.length - 1">&&</div>
</div> </div>
<div class="label">Healthy Description</div>
<el-input
v-model="description.healthy"
placeholder="Please input description"
size="small"
class="mt-5"
/>
<div class="label">Unhealthy Description</div>
<el-input
v-model="description.unhealthy"
placeholder="Please input description"
size="small"
class="mt-5"
/>
<el-button <el-button
@click="setLegend" @click="setLegend"
class="legend-btn" class="legend-btn"
@ -289,6 +304,7 @@ const legend = reactive<{
metric: l ? selectedGrid.legend : [{ name: "", condition: "", value: "" }], metric: l ? selectedGrid.legend : [{ name: "", condition: "", value: "" }],
}); });
const configType = ref<string>(""); const configType = ref<string>("");
const description = reactive<any>(selectedGrid.description || {});
getMetricList(); getMetricList();
async function getMetricList() { async function getMetricList() {
@ -347,6 +363,10 @@ async function setLegend() {
updateSettings(); updateSettings();
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 names = dashboardStore.selectedGrid.legend.map((d: any) => d.name);
if (!names.length) {
emit("updateNodes");
return;
}
const param = await useQueryTopologyMetrics(names, ids); const param = await useQueryTopologyMetrics(names, ids);
const res = await topologyStore.getLegendMetrics(param); const res = await topologyStore.getLegendMetrics(param);
@ -413,6 +433,7 @@ function updateSettings(metricConfig?: { [key: string]: MetricConfigOpt[] }) {
nodeMetrics: states.nodeMetrics, nodeMetrics: states.nodeMetrics,
legend: metrics, legend: metrics,
...metricConfig, ...metricConfig,
description,
}; };
dashboardStore.selectWidget(param); dashboardStore.selectWidget(param);
dashboardStore.setConfigs(param); dashboardStore.setConfigs(param);
@ -509,7 +530,7 @@ function setConfigType(type: string) {
.inputs { .inputs {
margin-top: 8px; margin-top: 8px;
width: 370px; width: 355px;
} }
.item { .item {

View File

@ -20,32 +20,25 @@ export default function topoLegend(
graph: any, graph: any,
clientHeight: number, clientHeight: number,
clientWidth: number, clientWidth: number,
config: any description: any
) { ) {
for (const item of ["CUBE", "CUBEERROR"]) { for (const item of ["CUBE", "CUBEERROR"]) {
graph graph
.append("image") .append("image")
.attr("width", 30) .attr("width", 30)
.attr("height", 30) .attr("height", 30)
.attr("x", clientWidth - (item === "CUBEERROR" ? 340 : 440)) .attr("x", clientWidth - (item === "CUBEERROR" ? 200 : 410))
.attr("y", clientHeight + 50) .attr("y", clientHeight + 50)
.attr("xlink:href", () => .attr("xlink:href", () =>
item === "CUBEERROR" ? icons.CUBEERROR : icons.CUBE item === "CUBEERROR" ? icons.CUBEERROR : icons.CUBE
); );
graph graph
.append("text") .append("text")
.attr("x", clientWidth - (item === "CUBEERROR" ? 310 : 410)) .attr("x", clientWidth - (item === "CUBEERROR" ? 170 : 380))
.attr("y", clientHeight + 70) .attr("y", clientHeight + 70)
.text(() => { .text(() => {
const l = config || []; const desc = description || {};
const str = l return item === "CUBEERROR" ? desc.unhealthy || "" : desc.healthy || "";
.map((d: any) => `${d.name} ${d.condition} ${d.value}`)
.join(" and ");
return item === "CUBEERROR"
? config
? `Unhealthy (${str})`
: "Unhealthy"
: "Healthy";
}) })
.style("fill", "#efeff1") .style("fill", "#efeff1")
.style("font-size", "11px"); .style("font-size", "11px");

View File

@ -55,11 +55,10 @@ export default (d3: any, graph: any, funcs: any, tip: any, legend: any) => {
} }
let c = true; let c = true;
for (const l of legend) { for (const l of legend) {
const val = l.name.includes("_sla") ? d[l.name] / 100 : d[l.name];
if (l.condition === "<") { if (l.condition === "<") {
c = c && val < Number(l.value); c = c && d[l.name] < Number(l.value);
} else { } else {
c = c && val > Number(l.value); c = c && d[l.name] > Number(l.value);
} }
} }
return c && d.isReal ? icons.CUBEERROR : icons.CUBE; return c && d.isReal ? icons.CUBEERROR : icons.CUBE;