feat: add custom config for graphs

This commit is contained in:
Qiuxia Fan 2022-01-12 23:04:31 +08:00
parent 8435beda35
commit 8d0acfa1e0
16 changed files with 303 additions and 77 deletions

View File

@ -47,7 +47,7 @@ export interface StandardConfig {
seconds?: string;
}
export type GraphConfig = BarConfig | LineConfig;
export type GraphConfig = BarConfig | LineConfig | CardConfig | TableConfig;
export interface BarConfig {
type?: string;
showBackground?: boolean;
@ -63,3 +63,21 @@ export interface AreaConfig {
type?: string;
opacity?: number;
}
export interface CardConfig {
type?: string;
fontSize?: number;
showUint: boolean;
}
export interface TableConfig {
type?: string;
showTableValues: boolean;
tableHeaderCol1: string;
tableHeaderCol2: string;
}
export interface TopListConfig {
type?: string;
topN: number;
}

View File

@ -48,8 +48,8 @@ const props = defineProps({
});
const emits = defineEmits(["update"]);
const { t } = useI18n();
const title = ref<string>(props.config.title);
const tips = ref<string>(props.config.tips);
const title = ref<string>(props.config.title || "");
const tips = ref<string>(props.config.tips || "");
function updateWidgetConfig(param: { [key: string]: unknown }) {
emits("update", param);

View File

@ -0,0 +1,60 @@
<!-- 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>
<span class="label">Font Size</span>
<el-slider
class="slider"
v-model="fontSize"
show-input
input-size="small"
:min="0.1"
:max="1"
:step="0.1"
@change="updateConfig({ fontSize })"
/>
</div>
</template>
<script lang="ts" setup>
import { defineProps, ref, defineEmits } from "vue";
import type { PropType } from "vue";
import { CardConfig } from "@/types/dashboard";
const props = defineProps({
config: {
type: Object as PropType<CardConfig>,
default: () => ({ fontSize: 12 }),
},
});
const emits = defineEmits(["update"]);
const fontSize = ref(props.config.fontSize);
function updateConfig(param: { [key: string]: unknown }) {
emits("update", param);
}
</script>
<style lang="scss" scoped>
.slider {
width: 500px;
margin-top: -13px;
}
.label {
font-size: 13px;
font-weight: 500;
display: block;
margin-bottom: 5px;
}
</style>

View File

@ -62,11 +62,6 @@ function updateConfig(param: { [key: string]: unknown }) {
}
</script>
<style lang="scss" scoped>
.bar-width {
width: 500px;
margin-top: -13px;
}
.label {
font-size: 13px;
font-weight: 500;

View File

@ -0,0 +1,84 @@
<!-- 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>
<span class="label">Show Values</span>
<el-switch
v-model="showTableValues"
active-text="Yes"
inactive-text="No"
@change="updateConfig({ showTableValues })"
/>
</div>
<div class="item">
<span class="label">{{ t("tableHeaderCol1") }}</span>
<el-input
class="input"
v-model="tableHeaderCol1"
size="mini"
placeholder="none"
@change="updateConfig({ tableHeaderCol1 })"
/>
</div>
<div class="item">
<span class="label">{{ t("tableHeaderCol2") }}</span>
<el-input
class="input"
v-model="tableHeaderCol2"
size="mini"
placeholder="none"
@change="updateConfig({ tableHeaderCol2 })"
/>
</div>
</template>
<script lang="ts" setup>
import { defineProps, ref, defineEmits } from "vue";
import type { PropType } from "vue";
import { TableConfig } from "@/types/dashboard";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const props = defineProps({
config: {
type: Object as PropType<TableConfig>,
default: () => ({
showTableValues: true,
tableHeaderCol1: "",
tableHeaderCol2: "",
}),
},
});
const emits = defineEmits(["update"]);
const showTableValues = ref(props.config.showTableValues);
const tableHeaderCol1 = ref(props.config.tableHeaderCol1);
const tableHeaderCol2 = ref(props.config.tableHeaderCol2);
function updateConfig(param: { [key: string]: unknown }) {
emits("update", param);
}
</script>
<style lang="scss" scoped>
.slider {
width: 500px;
margin-top: -13px;
}
.label {
font-size: 13px;
font-weight: 500;
display: block;
margin-bottom: 5px;
}
</style>

View File

@ -0,0 +1,59 @@
<!-- 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>
<span class="label">{{ $t("maxItemNum") }}</span>
<el-input
class="input"
v-model="topN"
size="mini"
placeholder="none"
type="number"
:min="1"
:max="100"
@change="updateConfig({ topN })"
/>
</div>
</template>
<script lang="ts" setup>
import { defineProps, ref, defineEmits } from "vue";
import type { PropType } from "vue";
import { TopListConfig } from "@/types/dashboard";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const props = defineProps({
config: {
type: Object as PropType<TopListConfig>,
default: () => ({
topN: 10,
}),
},
});
const emits = defineEmits(["update"]);
const topN = ref(props.config.topN);
function updateConfig(param: { [key: string]: unknown }) {
emits("update", param);
}
</script>
<style lang="scss" scoped>
.label {
font-size: 13px;
font-weight: 500;
display: block;
margin-bottom: 5px;
}
</style>

View File

@ -48,6 +48,7 @@ limitations under the License. -->
:intervalTime="appStoreWithOut.intervalTime"
:data="state.source"
:config="data.graph"
:standard="data.standard"
/>
</div>
<div v-else class="no-data">{{ t("noData") }}</div>

View File

@ -41,6 +41,21 @@ export const DefaultGraphConfig: { [key: string]: any } = {
type: "Area",
opacity: 0.4,
},
Card: {
type: "Card",
fontSize: 14,
showUint: true,
},
Table: {
type: "Card",
showTableValues: true,
tableHeaderCol1: "",
tableHeaderCol2: "",
},
TopList: {
type: "TopList",
topN: 10,
},
};
export enum MetricQueryTypes {

View File

@ -14,44 +14,41 @@ See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<div class="chart-card">
<div v-for="(item, index) in data" :key="index" class="card-detail">
<span class="b" :style="`color: ${getColors}`">{{
typeof item.avgNum === "string"
? item.avgNum
: isNaN(item.avgNum)
? null
: item.avgNum.toFixed(2)
}}</span>
</div>
<div class="chart-card" :style="{ fontSize: `${config.fontSize}px` }">
{{
typeof data[key] === "string"
? data[key]
: isNaN(data[key])
? null
: data[key].toFixed(2)
}}
<span v-show="config.showUint">{{ standard.unit }}</span>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from "vue";
import { defineProps, computed } from "vue";
import { computed, PropType } from "vue";
import { defineProps } from "vue";
import { CardConfig, StandardConfig } from "@/types/dashboard";
const props = defineProps({
data: {
type: Object as PropType<{ [key: string]: number[] }>,
type: Object as PropType<{ [key: string]: number }>,
default: () => ({}),
},
theme: { type: String, default: "" },
});
const getColors = computed(() => {
return props.theme === "dark" ? "#eee" : "#333";
config: {
type: Object as PropType<CardConfig>,
default: () => ({ fontSize: 12, showUint: true }),
},
standard: {
type: Object as PropType<StandardConfig>,
default: () => ({ unit: "" }),
},
});
const key = computed(() => Object.keys(props.data)[0]);
</script>
<style lang="scss" scoped>
.chart-card {
font-size: 14px;
box-sizing: border-box;
color: #333;
}
.card-detail {
span:first-child {
padding-right: 8px;
box-sizing: border-box;
color: #666;
}
}
</style>

View File

@ -18,7 +18,6 @@ limitations under the License. -->
</el-table>
</template>
<script setup lang="ts">
import { ElTable, ElTableColumn } from "element-plus";
import { defineProps } from "vue";
import type { PropType } from "vue";
@ -27,6 +26,9 @@ defineProps({
type: Array as PropType<{ label: string; value: string }[]>,
default: () => [],
},
theme: { type: String, default: "" },
config: {
type: Object,
default: () => ({}),
},
});
</script>

View File

@ -16,9 +16,9 @@ limitations under the License. -->
<Graph :option="option" />
</template>
<script lang="ts" setup>
import { defineProps, ref, computed } from "vue";
import { defineProps, computed } from "vue";
import type { PropType } from "vue";
import { Event } from "@/types/events";
import { StandardConfig } from "@/types/dashboard";
const props = defineProps({
data: {
@ -26,15 +26,15 @@ const props = defineProps({
default: () => ({}),
},
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
theme: { type: String, default: "dark" },
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
itemConfig: {
type: Object as PropType<{ unit: string }>,
config: {
type: Object as PropType<any>,
default: () => ({}),
},
standard: {
type: Object as PropType<StandardConfig>,
default: () => ({}),
},
});
/*global Nullable */
const chart = ref<Nullable<HTMLElement>>(null);
const option = computed(() => getOption());
function getOption() {
const source = (props.data.nodes || []).map((d: number[]) => d[2]);
@ -66,7 +66,7 @@ function getOption() {
tooltip: {
position: "top",
formatter: (a: any) =>
`${a.data[1] * 100}${props.itemConfig.unit} [ ${a.data[2]} ]`,
`${a.data[1] * 100}${props.standard.unit} [ ${a.data[2]} ]`,
textStyle: {
fontSize: 13,
color: "#ccc",

View File

@ -18,7 +18,6 @@ limitations under the License. -->
</el-table>
</template>
<script setup lang="ts">
import { ElTable, ElTableColumn } from "element-plus";
import { defineProps } from "vue";
import type { PropType } from "vue";
@ -27,6 +26,9 @@ defineProps({
type: Array as PropType<{ label: string; value: string }[]>,
default: () => [],
},
theme: { type: String, default: "" },
config: {
type: Object,
default: () => ({}),
},
});
</script>

View File

@ -24,7 +24,10 @@ const props = defineProps({
type: Array as PropType<{ name: string; value: number }[]>,
default: () => [],
},
theme: { type: String, default: "dark" },
config: {
type: Object as PropType<{ sortOrder: string }>,
default: () => ({}),
},
});
const option = computed(() => getOption());
function getOption() {
@ -40,7 +43,7 @@ function getOption() {
left: 0,
itemWidth: 12,
textStyle: {
color: props.theme === "dark" ? "#fff" : "#333",
color: "#333",
},
},
series: [

View File

@ -19,28 +19,26 @@ limitations under the License. -->
<div
class="row header flex-h"
:style="`width: ${nameWidth + initWidth}px`"
:class="{ dark: theme === 'dark' }"
>
<div class="name" :style="`width: ${nameWidth}px`">
{{ item.tableHeaderCol1 || $t("name") }}
{{ config.tableHeaderCol1 || $t("name") }}
<i class="r cp" ref="draggerName"
><rk-icon icon="settings_ethernet"
/></i>
</div>
<div class="value-col" v-if="showTableValues">
{{ item.tableHeaderCol2 || $t("value") }}
<div class="value-col" v-if="config.showTableValues">
{{ config.tableHeaderCol2 || $t("value") }}
</div>
</div>
<div
class="row flex-h"
:class="{ dark: theme === 'dark' }"
v-for="key in dataKeys"
:key="key"
:style="`width: ${nameWidth + initWidth}px`"
>
<div :style="`width: ${nameWidth}px`">{{ key }}</div>
<div class="value-col" v-if="showTableValues">
{{ data[key][dataLength(data[key])] }}
<div class="value-col" v-if="config.showTableValues">
{{ data[key][data[key].length - 1 || 0] }}
</div>
</div>
</div>
@ -54,9 +52,12 @@ const props = defineProps({
type: Object as PropType<{ [key: string]: number[][] }>,
default: () => ({}),
},
theme: { type: String, default: "dark" },
itemConfig: {
type: Object as PropType<{ showTableValues: string | boolean }>,
config: {
type: Object as PropType<{
showTableValues: boolean;
tableHeaderCol2: string;
tableHeaderCol1: string;
}>,
default: () => ({}),
},
});
@ -69,10 +70,10 @@ onMounted(() => {
if (!chartTable.value) {
return;
}
const width = showTableValues.value
const width = props.config.showTableValues
? chartTable.value.offsetWidth / 2
: chartTable.value.offsetWidth;
initWidth.value = showTableValues.value
initWidth.value = props.config.showTableValues
? chartTable.value.offsetWidth / 2
: 0;
nameWidth.value = width - 5;
@ -98,15 +99,6 @@ const dataKeys = computed(() => {
);
return keys;
});
const showTableValues = computed(() => {
return props.itemConfig.showTableValues === "true" ||
props.itemConfig.showTableValues === true
? true
: false;
});
const dataLength = computed((param: number[]) => {
return param.length - 1 || 0;
});
</script>
<style lang="scss" scoped>
.chart-table {

View File

@ -36,7 +36,6 @@ limitations under the License. -->
<script lang="ts" setup>
import type { PropType } from "vue";
import { defineProps, computed } from "vue";
import { ElProgress } from "element-plus";
import copy from "@/utils/copy";
const props = defineProps({
data: {
@ -45,8 +44,7 @@ const props = defineProps({
>,
default: () => [],
},
theme: { type: String, default: "" },
itemConfig: {
config: {
type: Object as PropType<{ sortOrder: string }>,
default: () => ({}),
},
@ -65,7 +63,7 @@ const datas: any = () => {
if (!props.data.length) {
return [];
}
const { sortOrder } = props.itemConfig;
const { sortOrder } = props.config;
const val: any = props.data;
switch (sortOrder) {

View File

@ -18,7 +18,7 @@
import Area from "./Area.vue";
import Line from "./Line.vue";
import Bar from "./Bar.vue";
// import Heatmap from "./Heatmap.vue";
import Heatmap from "./Heatmap.vue";
import TopList from "./TopList.vue";
import Table from "./Table.vue";
import Pie from "./Pie.vue";
@ -27,7 +27,7 @@ import Card from "./Card.vue";
export default {
Line,
Bar,
// Heatmap,
Heatmap,
TopList,
Area,
Table,