fix: edit widget config

This commit is contained in:
Qiuxia Fan 2022-01-11 20:16:33 +08:00
parent 015416d31d
commit 6189378f28
11 changed files with 91 additions and 86 deletions

View File

@ -28,6 +28,7 @@ import {
import type { PropType } from "vue"; import type { PropType } from "vue";
import { useECharts } from "@/hooks/useEcharts"; import { useECharts } from "@/hooks/useEcharts";
import { addResizeListener, removeResizeListener } from "@/utils/event"; import { addResizeListener, removeResizeListener } from "@/utils/event";
/*global Nullable*/ /*global Nullable*/
const chartRef = ref<Nullable<HTMLDivElement>>(null); const chartRef = ref<Nullable<HTMLDivElement>>(null);
const { setOptions, resize } = useECharts(chartRef as Ref<HTMLDivElement>); const { setOptions, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
@ -45,7 +46,7 @@ onMounted(() => {
if (!chartRef.value) { if (!chartRef.value) {
return; return;
} }
window.addEventListener("resize", resize); setOptions(props.option);
addResizeListener(unref(chartRef), resize); addResizeListener(unref(chartRef), resize);
}); });
@ -60,7 +61,6 @@ onBeforeUnmount(() => {
if (!chartRef.value) { if (!chartRef.value) {
return; return;
} }
window.removeEventListener("resize", resize);
removeResizeListener(unref(chartRef), resize); removeResizeListener(unref(chartRef), resize);
}); });
</script> </script>

View File

@ -20,7 +20,6 @@ import Selector from "./Selector.vue";
import Graph from "./Graph.vue"; import Graph from "./Graph.vue";
import type { App } from "vue"; import type { App } from "vue";
import VueGridLayout from "vue-grid-layout"; import VueGridLayout from "vue-grid-layout";
import { ElLoading } from "element-plus";
const components: { [key: string]: any } = { const components: { [key: string]: any } = {
Icon, Icon,
@ -28,7 +27,6 @@ const components: { [key: string]: any } = {
VueGridLayout, VueGridLayout,
Selector, Selector,
Graph, Graph,
ElLoading,
}; };
const componentsName: string[] = Object.keys(components); const componentsName: string[] = Object.keys(components);

View File

@ -29,13 +29,25 @@ interface DashboardState {
layerId: string; layerId: string;
activedGridItem: string; activedGridItem: string;
} }
const newControl: LayoutConfig = {
x: 0,
y: 0,
w: 24,
h: 12,
i: "0",
type: "Widget",
widget: {
title: "Title",
},
graph: {},
standard: {},
};
export const dashboardStore = defineStore({ export const dashboardStore = defineStore({
id: "dashboard", id: "dashboard",
state: (): DashboardState => ({ state: (): DashboardState => ({
layout: [ConfigData], layout: [ConfigData],
showConfig: false, showConfig: false,
selectedGrid: ConfigData, selectedGrid: null,
entity: "", entity: "",
layerId: "", layerId: "",
activedGridItem: "", activedGridItem: "",
@ -44,36 +56,15 @@ export const dashboardStore = defineStore({
setLayout(data: LayoutConfig[]) { setLayout(data: LayoutConfig[]) {
this.layout = data; this.layout = data;
}, },
addWidget() { addControl(type: string) {
const newWidget: LayoutConfig = { const newWidget: LayoutConfig = {
x: 0, ...newControl,
y: 0,
w: 24,
h: 12,
i: String(this.layout.length), i: String(this.layout.length),
type: "Widget", type,
widget: {
title: "Title",
},
graph: {},
standard: {},
}; };
this.layout = this.layout.map((d: LayoutConfig) => { if (type === "Tab") {
d.y = d.y + newWidget.h; newWidget.h = 24;
return d; newWidget.children = [
});
this.layout.push(newWidget);
this.activedGridItem = newWidget.i;
},
addTab() {
const newWidget: LayoutConfig = {
x: 0,
y: 0,
w: 24,
h: 20,
i: String(this.layout.length),
type: "Tab",
children: [
{ {
name: "Tab1", name: "Tab1",
children: [], children: [],
@ -82,11 +73,8 @@ export const dashboardStore = defineStore({
name: "Tab2", name: "Tab2",
children: [], children: [],
}, },
], ];
widget: {}, }
graph: {},
standard: {},
};
this.layout = this.layout.map((d: LayoutConfig) => { this.layout = this.layout.map((d: LayoutConfig) => {
d.y = d.y + newWidget.h; d.y = d.y + newWidget.h;
return d; return d;
@ -153,7 +141,7 @@ export const dashboardStore = defineStore({
this.showConfig = show; this.showConfig = show;
}, },
selectWidget(widget: Nullable<LayoutConfig>) { selectWidget(widget: Nullable<LayoutConfig>) {
this.selectedGrid = ConfigData || widget; //todo this.selectedGrid = widget;
}, },
setLayer(id: string) { setLayer(id: string) {
this.layerId = id; this.layerId = id;
@ -176,9 +164,10 @@ export const dashboardStore = defineStore({
return res.data; return res.data;
}, },
async fetchMetricValue(config: LayoutConfig) { async fetchMetricValue(config: LayoutConfig) {
if (!config.queryMetricType) { // if (!config.queryMetricType) {
return; // return;
} // }
config.queryMetricType = "readMetricsValues";
const appStoreWithOut = useAppStoreWithOut(); const appStoreWithOut = useAppStoreWithOut();
const variable = { const variable = {
condition: { condition: {

View File

@ -92,3 +92,9 @@ export function isElement(val: unknown): val is Element {
export function isMap(val: unknown): val is Map<any, any> { export function isMap(val: unknown): val is Map<any, any> {
return is(val, "Map"); return is(val, "Map");
} }
export function isEmptyObject<T = unknown>(val: T): val is T {
if (isObject(val)) {
return Object.keys(val).length === 0;
}
return false;
}

View File

@ -56,7 +56,6 @@ limitations under the License. -->
import { reactive } from "vue"; import { reactive } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import router from "@/router"; import router from "@/router";
import { ElInput, ElButton } from "element-plus";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { EntityType, Options } from "./data"; import { EntityType, Options } from "./data";
import uuid from "@/utils/uuid"; import uuid from "@/utils/uuid";

View File

@ -18,22 +18,22 @@ limitations under the License. -->
<div class="header">{{ title }}</div> <div class="header">{{ title }}</div>
<div class="render-chart"> <div class="render-chart">
<component <component
:is="chartType" :is="states.chartType"
:intervalTime="appStoreWithOut.intervalTime" :intervalTime="appStoreWithOut.intervalTime"
:data="source" :data="states.source"
/> />
<div v-show="!states.chartType" class="no-data">{{ t("noData") }}</div>
</div> </div>
<span v-show="!source">{{ t("noData") }}</span>
</div> </div>
<div class="collapse" :style="{ height: configHeight + 'px' }"> <div class="collapse" :style="{ height: configHeight + 'px' }">
<el-collapse <el-collapse
v-model="activeNames" v-model="states.activeNames"
:style="{ '--el-collapse-header-font-size': '15px' }" :style="{ '--el-collapse-header-font-size': '15px' }"
> >
<el-collapse-item :title="t('metricName')" name="1"> <el-collapse-item :title="t('metricName')" name="1">
<div> <div>
<Selector <Selector
:value="metrics" :value="states.metrics"
:options="metricOpts" :options="metricOpts"
:multiple="true" :multiple="true"
size="mini" size="mini"
@ -42,9 +42,9 @@ limitations under the License. -->
class="selectors" class="selectors"
/> />
<Selector <Selector
v-if="valueType" v-if="states.valueType"
:value="valueType" :value="states.valueType"
:options="valueTypes" :options="states.valueTypes"
size="mini" size="mini"
placeholder="Select a metric" placeholder="Select a metric"
@change="changeValueType" @change="changeValueType"
@ -59,7 +59,7 @@ limitations under the License. -->
v-for="(type, index) in ChartTypes" v-for="(type, index) in ChartTypes"
:key="index" :key="index"
@click="changeChartType(type)" @click="changeChartType(type)"
:class="{ active: type.value === chartType }" :class="{ active: type.value === states.chartType }"
> >
{{ type.label }} {{ type.label }}
</span> </span>
@ -67,7 +67,7 @@ limitations under the License. -->
</el-collapse-item> </el-collapse-item>
<el-collapse-item :title="t('graphStyles')" name="3"> <el-collapse-item :title="t('graphStyles')" name="3">
<component <component
:is="`${chartType}Config`" :is="`${states.chartType}Config`"
:config="dashboardStore.selectedGrid.graph" :config="dashboardStore.selectedGrid.graph"
/> />
</el-collapse-item> </el-collapse-item>
@ -94,13 +94,14 @@ import { reactive, defineComponent, toRefs, 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 { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { ElMessage, ElButton, ElCollapse, ElCollapseItem } from "element-plus"; import { ElMessage } from "element-plus";
import { ValuesTypes, MetricQueryTypes, ChartTypes } from "../data"; import { ValuesTypes, MetricQueryTypes, ChartTypes } from "../data";
import { Option } from "@/types/app"; import { Option } from "@/types/app";
import graphs from "../graphs"; import graphs from "../graphs";
import configs from "./graph-styles"; import configs from "./graph-styles";
import WidgetOptions from "./WidgetOptions.vue"; import WidgetOptions from "./WidgetOptions.vue";
import StandardOptions from "./StandardOptions.vue"; import StandardOptions from "./StandardOptions.vue";
import { isEmptyObject } from "@/utils/is";
export default defineComponent({ export default defineComponent({
name: "ConfigEdit", name: "ConfigEdit",
@ -109,9 +110,6 @@ export default defineComponent({
...configs, ...configs,
WidgetOptions, WidgetOptions,
StandardOptions, StandardOptions,
ElButton,
ElCollapse,
ElCollapseItem,
}, },
setup() { setup() {
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
@ -148,7 +146,9 @@ export default defineComponent({
tips: selectedGrid.widget.tips, tips: selectedGrid.widget.tips,
title: selectedGrid.widget.title, title: selectedGrid.widget.title,
}); });
if (states.metrics[0]) {
queryMetricType(states.metrics[0]); queryMetricType(states.metrics[0]);
}
async function changeMetrics(arr: Option[]) { async function changeMetrics(arr: Option[]) {
if (!arr.length) { if (!arr.length) {
@ -157,8 +157,10 @@ export default defineComponent({
return; return;
} }
states.metrics = arr.map((d: Option) => String(d.value)); states.metrics = arr.map((d: Option) => String(d.value));
if (arr[0].value) {
queryMetricType(String(arr[0].value)); queryMetricType(String(arr[0].value));
} }
}
async function queryMetricType(metric: string) { async function queryMetricType(metric: string) {
loading.value = true; loading.value = true;
@ -171,11 +173,13 @@ export default defineComponent({
const { typeOfMetrics } = resp.data; const { typeOfMetrics } = resp.data;
states.valueTypes = ValuesTypes[typeOfMetrics]; states.valueTypes = ValuesTypes[typeOfMetrics];
states.valueType = ValuesTypes[typeOfMetrics][0].value; states.valueType = ValuesTypes[typeOfMetrics][0].value;
queryMetrics();
} }
function changeValueType(val: Option[]) { function changeValueType(val: Option[]) {
states.valueType = String(val[0].value); states.valueType = String(val[0].value);
states.metricQueryType = (MetricQueryTypes as any)[states.valueType]; states.metricQueryType = (MetricQueryTypes as any)[states.valueType];
queryMetrics();
} }
function changeChartType(item: Option) { function changeChartType(item: Option) {
@ -207,6 +211,9 @@ export default defineComponent({
const json = await dashboardStore.fetchMetricValue( const json = await dashboardStore.fetchMetricValue(
dashboardStore.selectedGrid dashboardStore.selectedGrid
); );
if (!json) {
return;
}
if (json.error) { if (json.error) {
return; return;
@ -214,9 +221,7 @@ export default defineComponent({
const metricVal = json.data.readMetricsValues.values.values.map( const metricVal = json.data.readMetricsValues.values.values.map(
(d: { value: number }) => d.value (d: { value: number }) => d.value
); );
const m = const m = states.metrics[0];
dashboardStore.selectedGrid.metrics &&
dashboardStore.selectedGrid.metrics[0];
if (!m) { if (!m) {
return; return;
} }
@ -251,7 +256,7 @@ export default defineComponent({
return { return {
...toRefs(widgetOpt), ...toRefs(widgetOpt),
...toRefs(states), states,
changeChartType, changeChartType,
changeValueType, changeValueType,
changeMetrics, changeMetrics,
@ -325,6 +330,12 @@ export default defineComponent({
} }
} }
.no-data {
font-size: 14px;
text-align: center;
line-height: 350px;
}
span.active { span.active {
background-color: #409eff; background-color: #409eff;
color: #fff; color: #fff;

View File

@ -37,12 +37,16 @@ limitations under the License. -->
/> />
</span> </span>
<span class="tab-icons"> <span class="tab-icons">
<el-tooltip effect="dark" content="Add tab items" placement="bottom">
<i @click="addTabItem"> <i @click="addTabItem">
<Icon size="middle" iconName="add" /> <Icon size="middle" iconName="add" />
</i> </i>
</el-tooltip>
<el-tooltip effect="dark" content="Add widgets" placement="bottom">
<i @click="addTabWidget"> <i @click="addTabWidget">
<Icon size="middle" iconName="playlist_add" /> <Icon size="middle" iconName="playlist_add" />
</i> </i>
</el-tooltip>
</span> </span>
</div> </div>
<div class="operations"> <div class="operations">
@ -73,7 +77,7 @@ limitations under the License. -->
<Widget :data="item" :active="activeTabWidget === item.i" /> <Widget :data="item" :active="activeTabWidget === item.i" />
</grid-item> </grid-item>
</grid-layout> </grid-layout>
<div class="no-data-tips" v-else>No widgets, plase add widgets</div> <div class="no-data-tips" v-else>Please add widgets.</div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -25,10 +25,10 @@ limitations under the License. -->
<Icon iconName="ellipsis_v" size="middle" class="operation" /> <Icon iconName="ellipsis_v" size="middle" class="operation" />
</template> </template>
<div class="tools" @click="editConfig"> <div class="tools" @click="editConfig">
<span>Edit</span> <span>{{ t("edit") }}</span>
</div> </div>
<div class="tools" @click="removeWidget"> <div class="tools" @click="removeWidget">
<span>Delete</span> <span>{{ t("delete") }}</span>
</div> </div>
</el-popover> </el-popover>
</div> </div>
@ -39,7 +39,7 @@ limitations under the License. -->
:data="state.source" :data="state.source"
/> />
</div> </div>
<div v-else class="no-data">No data</div> <div v-else class="no-data">{{ t("noData") }}</div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -50,7 +50,7 @@ import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import graphs from "../graphs"; import graphs from "../graphs";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
// import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const props = { const props = {
data: { data: {
@ -64,7 +64,7 @@ export default defineComponent({
components: { ...graphs }, components: { ...graphs },
props, props,
setup(props) { setup(props) {
// const { t } = useI18n(); const { t } = useI18n();
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
const state = reactive({ const state = reactive({
source: {}, source: {},
@ -110,6 +110,7 @@ export default defineComponent({
editConfig, editConfig,
data, data,
loading, loading,
t,
}; };
}, },
}); });

View File

@ -26,7 +26,6 @@ export const ChartTypes = [
{ label: "Endpoint List", value: "EndpointList" }, { label: "Endpoint List", value: "EndpointList" },
{ label: "Instance List", value: "InstanceList" }, { label: "Instance List", value: "InstanceList" },
// { label: "Image", value: "Image" }, // { label: "Image", value: "Image" },
// { label: "Tab", value: "Tabs" },
]; ];
export enum MetricQueryTypes { export enum MetricQueryTypes {
ReadMetricsValue = "readMetricsValue", ReadMetricsValue = "readMetricsValue",
@ -123,7 +122,7 @@ export const SortOrder = [
export const ToolIcons = [ export const ToolIcons = [
{ name: "playlist_add", content: "Add Widget", id: "addWidget" }, { name: "playlist_add", content: "Add Widget", id: "addWidget" },
{ name: "all_inbox", content: "Add Tab", id: "addTab" }, { name: "all_inbox", content: "Add Tab", id: "addTab" },
{ name: "insert_image", content: "Add Image", id: "addImage" }, // { name: "insert_image", content: "Add Image", id: "addImage" },
{ name: "save_alt", content: "Export", id: "export" }, { name: "save_alt", content: "Export", id: "export" },
{ name: "folder_open", content: "Import", id: "import" }, { name: "folder_open", content: "Import", id: "import" },
{ name: "settings", content: "Settings", id: "settings" }, { name: "settings", content: "Settings", id: "settings" },

View File

@ -32,11 +32,7 @@ limitations under the License. -->
@click="clickGrid(item)" @click="clickGrid(item)"
:class="{ active: dashboardStore.activedGridItem === item.i }" :class="{ active: dashboardStore.activedGridItem === item.i }"
> >
<component <component :is="item.type" :data="item" />
:is="item.type"
:data="item"
:active="dashboardStore.activedGridItem === item.i"
/>
</grid-item> </grid-item>
</grid-layout> </grid-layout>
</template> </template>
@ -46,6 +42,7 @@ import { useDashboardStore } from "@/store/modules/dashboard";
import { LayoutConfig } from "@/types/dashboard"; import { LayoutConfig } from "@/types/dashboard";
import Widget from "../controls/Widget.vue"; import Widget from "../controls/Widget.vue";
import Tab from "../controls/Tab.vue"; import Tab from "../controls/Tab.vue";
export default defineComponent({ export default defineComponent({
name: "Layout", name: "Layout",
components: { Widget, Tab }, components: { Widget, Tab },

View File

@ -79,7 +79,6 @@ limitations under the License. -->
<script lang="ts" setup> <script lang="ts" setup>
import { reactive } from "vue"; import { reactive } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { ElTooltip, ElCascader } from "element-plus";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { Options, SelectOpts, EntityType, ToolIcons } from "../data"; import { Options, SelectOpts, EntityType, ToolIcons } from "../data";
@ -113,17 +112,19 @@ function changeService(val: { value: string; label: string }) {
function clickIcons(t: { id: string; content: string; name: string }) { function clickIcons(t: { id: string; content: string; name: string }) {
switch (t.id) { switch (t.id) {
case "addWidget": case "addWidget":
dashboardStore.addWidget(); dashboardStore.addControl("Widget");
break; break;
case "addTab": case "addTab":
dashboardStore.addTab(); dashboardStore.addControl("Tab");
break; break;
case "addImage": case "addImage":
dashboardStore.addWidget(); dashboardStore.addControl("Image");
break; break;
case "settings": case "settings":
dashboardStore.setConfigPanel(true); dashboardStore.setConfigPanel(true);
break; break;
default:
dashboardStore.addControl("Widget");
} }
} }
</script> </script>