feat: support ranges for Value Mappings (#421)

This commit is contained in:
Fine0830 2024-10-18 10:31:17 +08:00 committed by GitHub
parent bddbe40974
commit b6522f4555
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 68 additions and 35 deletions

View File

@ -386,6 +386,7 @@ const msg = {
tabExpressions: "Tab Expressions", tabExpressions: "Tab Expressions",
hierarchyNodeMetrics: "Metrics for Hierarchy Graph Node", hierarchyNodeMetrics: "Metrics for Hierarchy Graph Node",
hierarchyNodeDashboard: "As dashboard for Hierarchy Graph Node", hierarchyNodeDashboard: "As dashboard for Hierarchy Graph Node",
contentDecorations: "Content Decorations", valueMappings: "Value Mappings",
mappingTip: "Notice: The mapping key is a Regex string, for instance, ^-?(0|[1-9][0-9]*|2)(\\.0+)?$",
}; };
export default msg; export default msg;

View File

@ -386,6 +386,7 @@ const msg = {
tabExpressions: "Tab Expressions", tabExpressions: "Tab Expressions",
hierarchyNodeMetrics: "Metrics for Hierarchy Graph Node", hierarchyNodeMetrics: "Metrics for Hierarchy Graph Node",
hierarchyNodeDashboard: "As dashboard for Hierarchy Graph Node", hierarchyNodeDashboard: "As dashboard for Hierarchy Graph Node",
contentDecorations: "Content Decorations", valueMappings: "Value Mappings",
mappingTip: "Notice: The mapping key is a Regex string, for instance, ^-?(0|[1-9][0-9]*|2)(\\.0+)?$",
}; };
export default msg; export default msg;

View File

@ -384,6 +384,7 @@ const msg = {
tabExpressions: "Tab表达式", tabExpressions: "Tab表达式",
hierarchyNodeMetrics: "层次图节点的指标", hierarchyNodeMetrics: "层次图节点的指标",
hierarchyNodeDashboard: "作为层次图节点的dashboard", hierarchyNodeDashboard: "作为层次图节点的dashboard",
contentDecorations: "内容装饰", valueMappings: "值映射",
mappingTip: "注意: 映射键是一个正则表达式字符串,比如 ^-?(0|[1-9][0-9]*|2)(\\.0+)?$",
}; };
export default msg; export default msg;

View File

@ -123,7 +123,7 @@ export interface CardConfig {
fontSize?: number; fontSize?: number;
showUnit?: boolean; showUnit?: boolean;
textAlign?: "center" | "right" | "left"; textAlign?: "center" | "right" | "left";
decorations?: { [key: string]: string }; valueMappings?: { [key: string]: string };
} }
export interface TextConfig { export interface TextConfig {

View File

@ -32,7 +32,7 @@ limitations under the License. -->
:config="{ :config="{
i: 0, i: 0,
...graph, ...graph,
decorations: graph?.decorations, valueMappings: graph?.valueMappings,
metricConfig: config.metricConfig, metricConfig: config.metricConfig,
expressions: config.expressions || [], expressions: config.expressions || [],
typesOfMQE: typesOfMQE || [], typesOfMQE: typesOfMQE || [],

View File

@ -14,8 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<div> <div>
<span class="label">{{ t("contentDecorations") }}</span> <value-mappings />
<content-decorations />
</div> </div>
<div> <div>
<span class="label">{{ t("fontSize") }}</span> <span class="label">{{ t("fontSize") }}</span>
@ -39,7 +38,7 @@ limitations under the License. -->
import { ref } from "vue"; import { ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import ContentDecorations from "./components/ContentDecorations.vue"; import ValueMappings from "./components/ValueMappings.vue";
const { t } = useI18n(); const { t } = useI18n();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();

View File

@ -14,8 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<div> <div>
<span class="label">{{ t("contentDecorations") }}</span> <value-mappings />
<content-decorations />
</div> </div>
<div class="item"> <div class="item">
<span class="label">{{ t("showValues") }}</span> <span class="label">{{ t("showValues") }}</span>
@ -41,7 +40,7 @@ limitations under the License. -->
import { ref } from "vue"; import { ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import ContentDecorations from "./components/ContentDecorations.vue"; import ValueMappings from "./components/ValueMappings.vue";
const { t } = useI18n(); const { t } = useI18n();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();

View File

@ -13,13 +13,17 @@ 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>
<span class="label">{{ t("valueMappings") }}</span>
<span class="label red">({{ t("mappingTip") }})</span>
</div>
<div v-for="(key, index) in keys" :key="index" class="mb-10 flex-h"> <div v-for="(key, index) in keys" :key="index" class="mb-10 flex-h">
<div class="content-decoration" contenteditable="true" @blur="changeKeys($event, index)"> <div class="content-decoration" contenteditable="true" @blur="changeKeys($event, index)">
{{ key }} {{ key }}
</div> </div>
<div class="ml-5 mr-10">:</div> <div class="ml-5 mr-10">:</div>
<div class="content-decoration" contenteditable="true" @blur="changeValues($event, key)"> <div class="content-decoration" contenteditable="true" @blur="changeValues($event, key)">
{{ decorations[key] }} {{ valueMappings[key] }}
</div> </div>
<div v-if="index === keys.length - 1"> <div v-if="index === keys.length - 1">
<Icon class="cp mr-5" iconName="add_circle_outlinecontrol_point" size="middle" @click="addDecoration" /> <Icon class="cp mr-5" iconName="add_circle_outlinecontrol_point" size="middle" @click="addDecoration" />
@ -36,26 +40,28 @@ limitations under the License. -->
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph; const graph = dashboardStore.selectedGrid.graph;
const decorations = ref<{ [key: string]: string }>(graph?.decorations || {}); const valueMappings = ref<{ [key: string]: string }>(graph?.valueMappings || {});
const keys = ref<string[]>(graph.decorations ? Object.keys(decorations.value) : [""]); const keys = ref<string[]>(graph.valueMappings ? Object.keys(valueMappings.value) : [""]);
function changeKeys(event: any, index: number) { function changeKeys(event: any, index: number) {
const params = event.target.textContent || ""; const params = event.target.textContent || "";
const list = Object.keys(decorations.value); const list = Object.keys(valueMappings.value);
if (params) { if (params) {
decorations.value[params] = decorations.value[list[index]]; valueMappings.value[params] = valueMappings.value[list[index]];
} }
delete decorations.value[list[index]]; delete valueMappings.value[list[index]];
keys.value = Object.keys(decorations.value); keys.value = Object.keys(valueMappings.value);
updateConfig({ decorations: decorations.value }); updateConfig();
} }
function changeValues(event: any, key: string) { function changeValues(event: any, key: string) {
decorations.value[key] = event.target.textContent || ""; valueMappings.value[key] = event.target.textContent || "";
updateConfig({ decorations: decorations.value }); updateConfig();
} }
function addDecoration() { function addDecoration() {
@ -66,18 +72,15 @@ limitations under the License. -->
if (!keys.value.length) { if (!keys.value.length) {
return; return;
} }
if (!keys.value[index]) { delete valueMappings.value[keys.value[index]];
return;
}
delete decorations.value[keys.value[index]];
keys.value.splice(index, 1); keys.value.splice(index, 1);
updateConfig({ decorations: decorations.value }); updateConfig();
} }
function updateConfig(param: { [key: string]: unknown }) { function updateConfig() {
const graph = { const graph = {
...dashboardStore.selectedGrid.graph, ...dashboardStore.selectedGrid.graph,
...param, valueMappings: valueMappings.value,
}; };
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph }); dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
} }
@ -97,4 +100,10 @@ limitations under the License. -->
border-color: $active-color; border-color: $active-color;
} }
} }
.label {
font-size: 13px;
font-weight: 500;
padding-right: 10px;
}
</style> </style>

View File

@ -22,7 +22,7 @@ limitations under the License. -->
justifyContent: config.textAlign || 'center', justifyContent: config.textAlign || 'center',
}" }"
> >
{{ decorations[singleVal] || singleVal }} {{ getValue() }}
<span class="unit" v-show="config.showUnit && unit"> <span class="unit" v-show="config.showUnit && unit">
{{ decodeURIComponent(unit) }} {{ decodeURIComponent(unit) }}
</span> </span>
@ -48,18 +48,31 @@ limitations under the License. -->
showUnit: true, showUnit: true,
textAlign: "center", textAlign: "center",
metricConfig: [], metricConfig: [],
decorations: {}, valueMappings: {},
}), }),
}, },
}); });
const { t } = useI18n(); const { t } = useI18n();
const metricConfig = computed(() => props.config.metricConfig || []); const metricConfig = computed(() => props.config.metricConfig || []);
const decorations = computed(() => props.config.decorations || {}); const valueMappings = computed(() => props.config.valueMappings || {});
const key = computed(() => Object.keys(props.data)[0]); const key = computed(() => Object.keys(props.data)[0]);
const singleVal = computed(() => const singleVal = computed(() =>
Array.isArray(props.data[key.value]) ? props.data[key.value][0] : props.data[key.value], Array.isArray(props.data[key.value]) ? props.data[key.value][0] : props.data[key.value],
); );
const unit = computed(() => metricConfig.value[0] && encodeURIComponent(metricConfig.value[0].unit || "")); const unit = computed(() => metricConfig.value[0] && encodeURIComponent(metricConfig.value[0].unit || ""));
function getValue() {
if (valueMappings.value[singleVal.value]) {
return valueMappings.value[singleVal.value];
}
const list = Object.keys(valueMappings.value);
for (const i of list) {
if (new RegExp(i).test(String(singleVal.value))) {
return valueMappings.value[i] || singleVal.value;
}
}
return singleVal.value;
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.chart-card { .chart-card {

View File

@ -58,14 +58,14 @@ limitations under the License. -->
showTableValues: boolean; showTableValues: boolean;
tableHeaderCol2: string; tableHeaderCol2: string;
typesOfMQE: string[]; typesOfMQE: string[];
decorations: {}; valueMappings: {};
}>, }>,
default: () => ({ showTableValues: true }), default: () => ({ showTableValues: true }),
}, },
}); });
const { t } = useI18n(); const { t } = useI18n();
const decorations = computed<{ [key: number]: string }>(() => props.config.decorations || {}); const valueMappings = computed<{ [key: string]: string }>(() => props.config.valueMappings || {});
const nameWidth = computed(() => (props.config.showTableValues ? 80 : 100)); const nameWidth = computed(() => (props.config.showTableValues ? 80 : 100));
const dataKeys = computed(() => { const dataKeys = computed(() => {
const keys = Object.keys(props.data || {}).filter( const keys = Object.keys(props.data || {}).filter(
@ -75,9 +75,19 @@ limitations under the License. -->
return list; return list;
}); });
function getColValue(keys: string[]) { function getColValue(keys: string[]) {
const val = props.data[(keys as string[]).join(",")][props.data[(keys as string[]).join(",")].length - 1 || 0]; const source = props.data[(keys as string[]).join(",")][props.data[(keys as string[]).join(",")].length - 1 || 0];
return decorations.value[val] || val; if (valueMappings.value[source]) {
return valueMappings.value[source];
}
const list = Object.keys(valueMappings.value);
for (const i of list) {
if (new RegExp(i).test(String(source))) {
return valueMappings.value[i] || source;
}
}
return source;
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>