mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-02 06:54:01 +00:00
feat: enhance dashboard features for custom configurations (#11)
This commit is contained in:
commit
e85d819356
@ -13,7 +13,7 @@ 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>
|
||||
<router-view />
|
||||
<router-view :key="$route.fullPath" />
|
||||
</template>
|
||||
|
||||
<style>
|
||||
|
@ -5,31 +5,14 @@ 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
|
||||
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>
|
||||
<input v-show="!imgUrl" type="file" @change="fileChange" accept="image/*" />
|
||||
<img v-if="imgUrl" :src="imgUrl" alt="" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
const imgUrl = ref<string>("");
|
||||
const fileChange = (e: any) => {
|
||||
const fileList = e.target.files;
|
||||
if (fileList.length === 0) {
|
||||
imgUrl.value = "";
|
||||
return;
|
||||
}
|
||||
const file = fileList[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event: any) => {
|
||||
imgUrl.value = event.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
</script>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>add_circle_outlinecontrol_point</title>
|
||||
<path d="M12 20.016q3.281 0 5.648-2.367t2.367-5.648-2.367-5.648-5.648-2.367-5.648 2.367-2.367 5.648 2.367 5.648 5.648 2.367zM12 2.016q4.125 0 7.055 2.93t2.93 7.055-2.93 7.055-7.055 2.93-7.055-2.93-2.93-7.055 2.93-7.055 7.055-2.93zM12.984 6.984v4.031h4.031v1.969h-4.031v4.031h-1.969v-4.031h-4.031v-1.969h4.031v-4.031h1.969z"></path>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
18
src/assets/icons/remove_circle_outline.svg
Normal file
18
src/assets/icons/remove_circle_outline.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- 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 version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>remove_circle_outline</title>
|
||||
<path d="M12 20.016q3.281 0 5.648-2.367t2.367-5.648-2.367-5.648-5.648-2.367-5.648 2.367-2.367 5.648 2.367 5.648 5.648 2.367zM12 2.016q4.125 0 7.055 2.93t2.93 7.055-2.93 7.055-7.055 2.93-7.055-2.93-2.93-7.055 2.93-7.055 7.055-2.93zM6.984 11.016h10.031v1.969h-10.031v-1.969z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -277,15 +277,9 @@ limitations under the License. -->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
defineProps,
|
||||
computed,
|
||||
defineEmits,
|
||||
onMounted,
|
||||
watch,
|
||||
reactive,
|
||||
} from "vue";
|
||||
import { computed, onMounted, watch, reactive } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
/*global defineProps, defineEmits */
|
||||
const emit = defineEmits(["input", "setDates", "ok"]);
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
@ -580,11 +574,13 @@ onMounted(() => {
|
||||
user-select: none;
|
||||
color: #3d444f;
|
||||
}
|
||||
|
||||
.calendar + .calendar {
|
||||
border-left: solid 1px #eaeaea;
|
||||
margin-left: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.calendar-head {
|
||||
line-height: 34px;
|
||||
height: 34px;
|
||||
@ -630,10 +626,12 @@ onMounted(() => {
|
||||
.calendar-next-month-btn {
|
||||
right: 24px;
|
||||
}
|
||||
|
||||
.calendar-next-month-btn .middle,
|
||||
.calendar-prev-month-btn .middle {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.calendar-body {
|
||||
position: relative;
|
||||
width: 196px;
|
||||
|
@ -16,20 +16,12 @@ limitations under the License. -->
|
||||
<div ref="chartRef" :style="`height:${height};width:${width};`"></div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
watch,
|
||||
ref,
|
||||
defineProps,
|
||||
Ref,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
unref,
|
||||
} from "vue";
|
||||
import { watch, ref, Ref, onMounted, onBeforeUnmount, unref } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { useECharts } from "@/hooks/useEcharts";
|
||||
import { addResizeListener, removeResizeListener } from "@/utils/event";
|
||||
|
||||
/*global Nullable*/
|
||||
/*global Nullable, defineProps*/
|
||||
const chartRef = ref<Nullable<HTMLDivElement>>(null);
|
||||
const { setOptions, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const props = defineProps({
|
||||
@ -49,8 +41,11 @@ onMounted(() => {
|
||||
|
||||
watch(
|
||||
() => props.option,
|
||||
(opt) => {
|
||||
setOptions(opt);
|
||||
(newVal, oldVal) => {
|
||||
if (JSON.stringify(newVal) === JSON.stringify(oldVal)) {
|
||||
return;
|
||||
}
|
||||
setOptions(newVal);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -28,8 +28,9 @@ limitations under the License. -->
|
||||
</svg>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
import "@/assets/icons/index";
|
||||
|
||||
/*global defineProps */
|
||||
defineProps({
|
||||
iconName: { type: String, default: "" },
|
||||
size: { type: String, default: "sm" },
|
||||
@ -42,25 +43,31 @@ defineProps({
|
||||
height: 16px;
|
||||
vertical-align: middle;
|
||||
fill: currentColor;
|
||||
|
||||
&.sm {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
&.middle {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
&.lg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
&.loading {
|
||||
animation: loading 1.5s linear infinite;
|
||||
}
|
||||
|
||||
&.logo {
|
||||
height: 30px;
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
&.xl {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
|
@ -20,6 +20,7 @@ limitations under the License. -->
|
||||
@change="changeSelected"
|
||||
filterable
|
||||
:multiple="multiple"
|
||||
:disabled="disabled"
|
||||
:style="{ borderRadius }"
|
||||
>
|
||||
<el-option
|
||||
@ -32,7 +33,7 @@ limitations under the License. -->
|
||||
</el-select>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, defineEmits } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { ElSelect, ElOption } from "element-plus";
|
||||
|
||||
@ -41,8 +42,9 @@ interface Option {
|
||||
value: string;
|
||||
}
|
||||
|
||||
/*global defineProps, defineEmits*/
|
||||
|
||||
const emit = defineEmits(["change"]);
|
||||
/*global defineProps*/
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Array as PropType<Option[]>,
|
||||
@ -56,12 +58,11 @@ const props = defineProps({
|
||||
placeholder: { type: String, default: "Select a option" },
|
||||
borderRadius: { type: Number, default: 3 },
|
||||
multiple: { type: Boolean, default: false },
|
||||
disabled: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
const selected = ref<string[] | string>(props.value);
|
||||
function changeSelected() {
|
||||
if (!props.multiple) {
|
||||
return;
|
||||
}
|
||||
const options = props.options.filter((d: Option) =>
|
||||
props.multiple
|
||||
? selected.value.includes(d.value)
|
||||
@ -69,6 +70,12 @@ function changeSelected() {
|
||||
);
|
||||
emit("change", options);
|
||||
}
|
||||
watch(
|
||||
() => props.value,
|
||||
(data) => {
|
||||
selected.value = data;
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
.icon {
|
||||
|
@ -142,17 +142,10 @@ limitations under the License. -->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
defineProps,
|
||||
ref,
|
||||
computed,
|
||||
defineEmits,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
watch,
|
||||
} from "vue";
|
||||
import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DateCalendar from "./DateCalendar.vue";
|
||||
/*global defineProps, defineEmits */
|
||||
const datepicker = ref(null);
|
||||
const { t } = useI18n();
|
||||
const show = ref<boolean>(false);
|
||||
@ -339,6 +332,30 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@keyframes datepicker-anim-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes datepicker-anim-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
@ -373,7 +390,6 @@ watch(
|
||||
margin-left: -8px;
|
||||
margin-top: -8px;
|
||||
text-align: center;
|
||||
background: #ccc;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
background: #ccc
|
||||
@ -384,6 +400,7 @@ watch(
|
||||
.datepicker__clearable:hover:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.datepicker__clearable:hover .datepicker-close {
|
||||
display: block;
|
||||
}
|
||||
@ -436,25 +453,30 @@ watch(
|
||||
padding: 5px;
|
||||
overflow: hidden;
|
||||
z-index: 999;
|
||||
|
||||
&.top {
|
||||
bottom: 30px;
|
||||
right: 0;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
top: 30px;
|
||||
right: 0;
|
||||
transform-origin: center top;
|
||||
}
|
||||
|
||||
&.left {
|
||||
top: 30px;
|
||||
transform-origin: center top;
|
||||
}
|
||||
|
||||
&.right {
|
||||
right: -80px;
|
||||
top: 30px;
|
||||
transform-origin: center top;
|
||||
}
|
||||
|
||||
&__sidebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -464,6 +486,7 @@ watch(
|
||||
padding: 5px;
|
||||
border-right: solid 1px #eaeaea;
|
||||
}
|
||||
|
||||
&__shortcut {
|
||||
display: block;
|
||||
width: 100%;
|
||||
@ -476,10 +499,12 @@ watch(
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
color: #3f97e3;
|
||||
}
|
||||
}
|
||||
|
||||
&__body {
|
||||
margin-left: 100px;
|
||||
padding-left: 5px;
|
||||
@ -513,6 +538,7 @@ watch(
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.datepicker-anim-enter-active {
|
||||
transform-origin: 0 0;
|
||||
animation: datepicker-anim-in 0.2s cubic-bezier(0.23, 1, 0.32, 1);
|
||||
@ -545,26 +571,4 @@ watch(
|
||||
.datepicker__buttons .datepicker__button-cancel {
|
||||
background: #666;
|
||||
}
|
||||
|
||||
@keyframes datepicker-anim-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes datepicker-anim-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -18,47 +18,16 @@ export const TypeOfMetrics = {
|
||||
variable: "$name: String!",
|
||||
query: `typeOfMetrics(name: $name)`,
|
||||
};
|
||||
export const queryMetricsValues = {
|
||||
variable: ["$condition: MetricsCondition!, $duration: Duration!"],
|
||||
export const listMetrics = {
|
||||
variable: "$regex: String",
|
||||
query: `
|
||||
readMetricsValues: readMetricsValues(condition: $condition, duration: $duration) {
|
||||
label
|
||||
values {
|
||||
values {value}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const queryMetricsValue = {
|
||||
variable: ["$condition: MetricsCondition!, $duration: Duration!"],
|
||||
query: `
|
||||
readMetricsValue: readMetricsValue(condition: $condition, duration: $duration)`,
|
||||
};
|
||||
|
||||
export const querySortMetrics = {
|
||||
variable: ["$condition: TopNCondition!, $duration: Duration!"],
|
||||
query: `
|
||||
sortMetrics: sortMetrics(condition: $condition, duration: $duration) {
|
||||
name
|
||||
id
|
||||
value
|
||||
refId
|
||||
}`,
|
||||
};
|
||||
export const queryLabeledMetricsValues = {
|
||||
variable: [
|
||||
"$condition: MetricsCondition!, $labels: [String!]!, $duration: Duration!",
|
||||
],
|
||||
query: `
|
||||
readLabeledMetricsValues: readLabeledMetricsValues(
|
||||
condition: $condition,
|
||||
labels: $labels,
|
||||
duration: $duration) {
|
||||
label
|
||||
values {
|
||||
values {value}
|
||||
}
|
||||
}`,
|
||||
metrics: listMetrics(regex: $regex) {
|
||||
value: name
|
||||
label: name
|
||||
type
|
||||
catalog
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const queryHeatMap = {
|
||||
@ -75,12 +44,3 @@ export const queryHeatMap = {
|
||||
}
|
||||
}`,
|
||||
};
|
||||
export const querySampledRecords = {
|
||||
variable: ["$condition: TopNCondition!, $duration: Duration!"],
|
||||
query: `
|
||||
readSampledRecords: readSampledRecords(condition: $condition, duration: $duration) {
|
||||
name
|
||||
value
|
||||
refId
|
||||
}`,
|
||||
};
|
||||
|
@ -15,14 +15,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const Services = {
|
||||
variable: ["$layer: String!"],
|
||||
variable: "$layer: String!",
|
||||
query: `
|
||||
services: listServices(layer: $layer) {
|
||||
value: id
|
||||
services: listServices(layer: $layer) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
group
|
||||
layer
|
||||
}
|
||||
layers
|
||||
normal
|
||||
}
|
||||
`,
|
||||
};
|
||||
export const Layers = {
|
||||
@ -33,10 +35,13 @@ export const Layers = {
|
||||
export const Instances = {
|
||||
variable: "$serviceId: ID!, $duration: Duration!",
|
||||
query: `
|
||||
getServiceInstances(duration: $duration, serviceId: $serviceId) {
|
||||
key: id
|
||||
pods: listInstances(duration: $duration, serviceId: $serviceId) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
language
|
||||
instanceUUID
|
||||
layer
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
@ -47,9 +52,55 @@ export const Instances = {
|
||||
export const Endpoints = {
|
||||
variable: "$serviceId: ID!, $keyword: String!",
|
||||
query: `
|
||||
getEndpoints: searchEndpoint(serviceId: $serviceId, keyword: $keyword, limit: 100) {
|
||||
key: id
|
||||
label: name
|
||||
pods: findEndpoint(serviceId: $serviceId, keyword: $keyword, limit: 100) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const getService = {
|
||||
variable: "$serviceId: String!",
|
||||
query: `
|
||||
service: getService(serviceId: $serviceId) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
group
|
||||
layers
|
||||
normal
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const getInstance = {
|
||||
variable: "$instanceId: String!",
|
||||
query: `
|
||||
instance: getInstance(instanceId: $instanceId) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
language
|
||||
instanceUUID
|
||||
layer
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const getEndpoint = {
|
||||
variable: "$endpointId: ID!",
|
||||
query: `
|
||||
endpoint: getEndpointInfo(endpointId: $endpointId) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
serviceId
|
||||
serviceName
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
@ -16,25 +16,12 @@
|
||||
*/
|
||||
import {
|
||||
TypeOfMetrics,
|
||||
querySampledRecords,
|
||||
queryHeatMap,
|
||||
queryLabeledMetricsValues,
|
||||
querySortMetrics,
|
||||
queryMetricsValue,
|
||||
queryMetricsValues,
|
||||
listMetrics,
|
||||
} from "../fragments/dashboard";
|
||||
|
||||
export const queryTypeOfMetrics = `query typeOfMetrics(${TypeOfMetrics.variable}) {${TypeOfMetrics.query}}`;
|
||||
|
||||
export const readHeatMap = `query queryData(${queryHeatMap.variable}) {${queryHeatMap.query}}`;
|
||||
|
||||
export const readSampledRecords = `query queryData(${querySampledRecords.variable}) {${querySampledRecords.query}}`;
|
||||
|
||||
export const readLabeledMetricsValues = `query queryData(${queryLabeledMetricsValues.variable}) {
|
||||
${queryLabeledMetricsValues.query}}`;
|
||||
|
||||
export const sortMetrics = `query queryData(${querySortMetrics.variable}) {${querySortMetrics.query}}`;
|
||||
|
||||
export const readMetricsValue = `query queryData(${queryMetricsValue.variable}) {${queryMetricsValue.query}}`;
|
||||
|
||||
export const readMetricsValues = `query queryData(${queryMetricsValues.variable}) {${queryMetricsValues.query}}`;
|
||||
export const queryMetrics = `query queryData(${listMetrics.variable}) {${listMetrics.query}}`;
|
||||
|
@ -14,10 +14,20 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Services, Layers, Endpoints, Instances } from "../fragments/selector";
|
||||
import {
|
||||
Services,
|
||||
Layers,
|
||||
Endpoints,
|
||||
Instances,
|
||||
getService,
|
||||
getInstance,
|
||||
getEndpoint,
|
||||
} from "../fragments/selector";
|
||||
|
||||
export const queryServices = `query queryServices(${Services.variable}) {${Services.query}}`;
|
||||
export const queryLayers = `query ${Layers.query}`;
|
||||
export const queryEndpoints = `query queryEndpoints(${Endpoints.variable}) {${Endpoints.query}}`;
|
||||
|
||||
export const queryInstances = `query queryInstances(${Instances.variable}) {${Instances.query}}`;
|
||||
export const queryLayers = `query listLayer {${Layers.query}}`;
|
||||
export const queryService = `query queryService(${getService.variable}) {${getService.query}}`;
|
||||
export const queryInstance = `query queryInstance(${getInstance.variable}) {${getInstance.query}}`;
|
||||
export const queryEndpoint = `query queryInstance(${getEndpoint.variable}) {${getEndpoint.query}}`;
|
||||
|
@ -14,6 +14,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export enum MetricQueryTypes {
|
||||
ReadMetricsValue = "readMetricsValue",
|
||||
ReadMetricsValues = "readMetricsValues",
|
||||
SortMetrics = "sortMetrics",
|
||||
ReadLabeledMetricsValues = "readLabeledMetricsValues",
|
||||
READHEATMAP = "readHeatMap",
|
||||
ReadSampledRecords = "readSampledRecords",
|
||||
}
|
||||
export enum sizeEnum {
|
||||
XS = "XS",
|
||||
SM = "SM",
|
||||
@ -32,7 +40,7 @@ export enum screenEnum {
|
||||
XXL = 1600,
|
||||
}
|
||||
|
||||
const screenMap = new Map<sizeEnum, number>();
|
||||
export const screenMap = new Map<sizeEnum, number>();
|
||||
|
||||
screenMap.set(sizeEnum.XS, screenEnum.XS);
|
||||
screenMap.set(sizeEnum.SM, screenEnum.SM);
|
||||
@ -41,4 +49,47 @@ screenMap.set(sizeEnum.LG, screenEnum.LG);
|
||||
screenMap.set(sizeEnum.XL, screenEnum.XL);
|
||||
screenMap.set(sizeEnum.XXL, screenEnum.XXL);
|
||||
|
||||
export { screenMap };
|
||||
export const RespFields: any = {
|
||||
readMetricsValues: `{
|
||||
label
|
||||
values {
|
||||
values {value}
|
||||
}
|
||||
}`,
|
||||
readMetricsValue: "",
|
||||
sortMetrics: `{
|
||||
name
|
||||
id
|
||||
value
|
||||
refId
|
||||
}`,
|
||||
readLabeledMetricsValues: `{
|
||||
label
|
||||
values {
|
||||
values {value}
|
||||
}
|
||||
}`,
|
||||
readHeatMap: `{
|
||||
values {
|
||||
id
|
||||
values
|
||||
}
|
||||
buckets {
|
||||
min
|
||||
max
|
||||
}
|
||||
}`,
|
||||
readSampledRecords: `{
|
||||
name
|
||||
value
|
||||
refId
|
||||
}`,
|
||||
};
|
||||
export enum CalculationType {
|
||||
Plus = "+",
|
||||
Minus = "-",
|
||||
Multiplication = "*",
|
||||
Division = "/",
|
||||
"Convert Unix Timestamp(milliseconds)" = "milliseconds",
|
||||
"Convert Unix Timestamp(seconds)" = "seconds",
|
||||
}
|
||||
|
254
src/hooks/useProcessor.ts
Normal file
254
src/hooks/useProcessor.ts
Normal file
@ -0,0 +1,254 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
import { RespFields, MetricQueryTypes } from "./data";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { Instance, Endpoint } from "@/types/selector";
|
||||
|
||||
export function useQueryProcessor(config: any) {
|
||||
if (!(config.metrics && config.metrics[0])) {
|
||||
return;
|
||||
}
|
||||
const appStore = useAppStoreWithOut();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const selectorStore = useSelectorStore();
|
||||
if (!selectorStore.currentService) {
|
||||
return;
|
||||
}
|
||||
const conditions: { [key: string]: unknown } = {
|
||||
duration: appStore.durationTime,
|
||||
};
|
||||
const variables: string[] = [`$duration: Duration!`];
|
||||
const isRelation = [
|
||||
"ServiceRelation",
|
||||
"ServiceInstanceRelation",
|
||||
"EndpointRelation",
|
||||
].includes(dashboardStore.entity);
|
||||
const fragment = config.metrics.map((name: string, index: number) => {
|
||||
const metricType = config.metricTypes[index] || "";
|
||||
const labels = ["0", "1", "2", "3", "4"];
|
||||
if (
|
||||
[
|
||||
MetricQueryTypes.ReadSampledRecords,
|
||||
MetricQueryTypes.SortMetrics,
|
||||
].includes(metricType)
|
||||
) {
|
||||
variables.push(`$condition${index}: TopNCondition!`);
|
||||
conditions[`condition${index}`] = {
|
||||
name,
|
||||
parentService: ["Service", "All"].includes(dashboardStore.entity)
|
||||
? null
|
||||
: selectorStore.currentService.value,
|
||||
normal: selectorStore.currentService.normal,
|
||||
scope: dashboardStore.entity,
|
||||
topN: 10,
|
||||
order: "DES",
|
||||
};
|
||||
} else {
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
variables.push(`$labels${index}: [String!]!`);
|
||||
conditions[`labels${index}`] = labels;
|
||||
}
|
||||
variables.push(`$condition${index}: MetricsCondition!`);
|
||||
conditions[`condition${index}`] = {
|
||||
name,
|
||||
entity: {
|
||||
scope: dashboardStore.entity,
|
||||
serviceName:
|
||||
dashboardStore.entity === "All"
|
||||
? undefined
|
||||
: selectorStore.currentService.value,
|
||||
normal:
|
||||
dashboardStore.entity === "All"
|
||||
? undefined
|
||||
: selectorStore.currentService.normal,
|
||||
serviceInstanceName: dashboardStore.entity.includes("ServiceInstance")
|
||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||
: undefined,
|
||||
endpointName: dashboardStore.entity.includes("Endpoint")
|
||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||
: undefined,
|
||||
destNormal: isRelation
|
||||
? selectorStore.currentDestService.normal
|
||||
: undefined,
|
||||
destServiceName: isRelation
|
||||
? selectorStore.currentDestService.value
|
||||
: undefined,
|
||||
destServiceInstanceName:
|
||||
dashboardStore.entity === "ServiceInstanceRelation"
|
||||
? selectorStore.currentDestPod &&
|
||||
selectorStore.currentDestPod.value
|
||||
: undefined,
|
||||
destEndpointName:
|
||||
dashboardStore.entity === "EndpointRelation"
|
||||
? selectorStore.currentDestPod &&
|
||||
selectorStore.currentDestPod.value
|
||||
: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
return `${name}${index}: ${metricType}(condition: $condition${index}, labels: $labels${index}, duration: $duration)${RespFields[metricType]}`;
|
||||
} else {
|
||||
return `${name}${index}: ${metricType}(condition: $condition${index}, duration: $duration)${RespFields[metricType]}`;
|
||||
}
|
||||
});
|
||||
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||
return {
|
||||
queryStr,
|
||||
conditions,
|
||||
};
|
||||
}
|
||||
export function useSourceProcessor(
|
||||
resp: { errors: string; data: { [key: string]: any } },
|
||||
config: { metrics: string[]; metricTypes: string[] }
|
||||
) {
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return {};
|
||||
}
|
||||
const source: { [key: string]: unknown } = {};
|
||||
const keys = Object.keys(resp.data);
|
||||
|
||||
config.metricTypes.forEach((type: string, index) => {
|
||||
const m = config.metrics[index];
|
||||
|
||||
if (type === MetricQueryTypes.ReadMetricsValues) {
|
||||
source[m] = resp.data[keys[index]].values.values.map(
|
||||
(d: { value: number }) => d.value
|
||||
);
|
||||
}
|
||||
if (type === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const resVal = Object.values(resp.data)[0] || [];
|
||||
const labelsIdx = ["0", "1", "2", "3", "4"];
|
||||
const labels = ["P50", "P75", "P90", "P95", "P99"];
|
||||
for (const item of resVal) {
|
||||
const values = item.values.values.map(
|
||||
(d: { value: number }) => d.value
|
||||
);
|
||||
|
||||
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
|
||||
if (labels[indexNum] && indexNum > -1) {
|
||||
source[labels[indexNum]] = values;
|
||||
} else {
|
||||
source[item.label] = values;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type === MetricQueryTypes.ReadMetricsValue) {
|
||||
source[m] = Object.values(resp.data)[0];
|
||||
}
|
||||
if (
|
||||
type === MetricQueryTypes.SortMetrics ||
|
||||
type === MetricQueryTypes.ReadSampledRecords
|
||||
) {
|
||||
source[m] = Object.values(resp.data)[0] || [];
|
||||
}
|
||||
if (type === MetricQueryTypes.READHEATMAP) {
|
||||
const resVal = Object.values(resp.data)[0] || {};
|
||||
const nodes = [] as any;
|
||||
if (!(resVal && resVal.values)) {
|
||||
source[m] = { nodes: [] };
|
||||
return;
|
||||
}
|
||||
resVal.values.forEach((items: { values: number[] }, x: number) => {
|
||||
const grids = items.values.map((val: number, y: number) => [x, y, val]);
|
||||
|
||||
nodes.push(...grids);
|
||||
});
|
||||
let buckets = [] as any;
|
||||
if (resVal.buckets.length) {
|
||||
buckets = [
|
||||
resVal.buckets[0].min,
|
||||
...resVal.buckets.map(
|
||||
(item: { min: string; max: string }) => item.max
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
source[m] = { nodes, buckets }; // nodes: number[][]
|
||||
}
|
||||
});
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
export function useQueryPodsMetrics(
|
||||
pods: Array<Instance | Endpoint>,
|
||||
config: { metrics: string[]; metricTypes: string[] },
|
||||
scope: string
|
||||
) {
|
||||
const appStore = useAppStoreWithOut();
|
||||
const selectorStore = useSelectorStore();
|
||||
const conditions: { [key: string]: unknown } = {
|
||||
duration: appStore.durationTime,
|
||||
};
|
||||
const variables: string[] = [`$duration: Duration!`];
|
||||
const { currentService } = selectorStore;
|
||||
|
||||
const fragmentList = pods.map((d: Instance | Endpoint, index: number) => {
|
||||
const param = {
|
||||
scope,
|
||||
serviceName: currentService.label,
|
||||
serviceInstanceName: scope === "ServiceInstance" ? d.label : undefined,
|
||||
endpointName: scope === "Endpoint" ? d.label : undefined,
|
||||
normal: currentService.normal,
|
||||
};
|
||||
const f = config.metrics.map((name: string, idx: number) => {
|
||||
const metricType = config.metricTypes[idx] || "";
|
||||
conditions[`condition${index}${idx}`] = {
|
||||
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 queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||
|
||||
return { queryStr, conditions };
|
||||
}
|
||||
export function usePodsSource(
|
||||
pods: Array<Instance | Endpoint>,
|
||||
resp: { errors: string; data: { [key: string]: any } },
|
||||
config: { metrics: string[]; metricTypes: string[] }
|
||||
): any {
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return {};
|
||||
}
|
||||
const data = pods.map((d: Instance | any, idx: number) => {
|
||||
config.metrics.map((name: string, index: number) => {
|
||||
const key = name + idx + index;
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValue) {
|
||||
d[name] = resp.data[key];
|
||||
}
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValues) {
|
||||
d[name] = resp.data[key].values.values.map(
|
||||
(d: { value: number }) => d.value
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return d;
|
||||
});
|
||||
return data;
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<section class="app-main">
|
||||
<router-view v-slot="{ Component }">
|
||||
<router-view v-slot="{ Component }" :key="$route.fullPath">
|
||||
<keep-alive>
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
|
@ -30,7 +30,7 @@ const msg = {
|
||||
events: "Events",
|
||||
alerts: "Alerts",
|
||||
settings: "Settings",
|
||||
dashboards: "Dashboards",
|
||||
dashboards: "Dashboard",
|
||||
profiles: "Profiles",
|
||||
database: "Database",
|
||||
serviceName: "Service Name",
|
||||
@ -53,7 +53,8 @@ const msg = {
|
||||
instance: "Instance",
|
||||
create: "Create",
|
||||
loading: "Loading",
|
||||
selectVisualization: "Select your visualization",
|
||||
selectVisualization: "Visualize your metrics",
|
||||
visualization: "Visualization",
|
||||
graphStyles: "Graph styles",
|
||||
widgetOptions: "Widget options",
|
||||
standardOptions: "Standard options",
|
||||
@ -72,6 +73,8 @@ const msg = {
|
||||
fontSize: "Font Size",
|
||||
showBackground: "Show Background",
|
||||
areaOpacity: "Area Opacity",
|
||||
editGraph: "Edit Graph Options",
|
||||
dashboardName: "Select Dashboard Name",
|
||||
hourTip: "Select Hour",
|
||||
minuteTip: "Select Minute",
|
||||
secondTip: "Select Second",
|
||||
|
@ -51,7 +51,8 @@ const msg = {
|
||||
endpoint: "端点",
|
||||
create: "新建",
|
||||
loading: "加载中",
|
||||
selectVisualization: "选择你的可视化",
|
||||
selectVisualization: "可视化指标",
|
||||
visualization: "可视化",
|
||||
graphStyles: "图形样式",
|
||||
widgetOptions: "组件选项",
|
||||
standardOptions: "标准选项",
|
||||
@ -70,6 +71,8 @@ const msg = {
|
||||
fontSize: "字体大小",
|
||||
showBackground: "显示背景",
|
||||
areaOpacity: "透明度",
|
||||
editGraph: "编辑图表选项",
|
||||
dashboardName: "选择仪表板名称",
|
||||
hourTip: "选择小时",
|
||||
minuteTip: "选择分钟",
|
||||
secondTip: "选择秒数",
|
||||
|
@ -20,10 +20,10 @@ import router from "./router";
|
||||
import { store } from "./store";
|
||||
import components from "@/components";
|
||||
import i18n from "./locales";
|
||||
import "element-plus/dist/index.css";
|
||||
import "./styles/lib.scss";
|
||||
import "./styles/reset.scss";
|
||||
import ElementPlus from "element-plus";
|
||||
import "element-plus/dist/index.css";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
|
@ -48,9 +48,29 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/dashboard/edit/:layerId/:entity/:dashboardId",
|
||||
path: "/dashboard/:layerId/:entity/:name",
|
||||
component: () => import("@/views/dashboard/Edit.vue"),
|
||||
name: "Edit",
|
||||
name: "Create",
|
||||
meta: {
|
||||
title: "dashboardEdit",
|
||||
exact: false,
|
||||
notShow: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:name",
|
||||
component: () => import("@/views/dashboard/Edit.vue"),
|
||||
name: "CreateService",
|
||||
meta: {
|
||||
title: "dashboardEdit",
|
||||
exact: false,
|
||||
notShow: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:name",
|
||||
component: () => import("@/views/dashboard/Edit.vue"),
|
||||
name: "ViewPod",
|
||||
meta: {
|
||||
title: "dashboardEdit",
|
||||
exact: false,
|
||||
|
@ -26,6 +26,8 @@ export const NewControl = {
|
||||
},
|
||||
graph: {},
|
||||
standard: {},
|
||||
metrics: [""],
|
||||
metricTypes: [""],
|
||||
};
|
||||
export const ConfigData: any = {
|
||||
x: 0,
|
||||
@ -34,14 +36,64 @@ export const ConfigData: any = {
|
||||
h: 12,
|
||||
i: "0",
|
||||
metrics: ["service_resp_time"],
|
||||
queryMetricType: "readMetricsValues",
|
||||
metricTypes: ["readMetricsValues"],
|
||||
type: "Widget",
|
||||
widget: {
|
||||
title: "Title",
|
||||
title: "service_resp_time",
|
||||
tips: "Tooltip",
|
||||
},
|
||||
graph: {
|
||||
type: "Line",
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
},
|
||||
standard: {
|
||||
sortOrder: "DEC",
|
||||
unit: "min",
|
||||
},
|
||||
children: [],
|
||||
};
|
||||
export const ConfigData1: any = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 8,
|
||||
h: 12,
|
||||
i: "0",
|
||||
metrics: ["service_instance_resp_time"],
|
||||
metricTypes: ["readMetricsValues"],
|
||||
type: "Widget",
|
||||
widget: {
|
||||
title: "service_instance_resp_time",
|
||||
tips: "Tooltip",
|
||||
},
|
||||
graph: {
|
||||
type: "Line",
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
},
|
||||
standard: {
|
||||
sortOrder: "DEC",
|
||||
unit: "min",
|
||||
},
|
||||
children: [],
|
||||
};
|
||||
export const ConfigData2: any = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 8,
|
||||
h: 12,
|
||||
i: "0",
|
||||
metrics: ["endpoint_avg"],
|
||||
metricTypes: ["readMetricsValues"],
|
||||
type: "Widget",
|
||||
widget: {
|
||||
title: "endpoint_avg",
|
||||
tips: "Tooltip",
|
||||
},
|
||||
graph: {
|
||||
type: "Line",
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
},
|
||||
standard: {
|
||||
sortOrder: "DEC",
|
||||
|
@ -18,10 +18,13 @@ import { defineStore } from "pinia";
|
||||
import { store } from "@/store";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
import graph from "@/graph";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { ConfigData } from "../data";
|
||||
import { ConfigData, ConfigData1, ConfigData2 } from "../data";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { NewControl } from "../data";
|
||||
import { Duration } from "@/types/app";
|
||||
import axios, { AxiosResponse } from "axios";
|
||||
import { cancelToken } from "@/utils/cancelToken";
|
||||
interface DashboardState {
|
||||
showConfig: boolean;
|
||||
layout: LayoutConfig[];
|
||||
@ -29,6 +32,8 @@ interface DashboardState {
|
||||
entity: string;
|
||||
layerId: string;
|
||||
activedGridItem: string;
|
||||
durationTime: Duration;
|
||||
selectorStore: any;
|
||||
}
|
||||
|
||||
export const dashboardStore = defineStore({
|
||||
@ -40,6 +45,8 @@ export const dashboardStore = defineStore({
|
||||
entity: "",
|
||||
layerId: "",
|
||||
activedGridItem: "",
|
||||
durationTime: useAppStoreWithOut().durationTime,
|
||||
selectorStore: useSelectorStore(),
|
||||
}),
|
||||
actions: {
|
||||
setLayout(data: LayoutConfig[]) {
|
||||
@ -50,6 +57,8 @@ export const dashboardStore = defineStore({
|
||||
...NewControl,
|
||||
i: String(this.layout.length),
|
||||
type,
|
||||
metricTypes: [""],
|
||||
metrics: [""],
|
||||
};
|
||||
if (type === "Tab") {
|
||||
newWidget.h = 24;
|
||||
@ -129,14 +138,20 @@ export const dashboardStore = defineStore({
|
||||
setConfigPanel(show: boolean) {
|
||||
this.showConfig = show;
|
||||
},
|
||||
selectWidget(widget: Nullable<LayoutConfig>) {
|
||||
this.selectedGrid = widget;
|
||||
selectWidget(item: Nullable<LayoutConfig>) {
|
||||
this.selectedGrid = item;
|
||||
},
|
||||
setLayer(id: string) {
|
||||
this.layerId = id;
|
||||
},
|
||||
setEntity(type: string) {
|
||||
this.entity = type;
|
||||
if (type === "ServiceInstance") {
|
||||
this.layout = [ConfigData1];
|
||||
}
|
||||
if (type === "Endpoint") {
|
||||
this.layout = [ConfigData2];
|
||||
}
|
||||
},
|
||||
setConfigs(param: { [key: string]: unknown }) {
|
||||
const actived = this.activedGridItem.split("-");
|
||||
@ -165,29 +180,24 @@ export const dashboardStore = defineStore({
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async fetchMetricValue(config: LayoutConfig) {
|
||||
// if (!config.queryMetricType) {
|
||||
// return;
|
||||
// }
|
||||
config.queryMetricType = "readMetricsValues";
|
||||
const appStoreWithOut = useAppStoreWithOut();
|
||||
const variable = {
|
||||
condition: {
|
||||
name: "service_resp_time",
|
||||
entity: {
|
||||
normal: true,
|
||||
scope: "Service",
|
||||
serviceName: "agentless::app",
|
||||
},
|
||||
},
|
||||
duration: appStoreWithOut.durationTime,
|
||||
};
|
||||
async fetchMetricList(regex: string) {
|
||||
const res: AxiosResponse = await graph
|
||||
.query(config.queryMetricType)
|
||||
.params(variable);
|
||||
.query("queryMetrics")
|
||||
.params({ regex });
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async fetchMetricValue(param: {
|
||||
queryStr: string;
|
||||
conditions: { [key: string]: unknown };
|
||||
}) {
|
||||
const res: AxiosResponse = await axios.post(
|
||||
"/graphql",
|
||||
{ query: param.queryStr, variables: { ...param.conditions } },
|
||||
{ cancelToken: cancelToken() }
|
||||
);
|
||||
return res.data;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -15,25 +15,45 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { defineStore } from "pinia";
|
||||
import { Option, Duration } from "@/types/app";
|
||||
import { Duration } from "@/types/app";
|
||||
import { Service, Instance, Endpoint } from "@/types/selector";
|
||||
import { store } from "@/store";
|
||||
import graph from "@/graph";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
|
||||
interface SelectorState {
|
||||
services: Option[];
|
||||
services: Service[];
|
||||
pods: Array<Instance | Endpoint>;
|
||||
currentService: Nullable<Service>;
|
||||
currentPod: Nullable<Instance | Endpoint>;
|
||||
currentDestService: Nullable<Service>;
|
||||
currentDestPod: Nullable<Instance | Endpoint>;
|
||||
durationTime: Duration;
|
||||
}
|
||||
|
||||
export const selectorStore = defineStore({
|
||||
id: "selector",
|
||||
state: (): SelectorState => ({
|
||||
services: [],
|
||||
pods: [],
|
||||
currentService: null,
|
||||
currentPod: null,
|
||||
currentDestService: null,
|
||||
currentDestPod: null,
|
||||
durationTime: useAppStoreWithOut().durationTime,
|
||||
}),
|
||||
actions: {
|
||||
setCurrentService(service: Service) {
|
||||
this.currentService = service;
|
||||
},
|
||||
setCurrentPod(pod: Nullable<Instance | Endpoint>) {
|
||||
this.currentPod = pod;
|
||||
},
|
||||
async fetchLayers(): Promise<AxiosResponse> {
|
||||
const res: AxiosResponse = await graph.query("queryLayers").params({});
|
||||
|
||||
return res;
|
||||
return res.data || {};
|
||||
},
|
||||
async fetchServices(layer: string): Promise<AxiosResponse> {
|
||||
const res: AxiosResponse = await graph
|
||||
@ -41,30 +61,89 @@ export const selectorStore = defineStore({
|
||||
.params({ layer });
|
||||
|
||||
if (!res.data.errors) {
|
||||
this.services = res.data.data.services;
|
||||
this.services = res.data.data.services || [];
|
||||
}
|
||||
return res;
|
||||
return res.data;
|
||||
},
|
||||
async getServiceInstances(params: {
|
||||
async getServiceInstances(param?: {
|
||||
serviceId: string;
|
||||
duration: Duration;
|
||||
}): Promise<AxiosResponse> {
|
||||
const res: AxiosResponse = await graph
|
||||
.query("queryInstances")
|
||||
.params(params);
|
||||
return res;
|
||||
}): Promise<Nullable<AxiosResponse>> {
|
||||
const serviceId = param ? param.serviceId : this.currentService?.id;
|
||||
if (!serviceId) {
|
||||
return null;
|
||||
}
|
||||
const res: AxiosResponse = await graph.query("queryInstances").params({
|
||||
serviceId,
|
||||
duration: this.durationTime,
|
||||
});
|
||||
if (!res.data.errors) {
|
||||
this.pods = res.data.data.pods || [];
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
async getEndpoints(params: {
|
||||
keyword: string;
|
||||
serviceId: string;
|
||||
}): Promise<AxiosResponse> {
|
||||
async getEndpoints(params?: {
|
||||
keyword?: string;
|
||||
serviceId?: string;
|
||||
}): Promise<Nullable<AxiosResponse>> {
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
if (!params.keyword) {
|
||||
params.keyword = "";
|
||||
}
|
||||
const res: AxiosResponse = await graph
|
||||
.query("queryEndpoints")
|
||||
.params(params);
|
||||
return res;
|
||||
const serviceId = params.serviceId || this.currentService?.id;
|
||||
if (!serviceId) {
|
||||
return null;
|
||||
}
|
||||
const res: AxiosResponse = await graph.query("queryEndpoints").params({
|
||||
serviceId,
|
||||
duration: this.durationTime,
|
||||
keyword: params.keyword,
|
||||
});
|
||||
if (!res.data.errors) {
|
||||
this.pods = res.data.data.pods || [];
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
async getService(serviceId: string) {
|
||||
if (!serviceId) {
|
||||
return;
|
||||
}
|
||||
const res: AxiosResponse = await graph.query("queryService").params({
|
||||
serviceId,
|
||||
});
|
||||
if (!res.data.errors) {
|
||||
this.currentService = res.data.data.service || {};
|
||||
this.services = [res.data.data.service];
|
||||
}
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async getInstance(instanceId: string) {
|
||||
if (!instanceId) {
|
||||
return;
|
||||
}
|
||||
const res: AxiosResponse = await graph.query("queryInstance").params({
|
||||
instanceId,
|
||||
});
|
||||
if (!res.data.errors) {
|
||||
this.currentPod = res.data.data.instance || null;
|
||||
}
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async getEndpoint(endpointId: string) {
|
||||
if (!endpointId) {
|
||||
return;
|
||||
}
|
||||
const res: AxiosResponse = await graph.query("queryEndpoint").params({
|
||||
endpointId,
|
||||
});
|
||||
if (!res.data.errors) {
|
||||
this.currentPod = res.data.data.endpoint || null;
|
||||
}
|
||||
|
||||
return res.data;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -15,20 +15,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
body {
|
||||
body {
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
color: #3d444f;
|
||||
font-family: 'Helvetica', 'Arial', 'Source Han Sans CN', 'Microsoft YaHei', 'sans-serif';
|
||||
font-family: Helvetica, Arial, "Source Han Sans CN", "Microsoft YaHei",
|
||||
sans-serif;
|
||||
text-rendering: optimizeLegibility;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
div,
|
||||
header,
|
||||
footer,
|
||||
@ -53,6 +55,7 @@ a,
|
||||
img {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
@ -60,41 +63,51 @@ button {
|
||||
font-size: 100%;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-width: 0;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
@ -102,76 +115,11 @@ blockquote {
|
||||
border-left: 4px solid #cacaca;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
code,
|
||||
pre {
|
||||
font-family: Consolas, Menlo, Courier, monospace;
|
||||
}
|
||||
/*webkit core*/
|
||||
.scroll_hide::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-button {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-track {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-track-piece {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-corner {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-resizer {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
/*o core*/
|
||||
.scroll_hide .-o-scrollbar {
|
||||
-moz-appearance: none !important;
|
||||
background: rgba(0, 255, 0, 0) !important;
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-button {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-track {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-track-piece {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-corner {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-resizer {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
/*IE10,IE11,IE12*/
|
||||
.scroll_hide {
|
||||
-ms-scroll-chaining: chained;
|
||||
-ms-overflow-style: none;
|
||||
-ms-content-zooming: zoom;
|
||||
-ms-scroll-rails: none;
|
||||
-ms-content-zoom-limit-min: 100%;
|
||||
-ms-content-zoom-limit-max: 500%;
|
||||
-ms-scroll-snap-points-x: snapList(100%, 200%, 300%, 400%, 500%);
|
||||
-ms-overflow-style: none;
|
||||
overflow: auto;
|
||||
}
|
||||
.scroll_bar_style::-webkit-scrollbar {
|
||||
width: 9px;
|
||||
height: 6px;
|
||||
}
|
||||
.scroll_bar_style::-webkit-scrollbar-track {
|
||||
background-color: #3d444f;
|
||||
}
|
||||
.scroll_bar_style::-webkit-scrollbar-thumb {
|
||||
border-radius: 5px;
|
||||
background: rgba(196, 200, 225, .2);
|
||||
}
|
||||
|
2
src/types/app.d.ts
vendored
2
src/types/app.d.ts
vendored
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export interface Option {
|
||||
value: string | number;
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
export interface Duration {
|
||||
|
@ -20,12 +20,12 @@ export interface LayoutConfig {
|
||||
w: number;
|
||||
h: number;
|
||||
i: string;
|
||||
widget?: WidgetConfig;
|
||||
graph?: GraphConfig;
|
||||
standard?: StandardConfig;
|
||||
metrics?: string[];
|
||||
type?: string;
|
||||
queryMetricType?: string;
|
||||
widget: WidgetConfig;
|
||||
graph: GraphConfig;
|
||||
standard: StandardConfig;
|
||||
metrics: string[];
|
||||
type: string;
|
||||
metricTypes: string[];
|
||||
children?: any;
|
||||
}
|
||||
|
||||
@ -45,9 +45,17 @@ export interface StandardConfig {
|
||||
divide?: string;
|
||||
milliseconds?: string;
|
||||
seconds?: string;
|
||||
maxItemNum?: number;
|
||||
}
|
||||
|
||||
export type GraphConfig = BarConfig | LineConfig | CardConfig | TableConfig;
|
||||
export type GraphConfig =
|
||||
| BarConfig
|
||||
| LineConfig
|
||||
| CardConfig
|
||||
| TableConfig
|
||||
| EndpointListConfig
|
||||
| ServiceListConfig
|
||||
| InstanceListConfig;
|
||||
export interface BarConfig {
|
||||
type?: string;
|
||||
showBackground?: boolean;
|
||||
@ -57,6 +65,8 @@ export interface LineConfig extends AreaConfig {
|
||||
smooth?: boolean;
|
||||
showSymbol?: boolean;
|
||||
step?: boolean;
|
||||
showXAxis?: boolean;
|
||||
showYAxis?: boolean;
|
||||
}
|
||||
|
||||
export interface AreaConfig {
|
||||
@ -67,7 +77,8 @@ export interface AreaConfig {
|
||||
export interface CardConfig {
|
||||
type?: string;
|
||||
fontSize?: number;
|
||||
showUint: boolean;
|
||||
showUint?: boolean;
|
||||
textAlign?: "center" | "right" | "left";
|
||||
}
|
||||
|
||||
export interface TableConfig {
|
||||
@ -81,3 +92,21 @@ export interface TopListConfig {
|
||||
type?: string;
|
||||
topN: number;
|
||||
}
|
||||
|
||||
export interface ServiceListConfig {
|
||||
type?: string;
|
||||
dashboardName: string;
|
||||
fontSize: number;
|
||||
}
|
||||
|
||||
export interface InstanceListConfig {
|
||||
type?: string;
|
||||
dashboardName: string;
|
||||
fontSize: number;
|
||||
}
|
||||
|
||||
export interface EndpointListConfig {
|
||||
type?: string;
|
||||
dashboardName: string;
|
||||
fontSize: number;
|
||||
}
|
||||
|
49
src/types/selector.d.ts
vendored
Normal file
49
src/types/selector.d.ts
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
export type Service = {
|
||||
id: string;
|
||||
label: string;
|
||||
value: string;
|
||||
layers: string[];
|
||||
normal: boolean;
|
||||
group: string;
|
||||
};
|
||||
|
||||
export type Instance = {
|
||||
value: string;
|
||||
label: string;
|
||||
layer: string;
|
||||
language: string;
|
||||
instanceUUID: string;
|
||||
attributes: { name: string; value: string }[];
|
||||
};
|
||||
|
||||
export type Endpoint = {
|
||||
id: string;
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type Service = {
|
||||
id: string;
|
||||
value: string;
|
||||
label: string;
|
||||
group: string;
|
||||
normal: boolean;
|
||||
layers: string[];
|
||||
shortName: string;
|
||||
};
|
@ -16,7 +16,7 @@ limitations under the License. -->
|
||||
<div class="about">{{ props.msg }}</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
msg: String,
|
||||
});
|
||||
|
@ -18,23 +18,25 @@ limitations under the License. -->
|
||||
<grid-layout />
|
||||
<el-dialog
|
||||
v-model="dashboardStore.showConfig"
|
||||
title="Edit Graph Options"
|
||||
:title="t('editGraph')"
|
||||
fullscreen
|
||||
:destroy-on-close="true"
|
||||
@closed="dashboardStore.setConfigPanel(false)"
|
||||
>
|
||||
<widget-config />
|
||||
<config-edit />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
import GridLayout from "./panel/Layout.vue";
|
||||
// import { LayoutConfig } from "@/types/dashboard";
|
||||
import Tool from "./panel/Tool.vue";
|
||||
import WidgetConfig from "./configuration/ConfigEdit.vue";
|
||||
import ConfigEdit from "./configuration/ConfigEdit.vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { t } = useI18n();
|
||||
// fetch layout data from serve side
|
||||
// const layout: any[] = [
|
||||
// { x: 0, y: 0, w: 4, h: 12, i: "0" },
|
||||
@ -54,6 +56,7 @@ const dashboardStore = useDashboardStore();
|
||||
// { x: 8, y: 27, w: 4, h: 15, i: "16" },
|
||||
// ];
|
||||
// dashboardStore.setLayout(layout);
|
||||
|
||||
function handleClick(e: any) {
|
||||
e.stopPropagation();
|
||||
if (e.target.className === "ds-main") {
|
||||
|
@ -26,8 +26,8 @@ limitations under the License. -->
|
||||
<div class="item">
|
||||
<div class="label">{{ t("layer") }}</div>
|
||||
<Selector
|
||||
:value="states.layer"
|
||||
:options="Options"
|
||||
v-model="states.selectedLayer"
|
||||
:options="states.layers"
|
||||
size="small"
|
||||
placeholder="Select a layer"
|
||||
@change="changeLayer"
|
||||
@ -37,7 +37,7 @@ limitations under the License. -->
|
||||
<div class="item">
|
||||
<div class="label">{{ t("entityType") }}</div>
|
||||
<Selector
|
||||
:value="states.entity"
|
||||
v-model="states.entity"
|
||||
:options="EntityType"
|
||||
size="small"
|
||||
placeholder="Select a entity"
|
||||
@ -53,28 +53,38 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from "vue";
|
||||
import { reactive, onBeforeMount } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import router from "@/router";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { EntityType, Options } from "./data";
|
||||
import uuid from "@/utils/uuid";
|
||||
import { EntityType } from "./data";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const { t } = useI18n();
|
||||
const selectorStore = useSelectorStore();
|
||||
const states = reactive({
|
||||
name: "",
|
||||
layer: Options[0].value,
|
||||
selectedLayer: "",
|
||||
entity: EntityType[0].value,
|
||||
layers: [],
|
||||
});
|
||||
const onCreate = () => {
|
||||
const id = uuid();
|
||||
const path = `/dashboard/edit/${states.layer}/${states.entity}/${id}`;
|
||||
const name = states.name.split(" ").join("-");
|
||||
const path = `/dashboard/${states.selectedLayer}/${states.entity}/${name}`;
|
||||
router.push(path);
|
||||
};
|
||||
selectorStore.fetchServices("general");
|
||||
onBeforeMount(async () => {
|
||||
const resp = await selectorStore.fetchLayers();
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
}
|
||||
states.selectedLayer = resp.data.layers[0];
|
||||
states.layers = resp.data.layers.map((d: string) => {
|
||||
return { label: d, value: d };
|
||||
});
|
||||
});
|
||||
function changeLayer(opt: { label: string; value: string }[]) {
|
||||
states.layer = opt[0].value;
|
||||
states.selectedLayer = opt[0].value;
|
||||
}
|
||||
function changeEntity(opt: { label: string; value: string }[]) {
|
||||
states.entity = opt[0].value;
|
||||
|
@ -14,23 +14,30 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="widget-config flex-v">
|
||||
<div class="graph">
|
||||
<div class="graph" v-loading="loading">
|
||||
<div class="header">
|
||||
<span>{{ states.widget.title }}</span>
|
||||
<div class="tips" v-show="states.widget.tips">
|
||||
<el-tooltip :content="states.widget.tips">
|
||||
<span>{{ dashboardStore.selectedGrid.widget.title }}</span>
|
||||
<div class="tips" v-show="dashboardStore.selectedGrid.widget.tips">
|
||||
<el-tooltip :content="dashboardStore.selectedGrid.widget.tips">
|
||||
<Icon iconName="info_outline" size="sm" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="render-chart">
|
||||
<component
|
||||
:is="states.graph.type"
|
||||
:is="dashboardStore.selectedGrid.graph.type"
|
||||
:intervalTime="appStoreWithOut.intervalTime"
|
||||
:data="states.source"
|
||||
:config="states.graph"
|
||||
:config="{
|
||||
...dashboardStore.selectedGrid.graph,
|
||||
i: dashboardStore.selectedGrid.i,
|
||||
metrics: dashboardStore.selectedGrid.metrics,
|
||||
metricTypes: dashboardStore.selectedGrid.metricTypes,
|
||||
}"
|
||||
/>
|
||||
<div v-show="!states.graph.type" class="no-data">{{ t("noData") }}</div>
|
||||
<div v-show="!dashboardStore.selectedGrid.graph.type" class="no-data">
|
||||
{{ t("noData") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse" :style="{ height: configHeight + 'px' }">
|
||||
@ -38,59 +45,17 @@ limitations under the License. -->
|
||||
v-model="states.activeNames"
|
||||
:style="{ '--el-collapse-header-font-size': '15px' }"
|
||||
>
|
||||
<el-collapse-item :title="t('metricName')" name="1">
|
||||
<div>
|
||||
<Selector
|
||||
:value="states.metrics"
|
||||
:options="metricOpts"
|
||||
:multiple="true"
|
||||
size="mini"
|
||||
placeholder="Select a metric"
|
||||
@change="changeMetrics"
|
||||
class="selectors"
|
||||
/>
|
||||
<Selector
|
||||
v-if="states.valueType"
|
||||
:value="states.valueType"
|
||||
:options="states.valueTypes"
|
||||
size="mini"
|
||||
placeholder="Select a metric"
|
||||
@change="changeValueType"
|
||||
class="selectors"
|
||||
v-loading="loading"
|
||||
/>
|
||||
</div>
|
||||
<el-collapse-item :title="t('selectVisualization')" name="1">
|
||||
<MetricOptions @update="getSource" @loading="setLoading" />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="t('selectVisualization')" name="2">
|
||||
<div class="chart-types">
|
||||
<span
|
||||
v-for="(type, index) in ChartTypes"
|
||||
:key="index"
|
||||
@click="changeChartType(type)"
|
||||
:class="{ active: type.value === states.graph.type }"
|
||||
>
|
||||
{{ type.label }}
|
||||
</span>
|
||||
</div>
|
||||
<el-collapse-item :title="t('graphStyles')" name="2">
|
||||
<component :is="`${dashboardStore.selectedGrid.graph.type}Config`" />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="t('graphStyles')" name="3">
|
||||
<component
|
||||
:is="`${states.graph.type}Config`"
|
||||
:config="states.graph"
|
||||
@update="updateGraphOptions"
|
||||
/>
|
||||
<el-collapse-item :title="t('widgetOptions')" name="3">
|
||||
<WidgetOptions />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="t('widgetOptions')" name="4">
|
||||
<WidgetOptions
|
||||
:config="states.widget"
|
||||
@update="updateWidgetOptions"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="t('standardOptions')" name="5">
|
||||
<StandardOptions
|
||||
:config="states.standard"
|
||||
@update="updateStandardOptions"
|
||||
/>
|
||||
<el-collapse-item :title="t('standardOptions')" name="4">
|
||||
<StandardOptions />
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
@ -109,19 +74,12 @@ import { reactive, defineComponent, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { ElMessage } from "element-plus";
|
||||
import {
|
||||
ValuesTypes,
|
||||
MetricQueryTypes,
|
||||
ChartTypes,
|
||||
DefaultGraphConfig,
|
||||
} from "../data";
|
||||
import { Option } from "@/types/app";
|
||||
import { WidgetConfig, GraphConfig, StandardConfig } from "@/types/dashboard";
|
||||
import graphs from "../graphs";
|
||||
import configs from "./graph-styles";
|
||||
import WidgetOptions from "./WidgetOptions.vue";
|
||||
import StandardOptions from "./StandardOptions.vue";
|
||||
import MetricOptions from "./MetricOptions.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ConfigEdit",
|
||||
@ -130,166 +88,49 @@ export default defineComponent({
|
||||
...configs,
|
||||
WidgetOptions,
|
||||
StandardOptions,
|
||||
MetricOptions,
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(false);
|
||||
const configHeight = document.documentElement.clientHeight - 520;
|
||||
const { t } = useI18n();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const appStoreWithOut = useAppStoreWithOut();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const loading = ref<boolean>(false);
|
||||
const states = reactive<{
|
||||
metrics: string[];
|
||||
valueTypes: Option[];
|
||||
valueType: string;
|
||||
metricQueryType: string;
|
||||
activeNames: string;
|
||||
source: any;
|
||||
index: string;
|
||||
graph: GraphConfig;
|
||||
widget: WidgetConfig | any;
|
||||
standard: StandardConfig;
|
||||
visType: Option[];
|
||||
}>({
|
||||
metrics: selectedGrid.metrics || [],
|
||||
valueTypes: [],
|
||||
valueType: "",
|
||||
metricQueryType: "",
|
||||
activeNames: "1",
|
||||
source: {},
|
||||
index: selectedGrid.i,
|
||||
graph: selectedGrid.graph,
|
||||
widget: selectedGrid.widget,
|
||||
standard: selectedGrid.standard,
|
||||
index: dashboardStore.selectedGrid.i,
|
||||
visType: [],
|
||||
});
|
||||
if (states.metrics[0]) {
|
||||
queryMetricType(states.metrics[0]);
|
||||
|
||||
function getSource(source: unknown) {
|
||||
states.source = source;
|
||||
}
|
||||
|
||||
async function changeMetrics(arr: Option[]) {
|
||||
if (!arr.length) {
|
||||
states.valueTypes = [];
|
||||
states.valueType = "";
|
||||
return;
|
||||
}
|
||||
states.metrics = arr.map((d: Option) => String(d.value));
|
||||
if (arr[0].value) {
|
||||
queryMetricType(String(arr[0].value));
|
||||
}
|
||||
function setLoading(load: boolean) {
|
||||
loading.value = load;
|
||||
}
|
||||
|
||||
async function queryMetricType(metric: string) {
|
||||
loading.value = true;
|
||||
const resp = await dashboardStore.fetchMetricType(metric);
|
||||
loading.value = false;
|
||||
if (resp.error) {
|
||||
ElMessage.error(resp.data.error);
|
||||
return;
|
||||
}
|
||||
const { typeOfMetrics } = resp.data;
|
||||
states.valueTypes = ValuesTypes[typeOfMetrics];
|
||||
states.valueType = ValuesTypes[typeOfMetrics][0].value;
|
||||
queryMetrics();
|
||||
}
|
||||
|
||||
function changeValueType(val: Option[]) {
|
||||
states.valueType = String(val[0].value);
|
||||
states.metricQueryType = (MetricQueryTypes as any)[states.valueType];
|
||||
queryMetrics();
|
||||
}
|
||||
|
||||
function changeChartType(item: Option) {
|
||||
states.graph = {
|
||||
...DefaultGraphConfig[item.value],
|
||||
};
|
||||
}
|
||||
|
||||
const metricOpts = [
|
||||
{ value: "service_apdex", label: "service_apdex" },
|
||||
{ value: "service_sla", label: "service_sla" },
|
||||
{ value: "service_cpm", label: "service_cpm" },
|
||||
{ value: "service_resp_time", label: "service_resp_time" },
|
||||
{ value: "service_percentile", label: "service_percentile" },
|
||||
{
|
||||
value: "service_mq_consume_latency",
|
||||
label: "service_mq_consume_latency",
|
||||
},
|
||||
{ value: "service_mq_consume_count", label: "service_mq_consume_count" },
|
||||
];
|
||||
const configHeight = document.documentElement.clientHeight - 520;
|
||||
|
||||
function updateWidgetOptions(param: { [key: string]: unknown }) {
|
||||
states.widget = {
|
||||
...states.widget,
|
||||
...param,
|
||||
};
|
||||
}
|
||||
|
||||
function updateGraphOptions(param: { [key: string]: unknown }) {
|
||||
states.graph = {
|
||||
...states.graph,
|
||||
...param,
|
||||
};
|
||||
}
|
||||
|
||||
function updateStandardOptions(param: { [key: string]: unknown }) {
|
||||
states.standard = {
|
||||
...states.standard,
|
||||
...param,
|
||||
};
|
||||
}
|
||||
|
||||
async function queryMetrics() {
|
||||
const json = await dashboardStore.fetchMetricValue(
|
||||
dashboardStore.selectedGrid
|
||||
);
|
||||
if (!json) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (json.error) {
|
||||
return;
|
||||
}
|
||||
const metricVal = json.data.readMetricsValues.values.values.map(
|
||||
(d: { value: number }) => d.value + 1
|
||||
);
|
||||
const m = states.metrics[0];
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
states.source = {
|
||||
[m]: metricVal,
|
||||
};
|
||||
}
|
||||
|
||||
queryMetrics();
|
||||
|
||||
function applyConfig() {
|
||||
const opts = {
|
||||
...dashboardStore.selectedGrid,
|
||||
metrics: states.metrics,
|
||||
queryMetricType: states.valueType,
|
||||
widget: states.widget,
|
||||
graph: states.graph,
|
||||
standard: states.standard,
|
||||
};
|
||||
dashboardStore.setConfigs(opts);
|
||||
dashboardStore.setConfigs(dashboardStore.selectedGrid);
|
||||
dashboardStore.setConfigPanel(false);
|
||||
}
|
||||
|
||||
return {
|
||||
states,
|
||||
changeChartType,
|
||||
changeValueType,
|
||||
changeMetrics,
|
||||
loading,
|
||||
t,
|
||||
appStoreWithOut,
|
||||
ChartTypes,
|
||||
metricOpts,
|
||||
updateWidgetOptions,
|
||||
configHeight,
|
||||
updateGraphOptions,
|
||||
updateStandardOptions,
|
||||
dashboardStore,
|
||||
applyConfig,
|
||||
loading,
|
||||
getSource,
|
||||
setLoading,
|
||||
};
|
||||
},
|
||||
});
|
||||
@ -326,7 +167,7 @@ export default defineComponent({
|
||||
|
||||
.render-chart {
|
||||
padding: 5px;
|
||||
height: 350px;
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@ -343,30 +184,10 @@ export default defineComponent({
|
||||
min-width: 1280px;
|
||||
}
|
||||
|
||||
.chart-types {
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
border-right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span:nth-last-child(1) {
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.no-data {
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
line-height: 350px;
|
||||
}
|
||||
|
||||
span.active {
|
||||
background-color: #409eff;
|
||||
color: #fff;
|
||||
line-height: 400px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
@ -384,4 +205,8 @@ span.active {
|
||||
margin-top: 10px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.ds-name {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
329
src/views/dashboard/configuration/MetricOptions.vue
Normal file
329
src/views/dashboard/configuration/MetricOptions.vue
Normal file
@ -0,0 +1,329 @@
|
||||
<!-- 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 v-show="states.isTable" class="ds-name">
|
||||
<div>{{ t("dashboards") }}</div>
|
||||
<el-input
|
||||
v-model="states.dashboardName"
|
||||
placeholder="Please input dashboard name"
|
||||
@change="changeDashboard"
|
||||
class="selectors"
|
||||
/>
|
||||
</div>
|
||||
<div>{{ t("metrics") }}</div>
|
||||
<div
|
||||
v-for="(metric, index) in states.metrics"
|
||||
:key="index"
|
||||
class="metric-item"
|
||||
>
|
||||
<Selector
|
||||
:value="metric"
|
||||
:options="states.metricList"
|
||||
size="mini"
|
||||
placeholder="Select a metric"
|
||||
@change="changeMetrics(index, $event)"
|
||||
class="selectors"
|
||||
/>
|
||||
<Selector
|
||||
:value="states.metricTypes[index]"
|
||||
:options="states.metricTypeList[index]"
|
||||
size="mini"
|
||||
:disabled="
|
||||
dashboardStore.selectedGrid.graph.type && !states.isTable && index !== 0
|
||||
"
|
||||
@change="changeMetricType(index, $event)"
|
||||
class="selectors"
|
||||
/>
|
||||
<span
|
||||
v-show="states.isTable || states.metricTypes[0] === 'readMetricsValues'"
|
||||
>
|
||||
<Icon
|
||||
class="cp mr-5"
|
||||
v-show="
|
||||
index === states.metrics.length - 1 && states.metrics.length < 5
|
||||
"
|
||||
iconName="add_circle_outlinecontrol_point"
|
||||
size="middle"
|
||||
@click="addMetric"
|
||||
/>
|
||||
<Icon
|
||||
class="cp"
|
||||
v-show="states.metrics.length > 1"
|
||||
iconName="remove_circle_outline"
|
||||
size="middle"
|
||||
@click="deleteMetric(index)"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div>{{ t("visualization") }}</div>
|
||||
<div class="chart-types">
|
||||
<span
|
||||
v-for="(type, index) in states.visTypes"
|
||||
:key="index"
|
||||
@click="changeChartType(type)"
|
||||
:class="{
|
||||
active: type.value === dashboardStore.selectedGrid.graph.type,
|
||||
}"
|
||||
>
|
||||
{{ type.label }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from "vue";
|
||||
import { Option } from "@/types/app";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import {
|
||||
MetricTypes,
|
||||
TableChartTypes,
|
||||
MetricCatalog,
|
||||
DefaultGraphConfig,
|
||||
EntityType,
|
||||
ChartTypes,
|
||||
PodsChartTypes,
|
||||
TableEntity,
|
||||
} from "../data";
|
||||
import { ElMessage } from "element-plus";
|
||||
import Icon from "@/components/Icon.vue";
|
||||
import { useQueryProcessor, useSourceProcessor } from "@/hooks/useProcessor";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
/*global defineEmits */
|
||||
const { t } = useI18n();
|
||||
const emit = defineEmits(["update", "loading"]);
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { metrics, metricTypes, graph } = dashboardStore.selectedGrid;
|
||||
const states = reactive<{
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
metricTypeList: Option[][];
|
||||
visTypes: Option[];
|
||||
isTable: boolean;
|
||||
metricList: (Option & { type: string })[];
|
||||
dashboardName: string;
|
||||
}>({
|
||||
metrics: metrics && metrics.length ? metrics : [""],
|
||||
metricTypes: metricTypes && metricTypes.length ? metricTypes : [""],
|
||||
metricTypeList: [],
|
||||
visTypes: [],
|
||||
isTable: false,
|
||||
metricList: [],
|
||||
dashboardName: graph.dashboardName,
|
||||
});
|
||||
|
||||
states.isTable = TableChartTypes.includes(graph.type);
|
||||
states.visTypes = setVisTypes();
|
||||
setMetricType();
|
||||
|
||||
async function setMetricType(catalog?: string) {
|
||||
if (states.isTable) {
|
||||
catalog = catalog || TableEntity[graph.type];
|
||||
} else {
|
||||
catalog = catalog || dashboardStore.entity;
|
||||
}
|
||||
const json = await dashboardStore.fetchMetricList();
|
||||
if (json.errors) {
|
||||
ElMessage.error(json.errors);
|
||||
return;
|
||||
}
|
||||
states.metricList = (json.data.metrics || []).filter(
|
||||
(d: { catalog: string }) => catalog === (MetricCatalog as any)[d.catalog]
|
||||
);
|
||||
const metrics: any = states.metricList.filter(
|
||||
(d: { value: string; type: string }) => {
|
||||
const metric = states.metrics.filter((m: string) => m === d.value)[0];
|
||||
if (metric) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
);
|
||||
for (const metric of metrics) {
|
||||
states.metricTypeList.push(MetricTypes[metric.type]);
|
||||
}
|
||||
if (states.metrics && states.metrics[0]) {
|
||||
queryMetrics();
|
||||
}
|
||||
}
|
||||
|
||||
function setVisTypes() {
|
||||
let graphs = [];
|
||||
if (dashboardStore.entity === EntityType[0].value) {
|
||||
graphs = ChartTypes.filter((d: Option) => d.value !== ChartTypes[7].value);
|
||||
} else if (dashboardStore.entity === EntityType[1].value) {
|
||||
graphs = ChartTypes.filter(
|
||||
(d: Option) => !PodsChartTypes.includes(d.value)
|
||||
);
|
||||
} else {
|
||||
graphs = ChartTypes.filter(
|
||||
(d: Option) => !TableChartTypes.includes(d.value)
|
||||
);
|
||||
}
|
||||
|
||||
return graphs;
|
||||
}
|
||||
|
||||
function changeChartType(item: Option) {
|
||||
const graph = DefaultGraphConfig[item.value];
|
||||
states.isTable = TableChartTypes.includes(graph.type);
|
||||
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
|
||||
states.isTable = TableChartTypes.includes(graph.type);
|
||||
if (states.isTable) {
|
||||
dashboardStore.selectWidget({
|
||||
...dashboardStore.selectedGrid,
|
||||
metrics: [""],
|
||||
metricTypes: [""],
|
||||
});
|
||||
states.metrics = [""];
|
||||
states.metricTypes = [""];
|
||||
}
|
||||
const catalog: { [key: string]: string } = {
|
||||
InstanceList: EntityType[3].value,
|
||||
EndpointList: EntityType[2].value,
|
||||
ServiceList: EntityType[0].value,
|
||||
};
|
||||
if (catalog[graph.type]) {
|
||||
setMetricType(catalog[graph.type]);
|
||||
}
|
||||
}
|
||||
|
||||
function changeMetrics(index: number, arr: (Option & { type: string })[]) {
|
||||
if (!arr.length) {
|
||||
states.metricTypeList = [];
|
||||
states.metricTypes = [];
|
||||
dashboardStore.selectWidget({
|
||||
...dashboardStore.selectedGrid,
|
||||
...{ metricTypes: states.metricTypes, metrics: states.metrics },
|
||||
});
|
||||
return;
|
||||
}
|
||||
states.metrics[index] = arr[0].value;
|
||||
const typeOfMetrics = arr[0].type;
|
||||
|
||||
states.metricTypeList[index] = MetricTypes[typeOfMetrics];
|
||||
states.metricTypes[index] = MetricTypes[typeOfMetrics][0].value;
|
||||
dashboardStore.selectWidget({
|
||||
...dashboardStore.selectedGrid,
|
||||
...{ metricTypes: states.metricTypes, metrics: states.metrics },
|
||||
});
|
||||
if (states.isTable) {
|
||||
return;
|
||||
}
|
||||
queryMetrics();
|
||||
}
|
||||
|
||||
function changeMetricType(index: number, opt: Option[]) {
|
||||
const metric =
|
||||
states.metricList.filter(
|
||||
(d: Option) => states.metrics[index] === d.value
|
||||
)[0] || {};
|
||||
if (states.isTable) {
|
||||
states.metricTypes[index] = opt[0].value;
|
||||
states.metricTypeList[index] = (MetricTypes as any)[metric.type];
|
||||
} else {
|
||||
states.metricTypes = states.metricTypes.map((d: string) => {
|
||||
d = opt[0].value;
|
||||
return d;
|
||||
});
|
||||
states.metricTypeList = states.metricTypeList.map((d: Option[]) => {
|
||||
d = (MetricTypes as any)[metric.type];
|
||||
|
||||
return d;
|
||||
});
|
||||
}
|
||||
dashboardStore.selectWidget({
|
||||
...dashboardStore.selectedGrid,
|
||||
...{ metricTypes: states.metricTypes },
|
||||
});
|
||||
if (states.isTable) {
|
||||
return;
|
||||
}
|
||||
queryMetrics();
|
||||
}
|
||||
async function queryMetrics() {
|
||||
const params = useQueryProcessor(states);
|
||||
if (!params) {
|
||||
emit("update", {});
|
||||
return;
|
||||
}
|
||||
|
||||
emit("loading", true);
|
||||
const json = await dashboardStore.fetchMetricValue(params);
|
||||
emit("loading", false);
|
||||
if (json.errors) {
|
||||
ElMessage.error(json.errors);
|
||||
return;
|
||||
}
|
||||
const source = useSourceProcessor(json, states);
|
||||
emit("update", source);
|
||||
}
|
||||
|
||||
function changeDashboard() {
|
||||
const graph = {
|
||||
...dashboardStore.selectedGrid.graph,
|
||||
dashboardName: states.dashboardName,
|
||||
};
|
||||
dashboardStore.selectWidget({
|
||||
...dashboardStore.selectedGrid,
|
||||
graph,
|
||||
});
|
||||
}
|
||||
function addMetric() {
|
||||
states.metrics.push("");
|
||||
if (!states.isTable) {
|
||||
states.metricTypes.push(states.metricTypes[0]);
|
||||
states.metricTypeList.push(states.metricTypeList[0]);
|
||||
return;
|
||||
}
|
||||
states.metricTypes.push("");
|
||||
}
|
||||
function deleteMetric(index: number) {
|
||||
states.metrics.splice(index, 1);
|
||||
states.metricTypes.splice(index, 1);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ds-name {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.selectors {
|
||||
width: 500px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.chart-types {
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
border-right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span:nth-last-child(1) {
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
span.active {
|
||||
background-color: #409eff;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
@ -116,22 +116,16 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, defineProps, defineEmits } from "vue";
|
||||
import { reactive } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { SortOrder } from "../data";
|
||||
import { StandardConfig } from "@/types/dashboard";
|
||||
import type { PropType } from "vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<StandardConfig>,
|
||||
default: () => ({ unit: "", sortOrder: "DES" }),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const { t } = useI18n();
|
||||
const state = reactive({
|
||||
unit: props.config.unit,
|
||||
unit: selectedGrid.standard.unit,
|
||||
max: "",
|
||||
min: "",
|
||||
plus: "",
|
||||
@ -140,11 +134,15 @@ const state = reactive({
|
||||
divide: "",
|
||||
milliseconds: "",
|
||||
seconds: "",
|
||||
sortOrder: props.config.sortOrder,
|
||||
sortOrder: selectedGrid.standard.sortOrder,
|
||||
});
|
||||
|
||||
function changeStandardOpt(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
const standard = {
|
||||
...selectedGrid.standard,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...selectedGrid, standard });
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -35,24 +35,22 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, defineEmits, defineProps } from "vue";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { WidgetConfig } from "@/types/dashboard";
|
||||
import type { PropType } from "vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<WidgetConfig>,
|
||||
default: () => ({ title: "", tooltips: "" }),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const { t } = useI18n();
|
||||
const title = ref<string>(props.config.title || "");
|
||||
const tips = ref<string>(props.config.tips || "");
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const title = ref<string>(selectedGrid.widget.title || "");
|
||||
const tips = ref<string>(selectedGrid.widget.tips || "");
|
||||
|
||||
function updateWidgetConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
const widget = {
|
||||
...selectedGrid.widget,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...selectedGrid, widget });
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -28,24 +28,22 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { AreaConfig } from "@/types/dashboard";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const { t } = useI18n();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<AreaConfig>,
|
||||
default: () => ({ opacity: 0.4 }),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const opacity = ref(props.config.opacity);
|
||||
const opacity = ref(selectedGrid.graph.opacity);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
const graph = {
|
||||
...selectedGrid.graph,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -24,24 +24,21 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { BarConfig } from "@/types/dashboard";
|
||||
import { ref } from "vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<BarConfig>,
|
||||
default: () => ({ showBackground: true, barWidth: 30 }),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const showBackground = ref(props.config.showBackground || false);
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const showBackground = ref(selectedGrid.graph.showBackground || false);
|
||||
|
||||
function changeConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
const graph = {
|
||||
...selectedGrid.graph,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -20,32 +20,29 @@ limitations under the License. -->
|
||||
v-model="fontSize"
|
||||
show-input
|
||||
input-size="small"
|
||||
:min="0.1"
|
||||
:max="1"
|
||||
:step="0.1"
|
||||
:min="10"
|
||||
:max="20"
|
||||
:step="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";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<CardConfig>,
|
||||
default: () => ({ fontSize: 12 }),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const fontSize = ref(props.config.fontSize);
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const fontSize = ref(selectedGrid.graph.fontSize);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
const graph = {
|
||||
...selectedGrid.graph,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -0,0 +1,61 @@
|
||||
<!-- 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 dashboardStore = useDashboardStore();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const { t } = useI18n();
|
||||
|
||||
const fontSize = ref(selectedGrid.graph.fontSize);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
const graph = {
|
||||
...selectedGrid.graph,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...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>
|
@ -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">{{ 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 { selectedGrid } = dashboardStore;
|
||||
const fontSize = ref(selectedGrid.graph.fontSize);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
const graph = {
|
||||
...selectedGrid.graph,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...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>
|
@ -42,25 +42,23 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { LineConfig } from "@/types/dashboard";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<LineConfig>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const smooth = ref(props.config.smooth);
|
||||
const showSymbol = ref(props.config.showSymbol);
|
||||
const step = ref(props.config.step);
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const smooth = ref(selectedGrid.graph.smooth);
|
||||
const showSymbol = ref(selectedGrid.graph.showSymbol);
|
||||
const step = ref(selectedGrid.graph.step);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
const graph = {
|
||||
...selectedGrid.graph,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -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">{{ 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 { selectedGrid } = dashboardStore;
|
||||
const fontSize = ref(selectedGrid.graph.fontSize);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
const graph = {
|
||||
...selectedGrid.graph,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...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>
|
@ -44,29 +44,23 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { TableConfig } from "@/types/dashboard";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
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);
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const showTableValues = ref(selectedGrid.graph.showTableValues);
|
||||
const tableHeaderCol1 = ref(selectedGrid.graph.tableHeaderCol1);
|
||||
const tableHeaderCol2 = ref(selectedGrid.graph.tableHeaderCol2);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
const graph = {
|
||||
...selectedGrid.graph,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -28,25 +28,21 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { TopListConfig } from "@/types/dashboard";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
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);
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const topN = ref(selectedGrid.graph.topN);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
const graph = {
|
||||
...selectedGrid.graph,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -18,9 +18,21 @@
|
||||
import AreaConfig from "./Area.vue";
|
||||
import LineConfig from "./Line.vue";
|
||||
import BarConfig from "./Bar.vue";
|
||||
import TableConfig from "./Table.vue";
|
||||
import CardConfig from "./Card.vue";
|
||||
import InstanceListConfig from "./InstanceList.vue";
|
||||
import EndpointListConfig from "./EndpointList.vue";
|
||||
import ServiceListConfig from "./ServiceList.vue";
|
||||
import TopListConfig from "./TopList.vue";
|
||||
|
||||
export default {
|
||||
AreaConfig,
|
||||
LineConfig,
|
||||
BarConfig,
|
||||
InstanceListConfig,
|
||||
EndpointListConfig,
|
||||
ServiceListConfig,
|
||||
TableConfig,
|
||||
CardConfig,
|
||||
TopListConfig,
|
||||
};
|
||||
|
@ -84,12 +84,12 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, reactive, ref, watch } from "vue";
|
||||
import { ref, watch, reactive } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import Widget from "./Widget.vue";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<LayoutConfig>,
|
||||
@ -150,9 +150,12 @@ function clickTabGrid(e: Event, item: LayoutConfig) {
|
||||
);
|
||||
}
|
||||
document.body.addEventListener("click", handleClick, false);
|
||||
|
||||
const children = ref(
|
||||
dashboardStore.layout[props.data.i].children[activeTabIndex.value].children
|
||||
);
|
||||
watch(
|
||||
() =>
|
||||
dashboardStore.layout[props.data.i].children[activeTabIndex.value].children,
|
||||
() => children.value,
|
||||
(data) => {
|
||||
state.layout = data;
|
||||
}
|
||||
|
@ -45,9 +45,14 @@ limitations under the License. -->
|
||||
<div class="body" v-if="data.graph?.type" v-loading="loading">
|
||||
<component
|
||||
:is="data.graph.type"
|
||||
:intervalTime="appStoreWithOut.intervalTime"
|
||||
:intervalTime="appStore.intervalTime"
|
||||
:data="state.source"
|
||||
:config="data.graph"
|
||||
:config="{
|
||||
...data.graph,
|
||||
metrics: data.metrics,
|
||||
metricTypes: data.metricTypes,
|
||||
i: data.i,
|
||||
}"
|
||||
:standard="data.standard"
|
||||
/>
|
||||
</div>
|
||||
@ -60,9 +65,11 @@ import type { PropType } from "vue";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import graphs from "../graphs";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useQueryProcessor, useSourceProcessor } from "@/hooks/useProcessor";
|
||||
import { EntityType, TableChartTypes } from "../data";
|
||||
|
||||
const props = {
|
||||
data: {
|
||||
@ -78,34 +85,27 @@ export default defineComponent({
|
||||
setup(props) {
|
||||
const { t } = useI18n();
|
||||
const loading = ref<boolean>(false);
|
||||
const state = reactive({
|
||||
const state = reactive<{ source: { [key: string]: unknown } }>({
|
||||
source: {},
|
||||
});
|
||||
const { data } = toRefs(props);
|
||||
const appStoreWithOut = useAppStoreWithOut();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const dashboardStore = useDashboardStore();
|
||||
queryMetrics();
|
||||
const selectorStore = useSelectorStore();
|
||||
|
||||
async function queryMetrics() {
|
||||
const params = await useQueryProcessor(props.data);
|
||||
if (!params) {
|
||||
state.source = {};
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
const json = await dashboardStore.fetchMetricValue(props.data);
|
||||
const json = await dashboardStore.fetchMetricValue(params);
|
||||
loading.value = false;
|
||||
if (!json) {
|
||||
return;
|
||||
}
|
||||
if (json.error) {
|
||||
ElMessage.error(json.error);
|
||||
return;
|
||||
}
|
||||
const metricVal = json.data.readMetricsValues.values.values.map(
|
||||
(d: any) => d.value
|
||||
);
|
||||
const m = props.data.metrics && props.data.metrics[0];
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
state.source = {
|
||||
[m]: metricVal,
|
||||
};
|
||||
state.source = useSourceProcessor(json, props.data);
|
||||
}
|
||||
|
||||
function removeWidget() {
|
||||
@ -121,17 +121,41 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
watch(
|
||||
() => [props.data.queryMetricType, props.data.metrics],
|
||||
(data, old) => {
|
||||
if (data[0] === old[0] && data[1] === old[1]) {
|
||||
() => [props.data.metricTypes, props.data.metrics],
|
||||
() => {
|
||||
if (props.data.i !== dashboardStore.selectedGrid.i) {
|
||||
return;
|
||||
}
|
||||
if (TableChartTypes.includes(dashboardStore.selectedGrid.graph.type)) {
|
||||
return;
|
||||
}
|
||||
queryMetrics();
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => [selectorStore.currentService],
|
||||
() => {
|
||||
if (dashboardStore.entity === EntityType[0].value) {
|
||||
queryMetrics();
|
||||
}
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => [selectorStore.currentPod],
|
||||
() => {
|
||||
if (
|
||||
dashboardStore.entity === EntityType[0].value ||
|
||||
dashboardStore.entity === EntityType[1].value
|
||||
) {
|
||||
return;
|
||||
}
|
||||
queryMetrics();
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
state,
|
||||
appStoreWithOut,
|
||||
appStore,
|
||||
removeWidget,
|
||||
editConfig,
|
||||
data,
|
||||
|
@ -14,18 +14,36 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const PodsChartTypes = ["EndpointList", "InstanceList"];
|
||||
|
||||
export const TableChartTypes = ["EndpointList", "InstanceList", "ServiceList"];
|
||||
|
||||
export const ChartTypes = [
|
||||
{ label: "Bar", value: "Bar" },
|
||||
{ label: "Line", value: "Line" },
|
||||
{ label: "Area", value: "Area" },
|
||||
{ label: "Heatmap", value: "Heatmap" },
|
||||
{ label: "Pie", value: "Pie" },
|
||||
// { label: "Pie", value: "Pie" },
|
||||
{ label: "Card", value: "Card" },
|
||||
{ label: "Top List", value: "TopList" },
|
||||
{ label: "Table", value: "Table" },
|
||||
{ label: "Heatmap", value: "Heatmap" },
|
||||
{ label: "Service List", value: "ServiceList" },
|
||||
{ label: "Endpoint List", value: "EndpointList" },
|
||||
{ label: "Instance List", value: "InstanceList" },
|
||||
];
|
||||
export const MetricChartType: any = {
|
||||
readMetricsValue: [{ label: "Card", value: "Card" }],
|
||||
readMetricsValues: [
|
||||
{ label: "Bar", value: "Bar" },
|
||||
{ label: "Line", value: "Line" },
|
||||
{ label: "Area", value: "Area" },
|
||||
],
|
||||
sortMetrics: [{ label: "Top List", value: "TopList" }],
|
||||
readLabeledMetricsValues: [{ label: "Line", value: "Line" }],
|
||||
readHeatMap: [{ label: "Heatmap", value: "Heatmap" }],
|
||||
readSampledRecords: [{ label: "Top List", value: "TopList" }],
|
||||
};
|
||||
export const DefaultGraphConfig: { [key: string]: any } = {
|
||||
Bar: {
|
||||
type: "Bar",
|
||||
@ -36,36 +54,47 @@ export const DefaultGraphConfig: { [key: string]: any } = {
|
||||
step: false,
|
||||
smooth: false,
|
||||
showSymbol: false,
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
},
|
||||
Area: {
|
||||
type: "Area",
|
||||
opacity: 0.4,
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
},
|
||||
Card: {
|
||||
type: "Card",
|
||||
fontSize: 14,
|
||||
textAlign: "center",
|
||||
showUint: true,
|
||||
},
|
||||
Table: {
|
||||
type: "Card",
|
||||
type: "Table",
|
||||
showTableValues: true,
|
||||
tableHeaderCol1: "",
|
||||
tableHeaderCol2: "",
|
||||
},
|
||||
TopList: {
|
||||
type: "TopList",
|
||||
topN: 10,
|
||||
},
|
||||
InstanceList: {
|
||||
type: "InstanceList",
|
||||
dashboardName: "",
|
||||
fontSize: 12,
|
||||
},
|
||||
EndpointList: {
|
||||
type: "EndpointList",
|
||||
dashboardName: "",
|
||||
fontSize: 12,
|
||||
},
|
||||
ServiceList: {
|
||||
type: "ServiceList",
|
||||
dashboardName: "",
|
||||
fontSize: 12,
|
||||
},
|
||||
};
|
||||
|
||||
export enum MetricQueryTypes {
|
||||
ReadMetricsValue = "readMetricsValue",
|
||||
ReadMetricsValues = "readMetricsValues",
|
||||
SortMetrics = "sortMetrics",
|
||||
ReadLabeledMetricsValues = "readLabeledMetricsValues",
|
||||
READHEATMAP = "readHeatMap",
|
||||
ReadSampledRecords = "readSampledRecords",
|
||||
}
|
||||
export enum MetricsType {
|
||||
UNKNOWN = "UNKNOWN",
|
||||
REGULAR_VALUE = "REGULAR_VALUE",
|
||||
@ -73,7 +102,7 @@ export enum MetricsType {
|
||||
HEATMAP = "HEATMAP",
|
||||
SAMPLED_RECORD = "SAMPLED_RECORD",
|
||||
}
|
||||
export const ValuesTypes: {
|
||||
export const MetricTypes: {
|
||||
[key: string]: Array<{ label: string; value: string }>;
|
||||
} = {
|
||||
REGULAR_VALUE: [
|
||||
@ -97,55 +126,40 @@ export const ValuesTypes: {
|
||||
{ label: "get sorted topN values", value: "readSampledRecords" },
|
||||
],
|
||||
};
|
||||
export const MetricChartType: { [key: string]: string } = {
|
||||
readMetricsValue: "ChartNum",
|
||||
readMetricsValues: "ChartLine",
|
||||
sortMetrics: "ChartSlow",
|
||||
readLabeledMetricsValues: "ChartLine",
|
||||
readHeatMap: "ChartHeatmap",
|
||||
readSampledRecords: "ChartSlow",
|
||||
};
|
||||
export const CalculationType = [
|
||||
{ label: "Plus", value: "+" },
|
||||
{ label: "Minus", value: "-" },
|
||||
{ label: "Multiplication", value: "*" },
|
||||
{ label: "Division", value: "/" },
|
||||
{ label: "Convert Unix Timestamp(milliseconds)", value: "milliseconds" },
|
||||
{ label: "Convert Unix Timestamp(seconds)", value: "seconds" },
|
||||
];
|
||||
export const ReadValueChartType = [
|
||||
{ value: "ChartNum", label: "Digital Card" },
|
||||
{ value: "ChartSlow", label: "Slow Chart" },
|
||||
];
|
||||
|
||||
export const MaxItemNum = 10;
|
||||
|
||||
export enum MetricsName {
|
||||
SERVICE_RESP_TIME = "service_resp_time",
|
||||
SERVICE_SLA = "service_sla",
|
||||
SERVICE_CPM = "service_cpm",
|
||||
SERVICE_PERCENTILE = "service_percentile",
|
||||
SERVICE_APDEX = "service_apdex",
|
||||
export enum MetricCatalog {
|
||||
SERVICE = "Service",
|
||||
SERVICE_INSTANCE = "ServiceInstance",
|
||||
ENDPOINT = "Endpoint",
|
||||
ALL = "All",
|
||||
SERVICE_RELATION = "ServiceRelation",
|
||||
SERVICE_INSTANCE_RELATION = "ServiceInstanceRelation",
|
||||
ENDPOINT_RELATION = "EndpointRelation",
|
||||
}
|
||||
export const EntityType = [
|
||||
{ value: "service", label: "Service", key: 1 },
|
||||
{ value: "all", label: "All", key: 10 },
|
||||
{ value: "endpoint", label: "Service Endpoint", key: 3 },
|
||||
{ value: "serviceInstance", label: "Service Instance", key: 3 },
|
||||
{ value: "serviceRelationClient", label: "Service Relation(client)", key: 2 },
|
||||
{ value: "serviceRelationServer", label: "Service Relation(server)", key: 2 },
|
||||
{ value: "Service", label: "Service", key: 1 },
|
||||
{ value: "All", label: "All", key: 10 },
|
||||
{ value: "Endpoint", label: "Service Endpoint", key: 3 },
|
||||
{ value: "ServiceInstance", label: "Service Instance", key: 3 },
|
||||
{ value: "ServiceRelationClient", label: "Service Relation(client)", key: 2 },
|
||||
{ value: "ServiceRelationServer", label: "Service Relation(server)", key: 2 },
|
||||
{
|
||||
value: "serviceInstanceRelationClient",
|
||||
value: "ServiceInstanceRelationClient",
|
||||
label: "Service Instance Relation(client)",
|
||||
key: 4,
|
||||
},
|
||||
{
|
||||
value: "serviceInstanceRelationServer",
|
||||
value: "ServiceInstanceRelationServer",
|
||||
label: "Service Instance Relation(server)",
|
||||
key: 4,
|
||||
},
|
||||
{ value: "endpointRelation", label: "Endpoint Relation", key: 4 },
|
||||
{ value: "EndpointRelation", label: "Endpoint Relation", key: 4 },
|
||||
];
|
||||
export const TableEntity: any = {
|
||||
InstanceList: EntityType[3].value,
|
||||
EndpointList: EntityType[2].value,
|
||||
ServiceList: EntityType[0].value,
|
||||
};
|
||||
export const SortOrder = [
|
||||
{ label: "DES", value: "DES" },
|
||||
{ label: "ASC", value: "ASC" },
|
||||
@ -159,69 +173,3 @@ export const ToolIcons = [
|
||||
{ name: "settings", content: "Settings", id: "settings" },
|
||||
{ name: "save", content: "Apply", id: "applay" },
|
||||
];
|
||||
export const Options = [
|
||||
{
|
||||
value: "Option1",
|
||||
label: "Option1",
|
||||
},
|
||||
{
|
||||
value: "Option2",
|
||||
label: "Option2",
|
||||
},
|
||||
{
|
||||
value: "Option3",
|
||||
label: "Option3",
|
||||
},
|
||||
{
|
||||
value: "Option4",
|
||||
label: "Option4",
|
||||
},
|
||||
{
|
||||
value: "Option5",
|
||||
label: "Option5",
|
||||
},
|
||||
];
|
||||
export const SelectOpts = [
|
||||
{
|
||||
value: "guide",
|
||||
label: "Guide",
|
||||
children: [
|
||||
{
|
||||
value: "disciplines",
|
||||
label: "Disciplines",
|
||||
children: [
|
||||
{
|
||||
value: "consistency",
|
||||
label: "Consistency",
|
||||
},
|
||||
{
|
||||
value: "feedback",
|
||||
label: "Feedback",
|
||||
},
|
||||
{
|
||||
value: "efficiency",
|
||||
label: "Efficiency",
|
||||
},
|
||||
{
|
||||
value: "controllability",
|
||||
label: "Controllability",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "navigation",
|
||||
label: "Navigation",
|
||||
children: [
|
||||
{
|
||||
value: "side nav",
|
||||
label: "Side Navigation",
|
||||
},
|
||||
{
|
||||
value: "top nav",
|
||||
label: "Top Navigation",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
@ -17,11 +17,11 @@ limitations under the License. -->
|
||||
<Line :data="data" :intervalTime="intervalTime" :config="config" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import Line from "./Line.vue";
|
||||
import { AreaConfig } from "@/types/dashboard";
|
||||
|
||||
/*global defineProps */
|
||||
defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ [key: string]: number[] }>,
|
||||
|
@ -16,11 +16,12 @@ limitations under the License. -->
|
||||
<Graph :option="option" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, computed } from "vue";
|
||||
import { computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { Event } from "@/types/events";
|
||||
import { BarConfig } from "@/types/dashboard";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ [key: string]: number[] }>,
|
||||
|
@ -14,22 +14,25 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<template>
|
||||
<div class="chart-card" :style="{ fontSize: `${config.fontSize}px` }">
|
||||
<div
|
||||
class="chart-card"
|
||||
:style="{ fontSize: `${config.fontSize}px`, textAlign: config.textAlign }"
|
||||
>
|
||||
{{
|
||||
typeof data[key] === "string"
|
||||
? data[key]
|
||||
: isNaN(data[key])
|
||||
typeof singleVal === "string"
|
||||
? singleVal
|
||||
: isNaN(singleVal)
|
||||
? null
|
||||
: data[key].toFixed(2)
|
||||
: singleVal.toFixed(2)
|
||||
}}
|
||||
<span v-show="config.showUint">{{ standard.unit }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, PropType } from "vue";
|
||||
import { defineProps } from "vue";
|
||||
import { CardConfig, StandardConfig } from "@/types/dashboard";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ [key: string]: number }>,
|
||||
@ -37,7 +40,7 @@ const props = defineProps({
|
||||
},
|
||||
config: {
|
||||
type: Object as PropType<CardConfig>,
|
||||
default: () => ({ fontSize: 12, showUint: true }),
|
||||
default: () => ({ fontSize: 12, showUint: true, textAlign: "center" }),
|
||||
},
|
||||
standard: {
|
||||
type: Object as PropType<StandardConfig>,
|
||||
@ -45,10 +48,16 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
const key = computed(() => Object.keys(props.data)[0]);
|
||||
const singleVal = computed(() => props.data[key.value]);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.chart-card {
|
||||
box-sizing: border-box;
|
||||
color: #333;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-box-align: center;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
@ -13,22 +13,159 @@ 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>
|
||||
<el-table :data="data" style="width: 100%">
|
||||
<el-table-column prop="label" label="Endpoints" />
|
||||
</el-table>
|
||||
<div class="table">
|
||||
<div class="search">
|
||||
<el-input
|
||||
v-model="searchText"
|
||||
placeholder="Please input endpoint name"
|
||||
class="input-with-search"
|
||||
size="small"
|
||||
@change="searchList"
|
||||
>
|
||||
<template #append>
|
||||
<el-button size="small" @click="searchList">
|
||||
<Icon size="lg" iconName="search" />
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<el-table v-loading="chartLoading" :data="endpoints" style="width: 100%">
|
||||
<el-table-column label="Endpoints">
|
||||
<template #default="scope">
|
||||
<router-link
|
||||
class="link"
|
||||
:to="`/dashboard/${dashboardStore.layerId}/${EntityType[2].value}/${selectorStore.currentService.id}/${scope.row.id}/${config.dashboardName}`"
|
||||
:style="{ fontSize: `${config.fontSize}px` }"
|
||||
>
|
||||
{{ scope.row.label }}
|
||||
</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="(metric, index) in config.metrics"
|
||||
:label="metric"
|
||||
:key="metric + index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="chart">
|
||||
<Line
|
||||
:data="{ metric: scope.row[metric] }"
|
||||
:intervalTime="intervalTime"
|
||||
:config="{ showXAxis: false, showYAxis: false }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:page-size="pageSize"
|
||||
:total="selectorStore.pods.length"
|
||||
@current-change="changePage"
|
||||
@prev-click="changePage"
|
||||
@next-click="changePage"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { ElMessage } from "element-plus";
|
||||
import type { PropType } from "vue";
|
||||
import { EndpointListConfig } from "@/types/dashboard";
|
||||
import { Endpoint } from "@/types/selector";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
|
||||
import Line from "./Line.vue";
|
||||
import { EntityType } from "../data";
|
||||
|
||||
defineProps({
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array as PropType<{ label: string; value: string }[]>,
|
||||
default: () => [],
|
||||
type: Object,
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
type: Object as PropType<
|
||||
EndpointListConfig & {
|
||||
i: string;
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
}
|
||||
>,
|
||||
default: () => ({ dashboardName: "", fontSize: 12, i: "" }),
|
||||
},
|
||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||
});
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const chartLoading = ref<boolean>(false);
|
||||
const endpoints = ref<Endpoint[]>([]);
|
||||
const searchEndpoints = ref<Endpoint[]>([]);
|
||||
const pageSize = 5;
|
||||
const searchText = ref<string>("");
|
||||
|
||||
queryEndpoints();
|
||||
|
||||
async function queryEndpoints() {
|
||||
chartLoading.value = true;
|
||||
const resp = await selectorStore.getEndpoints();
|
||||
|
||||
chartLoading.value = false;
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return;
|
||||
}
|
||||
searchEndpoints.value = selectorStore.pods;
|
||||
endpoints.value = selectorStore.pods.splice(0, pageSize);
|
||||
queryEndpointMetrics(endpoints.value);
|
||||
}
|
||||
async function queryEndpointMetrics(currentPods: Endpoint[]) {
|
||||
const { metrics } = props.config;
|
||||
|
||||
if (metrics.length && metrics[0]) {
|
||||
const params = await useQueryPodsMetrics(
|
||||
currentPods,
|
||||
dashboardStore.selectedGrid,
|
||||
EntityType[2].value
|
||||
);
|
||||
const json = await dashboardStore.fetchMetricValue(params);
|
||||
|
||||
if (json.errors) {
|
||||
ElMessage.error(json.errors);
|
||||
return;
|
||||
}
|
||||
endpoints.value = usePodsSource(
|
||||
currentPods,
|
||||
json,
|
||||
dashboardStore.selectedGrid
|
||||
);
|
||||
return;
|
||||
}
|
||||
endpoints.value = currentPods;
|
||||
}
|
||||
function changePage(pageIndex: number) {
|
||||
endpoints.value = searchEndpoints.value.splice(pageIndex - 1, pageSize);
|
||||
}
|
||||
function searchList() {
|
||||
const currentEndpoints = selectorStore.pods.filter((d: { label: string }) =>
|
||||
d.label.includes(searchText.value)
|
||||
);
|
||||
searchEndpoints.value = currentEndpoints;
|
||||
endpoints.value = currentEndpoints.splice(0, pageSize);
|
||||
}
|
||||
watch(
|
||||
() => [props.config.metricTypes, props.config.metrics],
|
||||
() => {
|
||||
queryEndpointMetrics(endpoints.value);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "./style.scss";
|
||||
|
||||
.chart {
|
||||
height: 39px;
|
||||
}
|
||||
</style>
|
||||
|
@ -16,10 +16,11 @@ limitations under the License. -->
|
||||
<Graph :option="option" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, computed } from "vue";
|
||||
import { computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { StandardConfig } from "@/types/dashboard";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ nodes: number[][]; buckets: number[][] }>,
|
||||
|
@ -13,22 +13,171 @@ 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>
|
||||
<el-table :data="data" style="width: 100%">
|
||||
<el-table-column prop="label" label="Service Instances" />
|
||||
</el-table>
|
||||
<div class="table">
|
||||
<div class="search">
|
||||
<el-input
|
||||
v-model="searchText"
|
||||
placeholder="Please input instance name"
|
||||
class="input-with-search"
|
||||
size="small"
|
||||
@change="searchList"
|
||||
>
|
||||
<template #append>
|
||||
<el-button size="small" @click="searchList">
|
||||
<Icon size="lg" iconName="search" />
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<el-table v-loading="chartLoading" :data="instances" style="width: 100%">
|
||||
<el-table-column label="Service Instances">
|
||||
<template #default="scope">
|
||||
<router-link
|
||||
class="link"
|
||||
:to="`/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${selectorStore.currentService.id}/${scope.row.id}/${config.dashboardName}`"
|
||||
:style="{ fontSize: `${config.fontSize}px` }"
|
||||
>
|
||||
{{ scope.row.label }}
|
||||
</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="(metric, index) in config.metrics"
|
||||
:label="metric"
|
||||
:key="metric + index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="chart">
|
||||
<Line
|
||||
v-if="config.metricTypes[index] === 'readMetricsValues'"
|
||||
:data="metric ? { [metric]: scope.row[metric] } : {}"
|
||||
:intervalTime="intervalTime"
|
||||
:config="{ showXAxis: false, showYAxis: false }"
|
||||
/>
|
||||
<Card
|
||||
v-else
|
||||
:data="{ [metric]: scope.row[metric] }"
|
||||
:config="{ textAlign: 'left' }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:page-size="pageSize"
|
||||
:total="searchInstances.length"
|
||||
@current-change="changePage"
|
||||
@prev-click="changePage"
|
||||
@next-click="changePage"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import type { PropType } from "vue";
|
||||
import Line from "./Line.vue";
|
||||
import Card from "./Card.vue";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { InstanceListConfig } from "@/types/dashboard";
|
||||
import { Instance } from "@/types/selector";
|
||||
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
|
||||
import { EntityType } from "../data";
|
||||
|
||||
defineProps({
|
||||
data: {
|
||||
type: Array as PropType<{ label: string; value: string }[]>,
|
||||
default: () => [],
|
||||
},
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
type: Object as PropType<
|
||||
InstanceListConfig & {
|
||||
i: string;
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
}
|
||||
>,
|
||||
default: () => ({
|
||||
dashboardName: "",
|
||||
fontSize: 12,
|
||||
i: "",
|
||||
metrics: [],
|
||||
metricTypes: [],
|
||||
}),
|
||||
},
|
||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||
});
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const chartLoading = ref<boolean>(false);
|
||||
const instances = ref<Instance[]>([]); // current instances
|
||||
const searchInstances = ref<Instance[]>([]); // all instances
|
||||
const pageSize = 5;
|
||||
const searchText = ref<string>("");
|
||||
|
||||
queryInstance();
|
||||
|
||||
async function queryInstance() {
|
||||
chartLoading.value = true;
|
||||
const resp = await selectorStore.getServiceInstances();
|
||||
|
||||
chartLoading.value = false;
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return;
|
||||
}
|
||||
searchInstances.value = selectorStore.pods;
|
||||
instances.value = searchInstances.value.splice(0, pageSize);
|
||||
queryInstanceMetrics(instances.value);
|
||||
}
|
||||
|
||||
async function queryInstanceMetrics(currentInstances: Instance[]) {
|
||||
const { metrics } = props.config;
|
||||
|
||||
if (metrics.length && metrics[0]) {
|
||||
const params = await useQueryPodsMetrics(
|
||||
currentInstances,
|
||||
dashboardStore.selectedGrid,
|
||||
EntityType[3].value
|
||||
);
|
||||
const json = await dashboardStore.fetchMetricValue(params);
|
||||
|
||||
if (json.errors) {
|
||||
ElMessage.error(json.errors);
|
||||
return;
|
||||
}
|
||||
instances.value = usePodsSource(
|
||||
currentInstances,
|
||||
json,
|
||||
dashboardStore.selectedGrid
|
||||
);
|
||||
return;
|
||||
}
|
||||
instances.value = currentInstances;
|
||||
}
|
||||
|
||||
function changePage(pageIndex: number) {
|
||||
instances.value = searchInstances.value.splice(pageIndex - 1, pageSize);
|
||||
}
|
||||
function searchList() {
|
||||
searchInstances.value = selectorStore.pods.filter((d: { label: string }) =>
|
||||
d.label.includes(searchText.value)
|
||||
);
|
||||
instances.value = searchInstances.value.splice(0, pageSize);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.config.metricTypes, props.config.metrics],
|
||||
() => {
|
||||
queryInstanceMetrics(instances.value);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "./style.scss";
|
||||
|
||||
.chart {
|
||||
height: 40px;
|
||||
}
|
||||
</style>
|
||||
|
@ -16,11 +16,12 @@ limitations under the License. -->
|
||||
<Graph :option="option" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, computed } from "vue";
|
||||
import { computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { Event } from "@/types/events";
|
||||
import { LineConfig } from "@/types/dashboard";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ [key: string]: number[] }>,
|
||||
@ -36,6 +37,8 @@ const props = defineProps({
|
||||
smooth: false,
|
||||
showSymbol: false,
|
||||
opacity: 0.4,
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
@ -142,6 +145,8 @@ function getOption() {
|
||||
color,
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
zlevel: 1000,
|
||||
z: 60,
|
||||
backgroundColor: "rgb(50,50,50)",
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
@ -170,6 +175,7 @@ function getOption() {
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
show: props.config.showXAxis,
|
||||
axisTick: {
|
||||
lineStyle: { color: "#c1c5ca41" },
|
||||
alignWithLabel: true,
|
||||
@ -183,7 +189,11 @@ function getOption() {
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
splitLine: { lineStyle: { color: "#c1c5ca41", type: "dashed" } },
|
||||
axisLabel: { color: "#9da5b2", fontSize: "11" },
|
||||
axisLabel: {
|
||||
color: "#9da5b2",
|
||||
fontSize: "11",
|
||||
show: props.config.showYAxis,
|
||||
},
|
||||
},
|
||||
series: temp,
|
||||
};
|
||||
|
@ -16,9 +16,10 @@ limitations under the License. -->
|
||||
<Graph :option="option" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, computed } from "vue";
|
||||
import { computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array as PropType<{ name: string; value: number }[]>,
|
||||
|
168
src/views/dashboard/graphs/ServiceList.vue
Normal file
168
src/views/dashboard/graphs/ServiceList.vue
Normal file
@ -0,0 +1,168 @@
|
||||
<!-- 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 class="table">
|
||||
<div class="search">
|
||||
<el-input
|
||||
v-model="searchText"
|
||||
placeholder="Please input service name"
|
||||
class="input-with-search"
|
||||
size="small"
|
||||
@change="searchList"
|
||||
>
|
||||
<template #append>
|
||||
<el-button size="small" @click="searchList">
|
||||
<Icon size="lg" iconName="search" />
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<el-table v-loading="chartLoading" :data="services" style="width: 100%">
|
||||
<el-table-column label="Services">
|
||||
<template #default="scope">
|
||||
<router-link
|
||||
class="link"
|
||||
:to="`/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${selectorStore.currentService.id}/${config.dashboardName}`"
|
||||
:key="1"
|
||||
:style="{ fontSize: `${config.fontSize}px` }"
|
||||
>
|
||||
{{ scope.row.label }}
|
||||
</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="(metric, index) in config.metrics"
|
||||
:label="metric"
|
||||
:key="metric + index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="chart">
|
||||
<Line
|
||||
:data="{ metric: scope.row[metric] }"
|
||||
:intervalTime="intervalTime"
|
||||
:config="{ showXAxis: false, showYAxis: false }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:page-size="pageSize"
|
||||
:total="selectorStore.services.length"
|
||||
@current-change="changePage"
|
||||
@prev-click="changePage"
|
||||
@next-click="changePage"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { watch, ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import type { PropType } from "vue";
|
||||
import { ServiceListConfig } from "@/types/dashboard";
|
||||
import Line from "./Line.vue";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { Service } from "@/types/selector";
|
||||
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
|
||||
import { EntityType } from "../data";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
},
|
||||
config: {
|
||||
type: Object as PropType<
|
||||
ServiceListConfig & {
|
||||
i: string;
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
}
|
||||
>,
|
||||
default: () => ({ dashboardName: "", fontSize: 12 }),
|
||||
},
|
||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||
});
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const chartLoading = ref<boolean>(false);
|
||||
const pageSize = 5;
|
||||
const services = ref<Service[]>([]);
|
||||
const searchServices = ref<Service[]>([]);
|
||||
const searchText = ref<string>("");
|
||||
|
||||
queryServices();
|
||||
|
||||
async function queryServices() {
|
||||
chartLoading.value = true;
|
||||
const resp = await selectorStore.fetchServices();
|
||||
|
||||
chartLoading.value = false;
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
}
|
||||
services.value = selectorStore.services.splice(0, pageSize);
|
||||
}
|
||||
async function queryServiceMetrics(currentServices: Service[]) {
|
||||
const { metrics } = props.config;
|
||||
|
||||
if (metrics.length && metrics[0]) {
|
||||
const params = await useQueryPodsMetrics(
|
||||
currentServices,
|
||||
dashboardStore.selectedGrid,
|
||||
EntityType[0].value
|
||||
);
|
||||
const json = await dashboardStore.fetchMetricValue(params);
|
||||
|
||||
if (json.errors) {
|
||||
ElMessage.error(json.errors);
|
||||
return;
|
||||
}
|
||||
services.value = usePodsSource(
|
||||
currentServices,
|
||||
json,
|
||||
dashboardStore.selectedGrid
|
||||
);
|
||||
return;
|
||||
}
|
||||
services.value = currentServices;
|
||||
}
|
||||
function changePage(pageIndex: number) {
|
||||
services.value = selectorStore.services.splice(pageIndex - 1, pageSize);
|
||||
}
|
||||
function searchList() {
|
||||
searchServices.value = selectorStore.services.filter((d: { label: string }) =>
|
||||
d.label.includes(searchText.value)
|
||||
);
|
||||
services.value = searchServices.value.splice(0, pageSize);
|
||||
}
|
||||
watch(
|
||||
() => [props.config.metricTypes, props.config.metrics],
|
||||
() => {
|
||||
queryServiceMetrics(services.value);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "./style.scss";
|
||||
|
||||
.chart {
|
||||
height: 39px;
|
||||
}
|
||||
</style>
|
@ -22,9 +22,9 @@ limitations under the License. -->
|
||||
>
|
||||
<div class="name" :style="`width: ${nameWidth}px`">
|
||||
{{ config.tableHeaderCol1 || $t("name") }}
|
||||
<i class="r cp" ref="draggerName"
|
||||
><rk-icon icon="settings_ethernet"
|
||||
/></i>
|
||||
<i class="r cp" ref="draggerName">
|
||||
<Icon iconName="settings_ethernet" size="middle" />
|
||||
</i>
|
||||
</div>
|
||||
<div class="value-col" v-if="config.showTableValues">
|
||||
{{ config.tableHeaderCol2 || $t("value") }}
|
||||
@ -45,11 +45,12 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, computed, ref, onMounted } from "vue";
|
||||
import { computed, ref, onMounted } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ [key: string]: number[][] }>,
|
||||
type: Object as PropType<{ [key: string]: number[] }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
config: {
|
||||
|
@ -14,57 +14,68 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<template>
|
||||
<div class="chart-slow-i" v-for="(i, index) in datas" :key="index">
|
||||
<Icon
|
||||
iconName="review-list"
|
||||
size="sm"
|
||||
@click="handleClick((i.traceIds && i.traceIds[0]) || i.name)"
|
||||
/>
|
||||
<div class="mb-5 ell">
|
||||
<span class="calls sm mr-10">{{ i.value }}</span>
|
||||
<span class="cp link-hover">
|
||||
{{ i.name + getTraceId(i) }}
|
||||
</span>
|
||||
<div class="top-list">
|
||||
<div class="chart-slow-i" v-for="(i, index) in datas" :key="index">
|
||||
<div class="ell tools flex-h">
|
||||
<div>
|
||||
<span class="calls mr-10">{{ i.value }}</span>
|
||||
<span class="cp mr-20">
|
||||
{{ i.name + getTraceId(i) }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<Icon
|
||||
iconName="review-list"
|
||||
size="middle"
|
||||
class="cp"
|
||||
@click="handleClick((i.traceIds && i.traceIds[0]) || i.name)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<el-progress
|
||||
:stroke-width="6"
|
||||
:percentage="(i.value / maxValue) * 100"
|
||||
color="#bf99f8"
|
||||
:show-text="false"
|
||||
/>
|
||||
</div>
|
||||
<el-progress
|
||||
:stroke-width="10"
|
||||
:percentage="(i.value / maxValue) * 100"
|
||||
color="#bf99f8"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from "vue";
|
||||
import { defineProps, computed } from "vue";
|
||||
import { computed } from "vue";
|
||||
import copy from "@/utils/copy";
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array as PropType<
|
||||
{ name: string; value: number; traceIds: string[] }[]
|
||||
>,
|
||||
default: () => [],
|
||||
type: Object as PropType<{
|
||||
[key: string]: { name: string; value: number; traceIds: string[] }[];
|
||||
}>,
|
||||
default: () => ({}),
|
||||
},
|
||||
config: {
|
||||
type: Object as PropType<{ sortOrder: string }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||
});
|
||||
const key = computed(() => Object.keys(props.data)[0]);
|
||||
const maxValue = computed(() => {
|
||||
if (!props.data.length) {
|
||||
if (!(props.data[key.value] && props.data[key.value].length)) {
|
||||
return 0;
|
||||
}
|
||||
const temp: number[] = props.data.map((i: any) => i.value);
|
||||
const temp: number[] = props.data[key.value].map((i: any) => i.value);
|
||||
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: any = () => {
|
||||
if (!props.data.length) {
|
||||
const datas = computed(() => {
|
||||
if (!(props.data[key.value] && props.data[key.value].length)) {
|
||||
return [];
|
||||
}
|
||||
const { sortOrder } = props.config;
|
||||
const val: any = props.data;
|
||||
const val: any = props.data[key.value];
|
||||
|
||||
switch (sortOrder) {
|
||||
case "DES":
|
||||
@ -74,17 +85,29 @@ const datas: any = () => {
|
||||
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) {
|
||||
copy(i);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.top-list {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.tools {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
font-size: 14px;
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
@ -94,14 +117,15 @@ function handleClick(i: string) {
|
||||
|
||||
.chart-slow {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.calls {
|
||||
padding: 0 5px;
|
||||
display: inline-block;
|
||||
background-color: #40454e;
|
||||
color: #eee;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.calls {
|
||||
font-size: 12px;
|
||||
padding: 0 5px;
|
||||
display: inline-block;
|
||||
background-color: #40454e;
|
||||
color: #eee;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.chart-slow-link {
|
||||
|
@ -23,6 +23,9 @@ import TopList from "./TopList.vue";
|
||||
import Table from "./Table.vue";
|
||||
import Pie from "./Pie.vue";
|
||||
import Card from "./Card.vue";
|
||||
import InstanceList from "./InstanceList.vue";
|
||||
import EndpointList from "./EndpointList.vue";
|
||||
import ServiceList from "./ServiceList.vue";
|
||||
|
||||
export default {
|
||||
Line,
|
||||
@ -33,4 +36,7 @@ export default {
|
||||
Table,
|
||||
Pie,
|
||||
Card,
|
||||
EndpointList,
|
||||
InstanceList,
|
||||
ServiceList,
|
||||
};
|
||||
|
43
src/views/dashboard/graphs/style.scss
Normal file
43
src/views/dashboard/graphs/style.scss
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
.table {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 0 10px 5px 0;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 30px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.link {
|
||||
cursor: pointer;
|
||||
color: #409eff;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.input-with-search {
|
||||
width: 400px;
|
||||
}
|
@ -15,48 +15,55 @@ limitations under the License. -->
|
||||
<template>
|
||||
<div class="dashboard-tool flex-h">
|
||||
<div class="flex-h">
|
||||
<div class="selectors-item" v-if="states.key < 3">
|
||||
<div class="selectors-item" v-if="states.key !== 10">
|
||||
<span class="label">$Service</span>
|
||||
<Selector
|
||||
:value="states.service"
|
||||
:options="Options"
|
||||
v-model="states.currentService"
|
||||
:options="selectorStore.services"
|
||||
size="mini"
|
||||
placeholder="Select a service"
|
||||
@change="changeService"
|
||||
class="selectors"
|
||||
:borderRadius="4"
|
||||
/>
|
||||
</div>
|
||||
<div class="selectors-item" v-if="states.key === 3 || states.key === 4">
|
||||
<span class="label">$ServiceInstance</span>
|
||||
<el-cascader
|
||||
placeholder="Select a instance"
|
||||
:options="SelectOpts"
|
||||
<span class="label">
|
||||
{{
|
||||
dashboardStore.entity === "Endpoint"
|
||||
? "$Endpoint"
|
||||
: "$ServiceInstance"
|
||||
}}
|
||||
</span>
|
||||
<Selector
|
||||
v-model="states.currentPod"
|
||||
:options="selectorStore.pods"
|
||||
size="mini"
|
||||
filterable
|
||||
:style="{ minWidth: '300px' }"
|
||||
placeholder="Select a data"
|
||||
@change="changePods"
|
||||
class="selectors"
|
||||
/>
|
||||
</div>
|
||||
<div class="selectors-item" v-if="states.key === 2">
|
||||
<span class="label">$DestinationService</span>
|
||||
<Selector
|
||||
:value="states.service"
|
||||
:options="Options"
|
||||
v-model="selectorStore.currentDestService"
|
||||
:options="selectorStore.services"
|
||||
size="mini"
|
||||
placeholder="Select a service"
|
||||
:borderRadius="0"
|
||||
@change="changeService"
|
||||
class="selectors"
|
||||
/>
|
||||
</div>
|
||||
<div class="selectors-item" v-if="states.key === 4">
|
||||
<span class="label">$DestinationServiceInstance</span>
|
||||
<el-cascader
|
||||
placeholder="Select a instance"
|
||||
:options="SelectOpts"
|
||||
<Selector
|
||||
v-model="states.currentPod"
|
||||
:options="selectorStore.pods"
|
||||
size="mini"
|
||||
filterable
|
||||
:style="{ minWidth: '300px' }"
|
||||
placeholder="Select a data"
|
||||
@change="changePods"
|
||||
class="selectors"
|
||||
:borderRadius="4"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -80,33 +87,96 @@ limitations under the License. -->
|
||||
import { reactive } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { Options, SelectOpts, EntityType, ToolIcons } from "../data";
|
||||
import { EntityType, ToolIcons } from "../data";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Option } from "@/types/app";
|
||||
import { Service } from "@/types/selector";
|
||||
|
||||
const dashboardStore = useDashboardStore();
|
||||
const selectorStore = useSelectorStore();
|
||||
const params = useRoute().params;
|
||||
const type = EntityType.filter((d: Option) => d.value === params.entity)[0];
|
||||
const states = reactive<{
|
||||
entity: string | string[];
|
||||
layerId: string | string[];
|
||||
service: string;
|
||||
pod: string;
|
||||
destService: string;
|
||||
destPod: string;
|
||||
key: number;
|
||||
currentService: string;
|
||||
currentPod: string;
|
||||
}>({
|
||||
service: Options[0].value,
|
||||
pod: Options[0].value, // instances and endpoints
|
||||
destService: "",
|
||||
destPod: "",
|
||||
key: EntityType.filter((d: any) => d.value === params.entity)[0].key || 0,
|
||||
entity: params.entity,
|
||||
layerId: params.layerId,
|
||||
key: (type && type.key) || 0,
|
||||
currentService: "",
|
||||
currentPod: "",
|
||||
});
|
||||
|
||||
dashboardStore.setLayer(states.layerId);
|
||||
dashboardStore.setEntity(states.entity);
|
||||
dashboardStore.setLayer(String(params.layerId));
|
||||
dashboardStore.setEntity(String(params.entity));
|
||||
|
||||
function changeService(val: { value: string; label: string }) {
|
||||
states.service = val.value;
|
||||
if (params.serviceId) {
|
||||
setSelector();
|
||||
} else {
|
||||
getServices();
|
||||
}
|
||||
|
||||
async function setSelector() {
|
||||
if (params.podId) {
|
||||
await selectorStore.getService(String(params.serviceId));
|
||||
states.currentService = selectorStore.currentService.value;
|
||||
await fetchPods(String(params.entity), false);
|
||||
const currentPod = selectorStore.pods.filter(
|
||||
(d: { id: string }) => d.id === String(params.podId)
|
||||
)[0];
|
||||
selectorStore.setCurrentPod(currentPod);
|
||||
states.currentPod = currentPod.label;
|
||||
return;
|
||||
}
|
||||
// entity=Service with serviceId
|
||||
const json = await selectorStore.fetchServices(dashboardStore.layerId);
|
||||
if (json.errors) {
|
||||
ElMessage.error(json.errors);
|
||||
return;
|
||||
}
|
||||
const currentService = selectorStore.services.filter(
|
||||
(d: { id: string }) => d.id === String(params.serviceId)
|
||||
)[0];
|
||||
selectorStore.setCurrentService(currentService);
|
||||
states.currentService = selectorStore.currentService.value;
|
||||
}
|
||||
|
||||
async function getServices() {
|
||||
if (!dashboardStore.layerId) {
|
||||
return;
|
||||
}
|
||||
const json = await selectorStore.fetchServices(dashboardStore.layerId);
|
||||
if (json.errors) {
|
||||
ElMessage.error(json.errors);
|
||||
return;
|
||||
}
|
||||
selectorStore.setCurrentService(
|
||||
selectorStore.services.length ? selectorStore.services[0] : null
|
||||
);
|
||||
states.currentService = selectorStore.currentService.value;
|
||||
fetchPods(dashboardStore.entity, true);
|
||||
}
|
||||
|
||||
async function changeService(service: Service[]) {
|
||||
if (service[0]) {
|
||||
states.currentService = service[0].value;
|
||||
selectorStore.setCurrentService(service[0]);
|
||||
fetchPods(dashboardStore.entity, true);
|
||||
} else {
|
||||
selectorStore.setCurrentService("");
|
||||
}
|
||||
}
|
||||
|
||||
function changePods(pod: Option[]) {
|
||||
if (pod[0]) {
|
||||
selectorStore.setCurrentPod(pod[0].value);
|
||||
} else {
|
||||
selectorStore.setCurrentPod("");
|
||||
}
|
||||
}
|
||||
|
||||
function clickIcons(t: { id: string; content: string; name: string }) {
|
||||
@ -127,6 +197,36 @@ function clickIcons(t: { id: string; content: string; name: string }) {
|
||||
dashboardStore.addControl("Widget");
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchPods(type: string, setPod: boolean) {
|
||||
let resp;
|
||||
switch (type) {
|
||||
case "Endpoint":
|
||||
resp = await selectorStore.getEndpoints();
|
||||
if (setPod) {
|
||||
selectorStore.setCurrentPod(
|
||||
selectorStore.pods.length ? selectorStore.pods[0] : null
|
||||
);
|
||||
states.currentPod = selectorStore.currentPod.label;
|
||||
}
|
||||
break;
|
||||
case "ServiceInstance":
|
||||
resp = await selectorStore.getServiceInstances();
|
||||
if (setPod) {
|
||||
selectorStore.setCurrentPod(
|
||||
selectorStore.pods.length ? selectorStore.pods[0] : null
|
||||
);
|
||||
states.currentPod = selectorStore.currentPod.label;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
resp = {};
|
||||
}
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.dashboard-tool {
|
||||
|
@ -17,7 +17,7 @@ limitations under the License. -->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
/*global defineProps */
|
||||
defineProps({
|
||||
msg: { type: String },
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ limitations under the License. -->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
/*global defineProps */
|
||||
defineProps({
|
||||
msg: { type: String },
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ limitations under the License. -->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
/*global defineProps */
|
||||
defineProps({
|
||||
msg: { type: String },
|
||||
});
|
||||
|
@ -40,9 +40,19 @@ module.exports = {
|
||||
chunks: "all",
|
||||
cacheGroups: {
|
||||
echarts: {
|
||||
name: "echarts",
|
||||
test: /[\\/]node_modules[\\/]echarts[\\/]/,
|
||||
priority: 1,
|
||||
},
|
||||
elementPlus: {
|
||||
name: "element-plus",
|
||||
test: /[\\/]node_modules[\\/]element-plus[\\/]/,
|
||||
priority: 2,
|
||||
},
|
||||
three: {
|
||||
name: "three",
|
||||
test: /[\\/]node_modules[\\/]three[\\/]/,
|
||||
priority: 2,
|
||||
priority: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user