feat: create global actions for setting page title and auto refresh pages (#13)

* fix: update heat map

* feat: update servicelist

* fix: update list

* feat: update page with changing times

* feat: set auto fresh

* feat: set page titles
This commit is contained in:
Fine0830 2022-01-26 12:18:03 +08:00 committed by GitHub
parent 970989100b
commit 7472d70720
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 282 additions and 73 deletions

16
src/assets/icons/retry.svg Executable file
View File

@ -0,0 +1,16 @@
<!-- 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. -->
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>icn/retry</title><path d="M4.074 6.957c-.578 2.136.7 4.331 2.856 4.904a4.05 4.05 0 0 0 2.479-.124 1.013 1.013 0 0 1 1.303.579.998.998 0 0 1-.585 1.291 6.086 6.086 0 0 1-3.72.187c-3.232-.858-5.15-4.151-4.284-7.355l-.749-.199a.498.498 0 0 1-.122-.917L3.47 4.056a.507.507 0 0 1 .69.183l1.28 2.198a.497.497 0 0 1 .05.38.505.505 0 0 1-.618.353l-.798-.212zm7.852 2.086c.578-2.136-.7-4.331-2.856-4.904a4.05 4.05 0 0 0-2.479.124 1.013 1.013 0 0 1-1.303-.579.998.998 0 0 1 .585-1.291 6.086 6.086 0 0 1 3.72-.187c3.232.858 5.15 4.151 4.284 7.355l.749.199a.498.498 0 0 1 .122.917l-2.218 1.268a.507.507 0 0 1-.69-.183l-1.28-2.198a.497.497 0 0 1-.05-.38.505.505 0 0 1 .618-.353l.798.212z" id="a"/></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -19,7 +19,7 @@ import { ElMessage } from "element-plus";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { Instance, Endpoint } from "@/types/selector"; import { Instance, Endpoint, Service } from "@/types/selector";
export function useQueryProcessor(config: any) { export function useQueryProcessor(config: any) {
if (!(config.metrics && config.metrics[0])) { if (!(config.metrics && config.metrics[0])) {
@ -28,7 +28,7 @@ export function useQueryProcessor(config: any) {
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const selectorStore = useSelectorStore(); const selectorStore = useSelectorStore();
if (!selectorStore.currentService) { if (!selectorStore.currentService && dashboardStore.entity !== "All") {
return; return;
} }
const conditions: { [key: string]: unknown } = { const conditions: { [key: string]: unknown } = {
@ -190,7 +190,7 @@ export function useSourceProcessor(
} }
export function useQueryPodsMetrics( export function useQueryPodsMetrics(
pods: Array<Instance | Endpoint>, pods: Array<Instance | Endpoint | Service | any>,
config: { metrics: string[]; metricTypes: string[] }, config: { metrics: string[]; metricTypes: string[] },
scope: string scope: string
) { ) {
@ -202,25 +202,30 @@ export function useQueryPodsMetrics(
const variables: string[] = [`$duration: Duration!`]; const variables: string[] = [`$duration: Duration!`];
const { currentService } = selectorStore; const { currentService } = selectorStore;
const fragmentList = pods.map((d: Instance | Endpoint, index: number) => { const fragmentList = pods.map(
const param = { (
scope, d: (Instance | Endpoint | Service) & { normal: boolean },
serviceName: currentService.label, index: number
serviceInstanceName: scope === "ServiceInstance" ? d.label : undefined, ) => {
endpointName: scope === "Endpoint" ? d.label : undefined, const param = {
normal: currentService.normal, scope,
}; serviceName: scope === "Service" ? d.label : currentService.label,
const f = config.metrics.map((name: string, idx: number) => { serviceInstanceName: scope === "ServiceInstance" ? d.label : undefined,
const metricType = config.metricTypes[idx] || ""; endpointName: scope === "Endpoint" ? d.label : undefined,
conditions[`condition${index}${idx}`] = { normal: scope === "Service" ? d.normal : currentService.normal,
name,
entity: param,
}; };
variables.push(`$condition${index}${idx}: MetricsCondition!`); const f = config.metrics.map((name: string, idx: number) => {
return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, duration: $duration)${RespFields[metricType]}`; const metricType = config.metricTypes[idx] || "";
}); conditions[`condition${index}${idx}`] = {
return f; name,
}); entity: param,
};
variables.push(`$condition${index}${idx}: MetricsCondition!`);
return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, duration: $duration)${RespFields[metricType]}`;
});
return f;
}
);
const fragment = fragmentList.flat(1).join(" "); const fragment = fragmentList.flat(1).join(" ");
const queryStr = `query queryData(${variables}) {${fragment}}`; const queryStr = `query queryData(${variables}) {${fragment}}`;

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<div class="nav-bar flex-h" :class="{ dark: theme === 'dark' }"> <div class="nav-bar flex-h" :class="{ dark: theme === 'dark' }">
<div class="title">{{ t(pageName) }}</div> <div class="title">{{ appStore.pageTitle || t(pageName) }}</div>
<div class="app-config"> <div class="app-config">
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span> <span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
<TimePicker <TimePicker
@ -27,9 +27,9 @@ limitations under the License. -->
UTC{{ utcHour >= 0 ? "+" : "" UTC{{ utcHour >= 0 ? "+" : ""
}}{{ `${appStore.utcHour}:${appStore.utcMin}` }} }}{{ `${appStore.utcHour}:${appStore.utcMin}` }}
</span> </span>
<!-- <span @click="handleReload" title="refresh"> <span title="refresh" class="ghost ml-5 cp" @click="handleReload">
<Icon icon="retry" :loading="auto" class="middle" /> <Icon iconName="retry" :loading="appStore.autoRefresh" class="middle" />
</span> --> </span>
</div> </div>
</div> </div>
</template> </template>
@ -66,6 +66,12 @@ const time = computed(() => [
appStore.durationRow.start, appStore.durationRow.start,
appStore.durationRow.end, appStore.durationRow.end,
]); ]);
const handleReload = () => {
const gap =
appStore.duration.end.getTime() - appStore.duration.start.getTime();
const time: Date[] = [new Date(new Date().getTime() - gap), new Date()];
appStore.setDuration(timeFormat(time));
};
function changeTimeRange(val: Date[]) { function changeTimeRange(val: Date[]) {
timeRange.value = timeRange.value =
val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0; val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;

View File

@ -101,3 +101,24 @@ export const ConfigData2: any = {
}, },
children: [], children: [],
}; };
export const ConfigData3: any = {
x: 0,
y: 0,
w: 8,
h: 12,
i: "0",
metrics: ["all_heatmap"],
metricTypes: ["readHeatMap"],
type: "Widget",
widget: {
title: "all_heatmap",
tips: "Tooltip",
},
graph: {
type: "HeatMap",
},
standard: {
unit: "min",
},
children: [],
};

View File

@ -28,6 +28,8 @@ interface AppState {
utcMin: number; utcMin: number;
eventStack: (() => unknown)[]; eventStack: (() => unknown)[];
timer: Nullable<any>; timer: Nullable<any>;
autoRefresh: boolean;
pageTitle: string;
} }
export const appStore = defineStore({ export const appStore = defineStore({
@ -39,6 +41,8 @@ export const appStore = defineStore({
utcMin: 0, utcMin: 0,
eventStack: [], eventStack: [],
timer: null, timer: null,
autoRefresh: false,
pageTitle: "",
}), }),
getters: { getters: {
duration(): Duration { duration(): Duration {
@ -117,6 +121,12 @@ export const appStore = defineStore({
setEventStack(funcs: (() => void)[]): void { setEventStack(funcs: (() => void)[]): void {
this.eventStack = funcs; this.eventStack = funcs;
}, },
setAutoRefresh(auto: boolean) {
this.autoRefresh = auto;
},
setPageTitle(title: string) {
this.pageTitle = title;
},
runEventStack() { runEventStack() {
if (this.timer) { if (this.timer) {
clearTimeout(this.timer); clearTimeout(this.timer);

View File

@ -18,7 +18,7 @@ import { defineStore } from "pinia";
import { store } from "@/store"; import { store } from "@/store";
import { LayoutConfig } from "@/types/dashboard"; import { LayoutConfig } from "@/types/dashboard";
import graph from "@/graph"; import graph from "@/graph";
import { ConfigData, ConfigData1, ConfigData2 } from "../data"; import { ConfigData, ConfigData1, ConfigData2, ConfigData3 } from "../data";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { NewControl } from "../data"; import { NewControl } from "../data";
@ -146,12 +146,19 @@ export const dashboardStore = defineStore({
}, },
setEntity(type: string) { setEntity(type: string) {
this.entity = type; this.entity = type;
// todo
if (type === "ServiceInstance") { if (type === "ServiceInstance") {
this.layout = [ConfigData1]; this.layout = [ConfigData1];
} }
if (type === "Endpoint") { if (type === "Endpoint") {
this.layout = [ConfigData2]; this.layout = [ConfigData2];
} }
if (type == "All") {
this.layout = [ConfigData3];
}
if (type == "Service") {
this.layout = [ConfigData];
}
}, },
setConfigs(param: { [key: string]: unknown }) { setConfigs(param: { [key: string]: unknown }) {
const actived = this.activedGridItem.split("-"); const actived = this.activedGridItem.split("-");

View File

@ -126,3 +126,14 @@
.mr-20 { .mr-20 {
margin-right: 20px; margin-right: 20px;
} }
@keyframes loading {
0% {
transform: rotate(0deg);
transform: rotate(0deg);
}
to {
transform: rotate(1turn);
transform: rotate(1turn);
}
}

View File

@ -16,6 +16,10 @@ limitations under the License. -->
<div class="about">{{ props.msg }}</div> <div class="about">{{ props.msg }}</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useAppStoreWithOut } from "@/store/modules/app";
const appStore = useAppStoreWithOut();
appStore.setPageTitle("Log");
/*global defineProps */ /*global defineProps */
const props = defineProps({ const props = defineProps({
msg: String, msg: String,

View File

@ -55,7 +55,7 @@ limitations under the License. -->
</div> </div>
<div class="flex-h item"> <div class="flex-h item">
<span class="label">{{ t("auto") }}</span> <span class="label">{{ t("auto") }}</span>
<el-switch :change="handleAuto" style="height: 25px" /> <el-switch v-model="auto" @change="handleAuto" style="height: 25px" />
<div class="auto-time ml-5"> <div class="auto-time ml-5">
<span class="auto-select"> <span class="auto-select">
<input <input
@ -90,17 +90,18 @@ const utcArr = appStore.utc.split(":");
const utcHour = ref<number>(isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0])); const utcHour = ref<number>(isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]));
const utcMin = ref<number>(isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1])); const utcMin = ref<number>(isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]));
appStore.setPageTitle("Setting");
const handleReload = () => { const handleReload = () => {
const gap = const gap =
appStore.duration.end.getTime() - appStore.duration.start.getTime(); appStore.duration.end.getTime() - appStore.duration.start.getTime();
const time: Date[] = [new Date(new Date().getTime() - gap), new Date()]; const time: Date[] = [new Date(new Date().getTime() - gap), new Date()];
appStore.setDuration(timeFormat(time)); appStore.setDuration(timeFormat(time));
}; };
const handleAuto = (status: boolean) => { const handleAuto = () => {
if (autoTime.value < 1) { if (autoTime.value < 1) {
return; return;
} }
auto.value = status; appStore.setAutoRefresh(auto.value);
if (auto.value) { if (auto.value) {
handleReload(); handleReload();
state.timer = setInterval(handleReload, autoTime.value * 1000); state.timer = setInterval(handleReload, autoTime.value * 1000);
@ -164,15 +165,16 @@ const setUTCMin = () => {
outline: none; outline: none;
padding-bottom: 0; padding-bottom: 0;
} }
.utc-min { .utc-min {
display: inline-block; display: inline-block;
padding-top: 2px; padding-top: 2px;
} }
.auto-select { .auto-select {
border-radius: 3px; border-radius: 3px;
background-color: #fff; background-color: #fff;
padding: 1px; padding: 1px;
border-radius: 3px;
input { input {
width: 38px; width: 38px;
@ -180,14 +182,17 @@ const setUTCMin = () => {
outline: 0; outline: 0;
} }
} }
.settings { .settings {
color: #222; color: #222;
font-family: inherit; font-family: inherit;
font-size: 14px; font-size: 14px;
padding: 20px; padding: 20px;
.item { .item {
margin-top: 10px; margin-top: 10px;
} }
input { input {
outline: 0; outline: 0;
width: 50px; width: 50px;
@ -196,6 +201,7 @@ const setUTCMin = () => {
text-align: center; text-align: center;
height: 25px; height: 25px;
} }
.label { .label {
width: 100px; width: 100px;
display: inline-block; display: inline-block;

View File

@ -34,8 +34,10 @@ import GridLayout from "./panel/Layout.vue";
import Tool from "./panel/Tool.vue"; import Tool from "./panel/Tool.vue";
import ConfigEdit from "./configuration/ConfigEdit.vue"; import ConfigEdit from "./configuration/ConfigEdit.vue";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app";
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const appStore = useAppStoreWithOut();
const { t } = useI18n(); const { t } = useI18n();
// fetch layout data from serve side // fetch layout data from serve side
// const layout: any[] = [ // const layout: any[] = [
@ -56,7 +58,7 @@ const { t } = useI18n();
// { x: 8, y: 27, w: 4, h: 15, i: "16" }, // { x: 8, y: 27, w: 4, h: 15, i: "16" },
// ]; // ];
// dashboardStore.setLayout(layout); // dashboardStore.setLayout(layout);
appStore.setPageTitle("Dashboard Name");
function handleClick(e: any) { function handleClick(e: any) {
e.stopPropagation(); e.stopPropagation();
if (e.target.className === "ds-main") { if (e.target.className === "ds-main") {

View File

@ -61,6 +61,10 @@ limitations under the License. -->
import { ref } from "vue"; import { ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { ElTable, ElTableColumn, ElButton, ElInput } from "element-plus"; import { ElTable, ElTableColumn, ElButton, ElInput } from "element-plus";
import { useAppStoreWithOut } from "@/store/modules/app";
const appStore = useAppStoreWithOut();
appStore.setPageTitle("Dashboard List");
// # - os-linux // # - os-linux
// # - k8s // # - k8s
// # - general(agent-installed) // # - general(agent-installed)
@ -107,9 +111,11 @@ const handleDelete = (index: number, row: any) => {
.header { .header {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
.dashboard-list { .dashboard-list {
padding: 20px; padding: 20px;
} }
.input-with-search { .input-with-search {
width: 300px; width: 300px;
margin-left: 20px; margin-left: 20px;

View File

@ -59,7 +59,10 @@ import router from "@/router";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { EntityType } from "./data"; import { EntityType } from "./data";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useAppStoreWithOut } from "@/store/modules/app";
const appStore = useAppStoreWithOut();
appStore.setPageTitle("Dashboard New");
const { t } = useI18n(); const { t } = useI18n();
const selectorStore = useSelectorStore(); const selectorStore = useSelectorStore();
const states = reactive({ const states = reactive({

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("fontSize") }}</span>
<el-slider
class="slider"
v-model="fontSize"
show-input
input-size="small"
:min="10"
:max="20"
:step="1"
@change="updateConfig({ fontSize })"
/>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const fontSize = ref(dashboardStore.selectedGrid.graph.fontSize);
function updateConfig(param: { [key: string]: unknown }) {
const graph = {
...dashboardStore.selectedGrid.graph,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
}
</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

@ -93,6 +93,10 @@ export default defineComponent({
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const selectorStore = useSelectorStore(); const selectorStore = useSelectorStore();
if (dashboardStore.entity === EntityType[1].value) {
queryMetrics();
}
async function queryMetrics() { async function queryMetrics() {
const params = await useQueryProcessor(props.data); const params = await useQueryProcessor(props.data);
if (!params) { if (!params) {
@ -133,7 +137,7 @@ export default defineComponent({
} }
); );
watch( watch(
() => [selectorStore.currentService], () => selectorStore.currentService,
() => { () => {
if (dashboardStore.entity === EntityType[0].value) { if (dashboardStore.entity === EntityType[0].value) {
queryMetrics(); queryMetrics();
@ -141,12 +145,9 @@ export default defineComponent({
} }
); );
watch( watch(
() => [selectorStore.currentPod], () => selectorStore.currentPod,
() => { () => {
if ( if (dashboardStore.entity === EntityType[0].value) {
dashboardStore.entity === EntityType[0].value ||
dashboardStore.entity === EntityType[1].value
) {
return; return;
} }
queryMetrics(); queryMetrics();

View File

@ -41,7 +41,7 @@ export const MetricChartType: any = {
], ],
sortMetrics: [{ label: "Top List", value: "TopList" }], sortMetrics: [{ label: "Top List", value: "TopList" }],
readLabeledMetricsValues: [{ label: "Line", value: "Line" }], readLabeledMetricsValues: [{ label: "Line", value: "Line" }],
readHeatMap: [{ label: "Heatmap", value: "Heatmap" }], readHeatMap: [{ label: "Heat Map", value: "HeatMap" }],
readSampledRecords: [{ label: "Top List", value: "TopList" }], readSampledRecords: [{ label: "Top List", value: "TopList" }],
}; };
export const DefaultGraphConfig: { [key: string]: any } = { export const DefaultGraphConfig: { [key: string]: any } = {
@ -93,6 +93,9 @@ export const DefaultGraphConfig: { [key: string]: any } = {
dashboardName: "", dashboardName: "",
fontSize: 12, fontSize: 12,
}, },
HeatMap: {
type: "HeatMap",
},
}; };
export enum MetricsType { export enum MetricsType {
@ -141,16 +144,10 @@ export const EntityType = [
{ value: "All", label: "All", key: 10 }, { value: "All", label: "All", key: 10 },
{ value: "Endpoint", label: "Service Endpoint", key: 3 }, { value: "Endpoint", label: "Service Endpoint", key: 3 },
{ value: "ServiceInstance", label: "Service Instance", key: 3 }, { value: "ServiceInstance", label: "Service Instance", key: 3 },
{ value: "ServiceRelationClient", label: "Service Relation(client)", key: 2 }, { value: "ServiceRelation", label: "Service Relation", key: 2 },
{ value: "ServiceRelationServer", label: "Service Relation(server)", key: 2 },
{ {
value: "ServiceInstanceRelationClient", value: "ServiceInstanceRelation",
label: "Service Instance Relation(client)", label: "Service Instance Relation",
key: 4,
},
{
value: "ServiceInstanceRelationServer",
label: "Service Instance Relation(server)",
key: 4, key: 4,
}, },
{ value: "EndpointRelation", label: "Endpoint Relation", key: 4 }, { value: "EndpointRelation", label: "Endpoint Relation", key: 4 },

View File

@ -49,10 +49,16 @@ limitations under the License. -->
<template #default="scope"> <template #default="scope">
<div class="chart"> <div class="chart">
<Line <Line
:data="{ metric: scope.row[metric] }" v-if="config.metricTypes[index] === 'readMetricsValues'"
:data="{ [metric]: scope.row[metric] }"
:intervalTime="intervalTime" :intervalTime="intervalTime"
:config="{ showXAxis: false, showYAxis: false }" :config="{ showXAxis: false, showYAxis: false }"
/> />
<Card
v-else
:data="{ [metric]: scope.row[metric] }"
:config="{ textAlign: 'left' }"
/>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -79,6 +85,7 @@ import { Endpoint } from "@/types/selector";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor"; import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
import Line from "./Line.vue"; import Line from "./Line.vue";
import Card from "./Card.vue";
import { EntityType } from "../data"; import { EntityType } from "../data";
/*global defineProps */ /*global defineProps */
@ -158,7 +165,9 @@ function searchList() {
watch( watch(
() => [props.config.metricTypes, props.config.metrics], () => [props.config.metricTypes, props.config.metrics],
() => { () => {
queryEndpointMetrics(endpoints.value); if (dashboardStore.showConfig) {
queryEndpointMetrics(endpoints.value);
}
} }
); );
</script> </script>

View File

@ -23,7 +23,9 @@ import { StandardConfig } from "@/types/dashboard";
/*global defineProps */ /*global defineProps */
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object as PropType<{ nodes: number[][]; buckets: number[][] }>, type: Object as PropType<{
[key: string]: { nodes: number[][]; buckets: number[][] };
}>,
default: () => ({}), default: () => ({}),
}, },
intervalTime: { type: Array as PropType<string[]>, default: () => [] }, intervalTime: { type: Array as PropType<string[]>, default: () => [] },
@ -37,8 +39,11 @@ const props = defineProps({
}, },
}); });
const option = computed(() => getOption()); const option = computed(() => getOption());
function getOption() { function getOption() {
const source = (props.data.nodes || []).map((d: number[]) => d[2]); const metric = props.config.metrics[0];
const nodes = (props.data[metric] && props.data[metric].nodes) || [];
const source = (nodes || []).map((d: number[]) => d[2]);
const maxItem = Math.max(...source); const maxItem = Math.max(...source);
const minItem = Math.min(...source); const minItem = Math.min(...source);
const colorBox = [ const colorBox = [
@ -63,15 +68,16 @@ function getOption() {
"#761212", "#761212",
"#671010", "#671010",
]; ];
return { return {
tooltip: { tooltip: {
position: "top", position: "top",
formatter: (a: any) => // formatter: (a: any) =>
`${a.data[1] * 100}${props.standard.unit} [ ${a.data[2]} ]`, // `${a.data[1] * 100}${props.standard.unit} [ ${a.data[2]} ]`,
textStyle: { // textStyle: {
fontSize: 13, // fontSize: 13,
color: "#ccc", // color: "#ccc",
}, // },
}, },
grid: { grid: {
top: 15, top: 15,
@ -112,7 +118,7 @@ function getOption() {
series: [ series: [
{ {
type: "heatmap", type: "heatmap",
data: props.data.nodes || [], data: nodes || [],
emphasis: { emphasis: {
itemStyle: { itemStyle: {
shadowBlur: 10, shadowBlur: 10,

View File

@ -170,7 +170,9 @@ function searchList() {
watch( watch(
() => [props.config.metricTypes, props.config.metrics], () => [props.config.metricTypes, props.config.metrics],
() => { () => {
queryInstanceMetrics(instances.value); if (dashboardStore.showConfig) {
queryInstanceMetrics(instances.value);
}
} }
); );
</script> </script>

View File

@ -34,7 +34,7 @@ limitations under the License. -->
<template #default="scope"> <template #default="scope">
<router-link <router-link
class="link" class="link"
:to="`/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${selectorStore.currentService.id}/${config.dashboardName}`" :to="`/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${scope.row.id}/${config.dashboardName}`"
:key="1" :key="1"
:style="{ fontSize: `${config.fontSize}px` }" :style="{ fontSize: `${config.fontSize}px` }"
> >
@ -50,10 +50,16 @@ limitations under the License. -->
<template #default="scope"> <template #default="scope">
<div class="chart"> <div class="chart">
<Line <Line
:data="{ metric: scope.row[metric] }" v-if="config.metricTypes[index] === 'readMetricsValues'"
:data="{ [metric]: scope.row[metric] }"
:intervalTime="intervalTime" :intervalTime="intervalTime"
:config="{ showXAxis: false, showYAxis: false }" :config="{ showXAxis: false, showYAxis: false }"
/> />
<Card
v-else
:data="{ [metric]: scope.row[metric] }"
:config="{ textAlign: 'left' }"
/>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -76,6 +82,7 @@ import { ElMessage } from "element-plus";
import type { PropType } from "vue"; import type { PropType } from "vue";
import { ServiceListConfig } from "@/types/dashboard"; import { ServiceListConfig } from "@/types/dashboard";
import Line from "./Line.vue"; import Line from "./Line.vue";
import Card from "./Card.vue";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { Service } from "@/types/selector"; import { Service } from "@/types/selector";
@ -111,13 +118,14 @@ queryServices();
async function queryServices() { async function queryServices() {
chartLoading.value = true; chartLoading.value = true;
const resp = await selectorStore.fetchServices(); const resp = await selectorStore.fetchServices(dashboardStore.layerId);
chartLoading.value = false; chartLoading.value = false;
if (resp.errors) { if (resp.errors) {
ElMessage.error(resp.errors); ElMessage.error(resp.errors);
} }
services.value = selectorStore.services.splice(0, pageSize); services.value = selectorStore.services.splice(0, pageSize);
queryServiceMetrics(services.value);
} }
async function queryServiceMetrics(currentServices: Service[]) { async function queryServiceMetrics(currentServices: Service[]) {
const { metrics } = props.config; const { metrics } = props.config;
@ -155,7 +163,9 @@ function searchList() {
watch( watch(
() => [props.config.metricTypes, props.config.metrics], () => [props.config.metricTypes, props.config.metrics],
() => { () => {
queryServiceMetrics(services.value); if (dashboardStore.showConfig) {
queryServiceMetrics(services.value);
}
} }
); );
</script> </script>

View File

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

View File

@ -40,7 +40,7 @@ limitations under the License. -->
size="mini" size="mini"
placeholder="Select a data" placeholder="Select a data"
@change="changePods" @change="changePods"
class="selectors" class="selectorPod"
/> />
</div> </div>
<div class="selectors-item" v-if="states.key === 2"> <div class="selectors-item" v-if="states.key === 2">
@ -84,9 +84,10 @@ limitations under the License. -->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive } from "vue"; import { reactive, watch } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app";
import { EntityType, ToolIcons } from "../data"; import { EntityType, ToolIcons } from "../data";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
@ -95,6 +96,7 @@ import { Service } from "@/types/selector";
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const selectorStore = useSelectorStore(); const selectorStore = useSelectorStore();
const appStore = useAppStoreWithOut();
const params = useRoute().params; const params = useRoute().params;
const type = EntityType.filter((d: Option) => d.value === params.entity)[0]; const type = EntityType.filter((d: Option) => d.value === params.entity)[0];
const states = reactive<{ const states = reactive<{
@ -114,10 +116,14 @@ const states = reactive<{
dashboardStore.setLayer(String(params.layerId)); dashboardStore.setLayer(String(params.layerId));
dashboardStore.setEntity(String(params.entity)); dashboardStore.setEntity(String(params.entity));
if (params.serviceId) { initSelector();
setSelector();
} else { function initSelector() {
getServices(); if (params.serviceId) {
setSelector();
} else {
getServices();
}
} }
async function setSelector() { async function setSelector() {
@ -149,6 +155,9 @@ async function getServices() {
if (!dashboardStore.layerId) { if (!dashboardStore.layerId) {
return; return;
} }
if (dashboardStore.entity === EntityType[1].value) {
return;
}
const json = await selectorStore.fetchServices(dashboardStore.layerId); const json = await selectorStore.fetchServices(dashboardStore.layerId);
if (json.errors) { if (json.errors) {
ElMessage.error(json.errors); ElMessage.error(json.errors);
@ -173,7 +182,7 @@ async function changeService(service: Service[]) {
function changePods(pod: Option[]) { function changePods(pod: Option[]) {
if (pod[0]) { if (pod[0]) {
selectorStore.setCurrentPod(pod[0].value); selectorStore.setCurrentPod(pod[0]);
} else { } else {
selectorStore.setCurrentPod(""); selectorStore.setCurrentPod("");
} }
@ -227,6 +236,12 @@ async function fetchPods(type: string, setPod: boolean) {
return; return;
} }
} }
watch(
() => appStore.durationTime,
() => {
initSelector();
}
);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.dashboard-tool { .dashboard-tool {
@ -260,10 +275,14 @@ async function fetchPods(type: string, setPod: boolean) {
} }
.selectors { .selectors {
min-width: 180px; min-width: 200px;
} }
.selectors-item { .selectors-item {
margin-right: 5px; margin-right: 5px;
} }
.selectorPod {
width: 340px;
}
</style> </style>

View File

@ -50,7 +50,10 @@ import Endpoints from "./Endpoints.vue";
import Topology from "./Topology.vue"; import Topology from "./Topology.vue";
import Traces from "./Traces.vue"; import Traces from "./Traces.vue";
import Profiles from "./Profiles.vue"; import Profiles from "./Profiles.vue";
import { useAppStoreWithOut } from "@/store/modules/app";
const appStore = useAppStoreWithOut();
appStore.setPageTitle("General Service");
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const tabs = ["metrics", "topologies", "endpoints", "traces", "profiles"]; const tabs = ["metrics", "topologies", "endpoints", "traces", "profiles"];
@ -69,30 +72,36 @@ function handleClick(tab: string) {
.service-detail { .service-detail {
text-align: left; text-align: left;
} }
.tabs { .tabs {
padding: 15px 15px 0 15px; padding: 15px 15px 0 15px;
border-bottom: 1px solid var(--el-border-color-light); border-bottom: 1px solid var(--el-border-color-light);
} }
.tab { .tab {
display: inline-block; display: inline-block;
margin-right: 30px; margin-right: 30px;
font-size: 13px; font-size: 13px;
font-weight: 400; font-weight: 400;
height: 30px; height: 30px;
&:hover { &:hover {
color: var(--el-color-primary); color: var(--el-color-primary);
} }
&.active { &.active {
color: var(--el-color-primary); color: var(--el-color-primary);
border-bottom: 1px solid var(--el-color-primary); border-bottom: 1px solid var(--el-color-primary);
} }
} }
.title { .title {
padding: 5px 0 5px 15px; padding: 5px 0 5px 15px;
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
border-bottom: 1px solid #dfe4e8; border-bottom: 1px solid #dfe4e8;
background-color: #c4c8e133; background-color: #c4c8e133;
span { span {
display: inline-block; display: inline-block;
margin-right: 10px; margin-right: 10px;