mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-02 21:53:17 +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
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<router-view />
|
<router-view :key="$route.fullPath" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<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 not use this file except in compliance with
|
||||||
the License. You may obtain a copy of the License at
|
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
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
<input v-show="!imgUrl" type="file" @change="fileChange" accept="image/*" />
|
<title>add_circle_outlinecontrol_point</title>
|
||||||
<img v-if="imgUrl" :src="imgUrl" alt="" />
|
<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>
|
||||||
</template>
|
</svg>
|
||||||
<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>
|
|
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>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import { computed, onMounted, watch, reactive } from "vue";
|
||||||
defineProps,
|
|
||||||
computed,
|
|
||||||
defineEmits,
|
|
||||||
onMounted,
|
|
||||||
watch,
|
|
||||||
reactive,
|
|
||||||
} from "vue";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
/*global defineProps, defineEmits */
|
||||||
const emit = defineEmits(["input", "setDates", "ok"]);
|
const emit = defineEmits(["input", "setDates", "ok"]);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -580,11 +574,13 @@ onMounted(() => {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
color: #3d444f;
|
color: #3d444f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar + .calendar {
|
.calendar + .calendar {
|
||||||
border-left: solid 1px #eaeaea;
|
border-left: solid 1px #eaeaea;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-head {
|
.calendar-head {
|
||||||
line-height: 34px;
|
line-height: 34px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
@ -630,10 +626,12 @@ onMounted(() => {
|
|||||||
.calendar-next-month-btn {
|
.calendar-next-month-btn {
|
||||||
right: 24px;
|
right: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-next-month-btn .middle,
|
.calendar-next-month-btn .middle,
|
||||||
.calendar-prev-month-btn .middle {
|
.calendar-prev-month-btn .middle {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-body {
|
.calendar-body {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 196px;
|
width: 196px;
|
||||||
|
@ -16,20 +16,12 @@ limitations under the License. -->
|
|||||||
<div ref="chartRef" :style="`height:${height};width:${width};`"></div>
|
<div ref="chartRef" :style="`height:${height};width:${width};`"></div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import { watch, ref, Ref, onMounted, onBeforeUnmount, unref } from "vue";
|
||||||
watch,
|
|
||||||
ref,
|
|
||||||
defineProps,
|
|
||||||
Ref,
|
|
||||||
onMounted,
|
|
||||||
onBeforeUnmount,
|
|
||||||
unref,
|
|
||||||
} from "vue";
|
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { useECharts } from "@/hooks/useEcharts";
|
import { useECharts } from "@/hooks/useEcharts";
|
||||||
import { addResizeListener, removeResizeListener } from "@/utils/event";
|
import { addResizeListener, removeResizeListener } from "@/utils/event";
|
||||||
|
|
||||||
/*global Nullable*/
|
/*global Nullable, defineProps*/
|
||||||
const chartRef = ref<Nullable<HTMLDivElement>>(null);
|
const chartRef = ref<Nullable<HTMLDivElement>>(null);
|
||||||
const { setOptions, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
|
const { setOptions, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -49,8 +41,11 @@ onMounted(() => {
|
|||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.option,
|
() => props.option,
|
||||||
(opt) => {
|
(newVal, oldVal) => {
|
||||||
setOptions(opt);
|
if (JSON.stringify(newVal) === JSON.stringify(oldVal)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setOptions(newVal);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -28,8 +28,9 @@ limitations under the License. -->
|
|||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps } from "vue";
|
|
||||||
import "@/assets/icons/index";
|
import "@/assets/icons/index";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
defineProps({
|
defineProps({
|
||||||
iconName: { type: String, default: "" },
|
iconName: { type: String, default: "" },
|
||||||
size: { type: String, default: "sm" },
|
size: { type: String, default: "sm" },
|
||||||
@ -42,25 +43,31 @@ defineProps({
|
|||||||
height: 16px;
|
height: 16px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
|
|
||||||
&.sm {
|
&.sm {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.middle {
|
&.middle {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.lg {
|
&.lg {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.loading {
|
&.loading {
|
||||||
animation: loading 1.5s linear infinite;
|
animation: loading 1.5s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.logo {
|
&.logo {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 110px;
|
width: 110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.xl {
|
&.xl {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
|
@ -20,6 +20,7 @@ limitations under the License. -->
|
|||||||
@change="changeSelected"
|
@change="changeSelected"
|
||||||
filterable
|
filterable
|
||||||
:multiple="multiple"
|
:multiple="multiple"
|
||||||
|
:disabled="disabled"
|
||||||
:style="{ borderRadius }"
|
:style="{ borderRadius }"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
@ -32,7 +33,7 @@ limitations under the License. -->
|
|||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, defineEmits } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { ElSelect, ElOption } from "element-plus";
|
import { ElSelect, ElOption } from "element-plus";
|
||||||
|
|
||||||
@ -41,8 +42,9 @@ interface Option {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*global defineProps, defineEmits*/
|
||||||
|
|
||||||
const emit = defineEmits(["change"]);
|
const emit = defineEmits(["change"]);
|
||||||
/*global defineProps*/
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
options: {
|
options: {
|
||||||
type: Array as PropType<Option[]>,
|
type: Array as PropType<Option[]>,
|
||||||
@ -56,12 +58,11 @@ const props = defineProps({
|
|||||||
placeholder: { type: String, default: "Select a option" },
|
placeholder: { type: String, default: "Select a option" },
|
||||||
borderRadius: { type: Number, default: 3 },
|
borderRadius: { type: Number, default: 3 },
|
||||||
multiple: { type: Boolean, default: false },
|
multiple: { type: Boolean, default: false },
|
||||||
|
disabled: { type: Boolean, default: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
const selected = ref<string[] | string>(props.value);
|
const selected = ref<string[] | string>(props.value);
|
||||||
function changeSelected() {
|
function changeSelected() {
|
||||||
if (!props.multiple) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const options = props.options.filter((d: Option) =>
|
const options = props.options.filter((d: Option) =>
|
||||||
props.multiple
|
props.multiple
|
||||||
? selected.value.includes(d.value)
|
? selected.value.includes(d.value)
|
||||||
@ -69,6 +70,12 @@ function changeSelected() {
|
|||||||
);
|
);
|
||||||
emit("change", options);
|
emit("change", options);
|
||||||
}
|
}
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
(data) => {
|
||||||
|
selected.value = data;
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scope>
|
<style lang="scss" scope>
|
||||||
.icon {
|
.icon {
|
||||||
|
@ -142,17 +142,10 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue";
|
||||||
defineProps,
|
|
||||||
ref,
|
|
||||||
computed,
|
|
||||||
defineEmits,
|
|
||||||
onMounted,
|
|
||||||
onBeforeUnmount,
|
|
||||||
watch,
|
|
||||||
} from "vue";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import DateCalendar from "./DateCalendar.vue";
|
import DateCalendar from "./DateCalendar.vue";
|
||||||
|
/*global defineProps, defineEmits */
|
||||||
const datepicker = ref(null);
|
const datepicker = ref(null);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const show = ref<boolean>(false);
|
const show = ref<boolean>(false);
|
||||||
@ -339,6 +332,30 @@ watch(
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<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 {
|
.datepicker {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -373,7 +390,6 @@ watch(
|
|||||||
margin-left: -8px;
|
margin-left: -8px;
|
||||||
margin-top: -8px;
|
margin-top: -8px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: #ccc;
|
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #ccc
|
background: #ccc
|
||||||
@ -384,6 +400,7 @@ watch(
|
|||||||
.datepicker__clearable:hover:before {
|
.datepicker__clearable:hover:before {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.datepicker__clearable:hover .datepicker-close {
|
.datepicker__clearable:hover .datepicker-close {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@ -436,25 +453,30 @@ watch(
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
|
|
||||||
&.top {
|
&.top {
|
||||||
bottom: 30px;
|
bottom: 30px;
|
||||||
right: 0;
|
right: 0;
|
||||||
transform-origin: center bottom;
|
transform-origin: center bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.bottom {
|
&.bottom {
|
||||||
top: 30px;
|
top: 30px;
|
||||||
right: 0;
|
right: 0;
|
||||||
transform-origin: center top;
|
transform-origin: center top;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.left {
|
&.left {
|
||||||
top: 30px;
|
top: 30px;
|
||||||
transform-origin: center top;
|
transform-origin: center top;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.right {
|
&.right {
|
||||||
right: -80px;
|
right: -80px;
|
||||||
top: 30px;
|
top: 30px;
|
||||||
transform-origin: center top;
|
transform-origin: center top;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__sidebar {
|
&__sidebar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -464,6 +486,7 @@ watch(
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-right: solid 1px #eaeaea;
|
border-right: solid 1px #eaeaea;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__shortcut {
|
&__shortcut {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -476,10 +499,12 @@ watch(
|
|||||||
outline: none;
|
outline: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #3f97e3;
|
color: #3f97e3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__body {
|
&__body {
|
||||||
margin-left: 100px;
|
margin-left: 100px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
@ -513,6 +538,7 @@ watch(
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.datepicker-anim-enter-active {
|
.datepicker-anim-enter-active {
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
animation: datepicker-anim-in 0.2s cubic-bezier(0.23, 1, 0.32, 1);
|
animation: datepicker-anim-in 0.2s cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
@ -545,26 +571,4 @@ watch(
|
|||||||
.datepicker__buttons .datepicker__button-cancel {
|
.datepicker__buttons .datepicker__button-cancel {
|
||||||
background: #666;
|
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>
|
</style>
|
||||||
|
@ -18,47 +18,16 @@ export const TypeOfMetrics = {
|
|||||||
variable: "$name: String!",
|
variable: "$name: String!",
|
||||||
query: `typeOfMetrics(name: $name)`,
|
query: `typeOfMetrics(name: $name)`,
|
||||||
};
|
};
|
||||||
export const queryMetricsValues = {
|
export const listMetrics = {
|
||||||
variable: ["$condition: MetricsCondition!, $duration: Duration!"],
|
variable: "$regex: String",
|
||||||
query: `
|
query: `
|
||||||
readMetricsValues: readMetricsValues(condition: $condition, duration: $duration) {
|
metrics: listMetrics(regex: $regex) {
|
||||||
label
|
value: name
|
||||||
values {
|
label: name
|
||||||
values {value}
|
type
|
||||||
}
|
catalog
|
||||||
}`,
|
}
|
||||||
};
|
`,
|
||||||
|
|
||||||
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}
|
|
||||||
}
|
|
||||||
}`,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const queryHeatMap = {
|
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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
export const Services = {
|
export const Services = {
|
||||||
variable: ["$layer: String!"],
|
variable: "$layer: String!",
|
||||||
query: `
|
query: `
|
||||||
services: listServices(layer: $layer) {
|
services: listServices(layer: $layer) {
|
||||||
value: id
|
id
|
||||||
|
value: name
|
||||||
label: name
|
label: name
|
||||||
group
|
group
|
||||||
layer
|
layers
|
||||||
}
|
normal
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
export const Layers = {
|
export const Layers = {
|
||||||
@ -33,10 +35,13 @@ export const Layers = {
|
|||||||
export const Instances = {
|
export const Instances = {
|
||||||
variable: "$serviceId: ID!, $duration: Duration!",
|
variable: "$serviceId: ID!, $duration: Duration!",
|
||||||
query: `
|
query: `
|
||||||
getServiceInstances(duration: $duration, serviceId: $serviceId) {
|
pods: listInstances(duration: $duration, serviceId: $serviceId) {
|
||||||
key: id
|
id
|
||||||
|
value: name
|
||||||
label: name
|
label: name
|
||||||
language
|
language
|
||||||
|
instanceUUID
|
||||||
|
layer
|
||||||
attributes {
|
attributes {
|
||||||
name
|
name
|
||||||
value
|
value
|
||||||
@ -47,9 +52,55 @@ export const Instances = {
|
|||||||
export const Endpoints = {
|
export const Endpoints = {
|
||||||
variable: "$serviceId: ID!, $keyword: String!",
|
variable: "$serviceId: ID!, $keyword: String!",
|
||||||
query: `
|
query: `
|
||||||
getEndpoints: searchEndpoint(serviceId: $serviceId, keyword: $keyword, limit: 100) {
|
pods: findEndpoint(serviceId: $serviceId, keyword: $keyword, limit: 100) {
|
||||||
key: id
|
id
|
||||||
label: name
|
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 {
|
import {
|
||||||
TypeOfMetrics,
|
TypeOfMetrics,
|
||||||
querySampledRecords,
|
|
||||||
queryHeatMap,
|
queryHeatMap,
|
||||||
queryLabeledMetricsValues,
|
listMetrics,
|
||||||
querySortMetrics,
|
|
||||||
queryMetricsValue,
|
|
||||||
queryMetricsValues,
|
|
||||||
} from "../fragments/dashboard";
|
} from "../fragments/dashboard";
|
||||||
|
|
||||||
export const queryTypeOfMetrics = `query typeOfMetrics(${TypeOfMetrics.variable}) {${TypeOfMetrics.query}}`;
|
export const queryTypeOfMetrics = `query typeOfMetrics(${TypeOfMetrics.variable}) {${TypeOfMetrics.query}}`;
|
||||||
|
|
||||||
export const readHeatMap = `query queryData(${queryHeatMap.variable}) {${queryHeatMap.query}}`;
|
export const readHeatMap = `query queryData(${queryHeatMap.variable}) {${queryHeatMap.query}}`;
|
||||||
|
|
||||||
export const readSampledRecords = `query queryData(${querySampledRecords.variable}) {${querySampledRecords.query}}`;
|
export const queryMetrics = `query queryData(${listMetrics.variable}) {${listMetrics.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}}`;
|
|
||||||
|
@ -14,10 +14,20 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
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 queryServices = `query queryServices(${Services.variable}) {${Services.query}}`;
|
||||||
export const queryLayers = `query ${Layers.query}`;
|
|
||||||
export const queryEndpoints = `query queryEndpoints(${Endpoints.variable}) {${Endpoints.query}}`;
|
export const queryEndpoints = `query queryEndpoints(${Endpoints.variable}) {${Endpoints.query}}`;
|
||||||
|
|
||||||
export const queryInstances = `query queryInstances(${Instances.variable}) {${Instances.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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
export enum MetricQueryTypes {
|
||||||
|
ReadMetricsValue = "readMetricsValue",
|
||||||
|
ReadMetricsValues = "readMetricsValues",
|
||||||
|
SortMetrics = "sortMetrics",
|
||||||
|
ReadLabeledMetricsValues = "readLabeledMetricsValues",
|
||||||
|
READHEATMAP = "readHeatMap",
|
||||||
|
ReadSampledRecords = "readSampledRecords",
|
||||||
|
}
|
||||||
export enum sizeEnum {
|
export enum sizeEnum {
|
||||||
XS = "XS",
|
XS = "XS",
|
||||||
SM = "SM",
|
SM = "SM",
|
||||||
@ -32,7 +40,7 @@ export enum screenEnum {
|
|||||||
XXL = 1600,
|
XXL = 1600,
|
||||||
}
|
}
|
||||||
|
|
||||||
const screenMap = new Map<sizeEnum, number>();
|
export const screenMap = new Map<sizeEnum, number>();
|
||||||
|
|
||||||
screenMap.set(sizeEnum.XS, screenEnum.XS);
|
screenMap.set(sizeEnum.XS, screenEnum.XS);
|
||||||
screenMap.set(sizeEnum.SM, screenEnum.SM);
|
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.XL, screenEnum.XL);
|
||||||
screenMap.set(sizeEnum.XXL, screenEnum.XXL);
|
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. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<section class="app-main">
|
<section class="app-main">
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }" :key="$route.fullPath">
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
|
@ -30,7 +30,7 @@ const msg = {
|
|||||||
events: "Events",
|
events: "Events",
|
||||||
alerts: "Alerts",
|
alerts: "Alerts",
|
||||||
settings: "Settings",
|
settings: "Settings",
|
||||||
dashboards: "Dashboards",
|
dashboards: "Dashboard",
|
||||||
profiles: "Profiles",
|
profiles: "Profiles",
|
||||||
database: "Database",
|
database: "Database",
|
||||||
serviceName: "Service Name",
|
serviceName: "Service Name",
|
||||||
@ -53,7 +53,8 @@ const msg = {
|
|||||||
instance: "Instance",
|
instance: "Instance",
|
||||||
create: "Create",
|
create: "Create",
|
||||||
loading: "Loading",
|
loading: "Loading",
|
||||||
selectVisualization: "Select your visualization",
|
selectVisualization: "Visualize your metrics",
|
||||||
|
visualization: "Visualization",
|
||||||
graphStyles: "Graph styles",
|
graphStyles: "Graph styles",
|
||||||
widgetOptions: "Widget options",
|
widgetOptions: "Widget options",
|
||||||
standardOptions: "Standard options",
|
standardOptions: "Standard options",
|
||||||
@ -72,6 +73,8 @@ const msg = {
|
|||||||
fontSize: "Font Size",
|
fontSize: "Font Size",
|
||||||
showBackground: "Show Background",
|
showBackground: "Show Background",
|
||||||
areaOpacity: "Area Opacity",
|
areaOpacity: "Area Opacity",
|
||||||
|
editGraph: "Edit Graph Options",
|
||||||
|
dashboardName: "Select Dashboard Name",
|
||||||
hourTip: "Select Hour",
|
hourTip: "Select Hour",
|
||||||
minuteTip: "Select Minute",
|
minuteTip: "Select Minute",
|
||||||
secondTip: "Select Second",
|
secondTip: "Select Second",
|
||||||
|
@ -51,7 +51,8 @@ const msg = {
|
|||||||
endpoint: "端点",
|
endpoint: "端点",
|
||||||
create: "新建",
|
create: "新建",
|
||||||
loading: "加载中",
|
loading: "加载中",
|
||||||
selectVisualization: "选择你的可视化",
|
selectVisualization: "可视化指标",
|
||||||
|
visualization: "可视化",
|
||||||
graphStyles: "图形样式",
|
graphStyles: "图形样式",
|
||||||
widgetOptions: "组件选项",
|
widgetOptions: "组件选项",
|
||||||
standardOptions: "标准选项",
|
standardOptions: "标准选项",
|
||||||
@ -70,6 +71,8 @@ const msg = {
|
|||||||
fontSize: "字体大小",
|
fontSize: "字体大小",
|
||||||
showBackground: "显示背景",
|
showBackground: "显示背景",
|
||||||
areaOpacity: "透明度",
|
areaOpacity: "透明度",
|
||||||
|
editGraph: "编辑图表选项",
|
||||||
|
dashboardName: "选择仪表板名称",
|
||||||
hourTip: "选择小时",
|
hourTip: "选择小时",
|
||||||
minuteTip: "选择分钟",
|
minuteTip: "选择分钟",
|
||||||
secondTip: "选择秒数",
|
secondTip: "选择秒数",
|
||||||
|
@ -20,10 +20,10 @@ import router from "./router";
|
|||||||
import { store } from "./store";
|
import { store } from "./store";
|
||||||
import components from "@/components";
|
import components from "@/components";
|
||||||
import i18n from "./locales";
|
import i18n from "./locales";
|
||||||
|
import "element-plus/dist/index.css";
|
||||||
import "./styles/lib.scss";
|
import "./styles/lib.scss";
|
||||||
import "./styles/reset.scss";
|
import "./styles/reset.scss";
|
||||||
import ElementPlus from "element-plus";
|
import ElementPlus from "element-plus";
|
||||||
import "element-plus/dist/index.css";
|
|
||||||
|
|
||||||
const app = createApp(App);
|
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"),
|
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: {
|
meta: {
|
||||||
title: "dashboardEdit",
|
title: "dashboardEdit",
|
||||||
exact: false,
|
exact: false,
|
||||||
|
@ -26,6 +26,8 @@ export const NewControl = {
|
|||||||
},
|
},
|
||||||
graph: {},
|
graph: {},
|
||||||
standard: {},
|
standard: {},
|
||||||
|
metrics: [""],
|
||||||
|
metricTypes: [""],
|
||||||
};
|
};
|
||||||
export const ConfigData: any = {
|
export const ConfigData: any = {
|
||||||
x: 0,
|
x: 0,
|
||||||
@ -34,14 +36,64 @@ export const ConfigData: any = {
|
|||||||
h: 12,
|
h: 12,
|
||||||
i: "0",
|
i: "0",
|
||||||
metrics: ["service_resp_time"],
|
metrics: ["service_resp_time"],
|
||||||
queryMetricType: "readMetricsValues",
|
metricTypes: ["readMetricsValues"],
|
||||||
type: "Widget",
|
type: "Widget",
|
||||||
widget: {
|
widget: {
|
||||||
title: "Title",
|
title: "service_resp_time",
|
||||||
tips: "Tooltip",
|
tips: "Tooltip",
|
||||||
},
|
},
|
||||||
graph: {
|
graph: {
|
||||||
type: "Line",
|
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: {
|
standard: {
|
||||||
sortOrder: "DEC",
|
sortOrder: "DEC",
|
||||||
|
@ -18,10 +18,13 @@ import { defineStore } from "pinia";
|
|||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import { LayoutConfig } from "@/types/dashboard";
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
import graph from "@/graph";
|
import graph from "@/graph";
|
||||||
import { AxiosResponse } from "axios";
|
import { ConfigData, ConfigData1, ConfigData2 } from "../data";
|
||||||
import { ConfigData } from "../data";
|
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { NewControl } from "../data";
|
import { NewControl } from "../data";
|
||||||
|
import { Duration } from "@/types/app";
|
||||||
|
import axios, { AxiosResponse } from "axios";
|
||||||
|
import { cancelToken } from "@/utils/cancelToken";
|
||||||
interface DashboardState {
|
interface DashboardState {
|
||||||
showConfig: boolean;
|
showConfig: boolean;
|
||||||
layout: LayoutConfig[];
|
layout: LayoutConfig[];
|
||||||
@ -29,6 +32,8 @@ interface DashboardState {
|
|||||||
entity: string;
|
entity: string;
|
||||||
layerId: string;
|
layerId: string;
|
||||||
activedGridItem: string;
|
activedGridItem: string;
|
||||||
|
durationTime: Duration;
|
||||||
|
selectorStore: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dashboardStore = defineStore({
|
export const dashboardStore = defineStore({
|
||||||
@ -40,6 +45,8 @@ export const dashboardStore = defineStore({
|
|||||||
entity: "",
|
entity: "",
|
||||||
layerId: "",
|
layerId: "",
|
||||||
activedGridItem: "",
|
activedGridItem: "",
|
||||||
|
durationTime: useAppStoreWithOut().durationTime,
|
||||||
|
selectorStore: useSelectorStore(),
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setLayout(data: LayoutConfig[]) {
|
setLayout(data: LayoutConfig[]) {
|
||||||
@ -50,6 +57,8 @@ export const dashboardStore = defineStore({
|
|||||||
...NewControl,
|
...NewControl,
|
||||||
i: String(this.layout.length),
|
i: String(this.layout.length),
|
||||||
type,
|
type,
|
||||||
|
metricTypes: [""],
|
||||||
|
metrics: [""],
|
||||||
};
|
};
|
||||||
if (type === "Tab") {
|
if (type === "Tab") {
|
||||||
newWidget.h = 24;
|
newWidget.h = 24;
|
||||||
@ -129,14 +138,20 @@ export const dashboardStore = defineStore({
|
|||||||
setConfigPanel(show: boolean) {
|
setConfigPanel(show: boolean) {
|
||||||
this.showConfig = show;
|
this.showConfig = show;
|
||||||
},
|
},
|
||||||
selectWidget(widget: Nullable<LayoutConfig>) {
|
selectWidget(item: Nullable<LayoutConfig>) {
|
||||||
this.selectedGrid = widget;
|
this.selectedGrid = item;
|
||||||
},
|
},
|
||||||
setLayer(id: string) {
|
setLayer(id: string) {
|
||||||
this.layerId = id;
|
this.layerId = id;
|
||||||
},
|
},
|
||||||
setEntity(type: string) {
|
setEntity(type: string) {
|
||||||
this.entity = type;
|
this.entity = type;
|
||||||
|
if (type === "ServiceInstance") {
|
||||||
|
this.layout = [ConfigData1];
|
||||||
|
}
|
||||||
|
if (type === "Endpoint") {
|
||||||
|
this.layout = [ConfigData2];
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setConfigs(param: { [key: string]: unknown }) {
|
setConfigs(param: { [key: string]: unknown }) {
|
||||||
const actived = this.activedGridItem.split("-");
|
const actived = this.activedGridItem.split("-");
|
||||||
@ -165,29 +180,24 @@ export const dashboardStore = defineStore({
|
|||||||
|
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async fetchMetricValue(config: LayoutConfig) {
|
async fetchMetricList(regex: string) {
|
||||||
// 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,
|
|
||||||
};
|
|
||||||
const res: AxiosResponse = await graph
|
const res: AxiosResponse = await graph
|
||||||
.query(config.queryMetricType)
|
.query("queryMetrics")
|
||||||
.params(variable);
|
.params({ regex });
|
||||||
|
|
||||||
return res.data;
|
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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { defineStore } from "pinia";
|
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 { store } from "@/store";
|
||||||
import graph from "@/graph";
|
import graph from "@/graph";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
|
||||||
interface SelectorState {
|
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({
|
export const selectorStore = defineStore({
|
||||||
id: "selector",
|
id: "selector",
|
||||||
state: (): SelectorState => ({
|
state: (): SelectorState => ({
|
||||||
services: [],
|
services: [],
|
||||||
|
pods: [],
|
||||||
|
currentService: null,
|
||||||
|
currentPod: null,
|
||||||
|
currentDestService: null,
|
||||||
|
currentDestPod: null,
|
||||||
|
durationTime: useAppStoreWithOut().durationTime,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
|
setCurrentService(service: Service) {
|
||||||
|
this.currentService = service;
|
||||||
|
},
|
||||||
|
setCurrentPod(pod: Nullable<Instance | Endpoint>) {
|
||||||
|
this.currentPod = pod;
|
||||||
|
},
|
||||||
async fetchLayers(): Promise<AxiosResponse> {
|
async fetchLayers(): Promise<AxiosResponse> {
|
||||||
const res: AxiosResponse = await graph.query("queryLayers").params({});
|
const res: AxiosResponse = await graph.query("queryLayers").params({});
|
||||||
|
|
||||||
return res;
|
return res.data || {};
|
||||||
},
|
},
|
||||||
async fetchServices(layer: string): Promise<AxiosResponse> {
|
async fetchServices(layer: string): Promise<AxiosResponse> {
|
||||||
const res: AxiosResponse = await graph
|
const res: AxiosResponse = await graph
|
||||||
@ -41,30 +61,89 @@ export const selectorStore = defineStore({
|
|||||||
.params({ layer });
|
.params({ layer });
|
||||||
|
|
||||||
if (!res.data.errors) {
|
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;
|
serviceId: string;
|
||||||
duration: Duration;
|
}): Promise<Nullable<AxiosResponse>> {
|
||||||
}): Promise<AxiosResponse> {
|
const serviceId = param ? param.serviceId : this.currentService?.id;
|
||||||
const res: AxiosResponse = await graph
|
if (!serviceId) {
|
||||||
.query("queryInstances")
|
return null;
|
||||||
.params(params);
|
}
|
||||||
return res;
|
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: {
|
async getEndpoints(params?: {
|
||||||
keyword: string;
|
keyword?: string;
|
||||||
serviceId: string;
|
serviceId?: string;
|
||||||
}): Promise<AxiosResponse> {
|
}): Promise<Nullable<AxiosResponse>> {
|
||||||
|
if (!params) {
|
||||||
|
params = {};
|
||||||
|
}
|
||||||
if (!params.keyword) {
|
if (!params.keyword) {
|
||||||
params.keyword = "";
|
params.keyword = "";
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graph
|
const serviceId = params.serviceId || this.currentService?.id;
|
||||||
.query("queryEndpoints")
|
if (!serviceId) {
|
||||||
.params(params);
|
return null;
|
||||||
return res;
|
}
|
||||||
|
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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #3d444f;
|
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;
|
text-rendering: optimizeLegibility;
|
||||||
-ms-text-size-adjust: 100%;
|
text-size-adjust: 100%;
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
div,
|
div,
|
||||||
header,
|
header,
|
||||||
footer,
|
footer,
|
||||||
@ -53,6 +55,7 @@ a,
|
|||||||
img {
|
img {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
input,
|
input,
|
||||||
textarea,
|
textarea,
|
||||||
select,
|
select,
|
||||||
@ -60,41 +63,51 @@ button {
|
|||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 21px;
|
font-size: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h6 {
|
h6 {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul,
|
ul,
|
||||||
ol {
|
ol {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
-webkit-appearance: none;
|
appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
border-bottom: 1px solid #e0e0e0;
|
border-bottom: 1px solid #e0e0e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
@ -102,76 +115,11 @@ blockquote {
|
|||||||
border-left: 4px solid #cacaca;
|
border-left: 4px solid #cacaca;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-dialog__body {
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
code,
|
code,
|
||||||
pre {
|
pre {
|
||||||
font-family: Consolas, Menlo, Courier, monospace;
|
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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
export interface Option {
|
export interface Option {
|
||||||
value: string | number;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
export interface Duration {
|
export interface Duration {
|
||||||
|
@ -20,12 +20,12 @@ export interface LayoutConfig {
|
|||||||
w: number;
|
w: number;
|
||||||
h: number;
|
h: number;
|
||||||
i: string;
|
i: string;
|
||||||
widget?: WidgetConfig;
|
widget: WidgetConfig;
|
||||||
graph?: GraphConfig;
|
graph: GraphConfig;
|
||||||
standard?: StandardConfig;
|
standard: StandardConfig;
|
||||||
metrics?: string[];
|
metrics: string[];
|
||||||
type?: string;
|
type: string;
|
||||||
queryMetricType?: string;
|
metricTypes: string[];
|
||||||
children?: any;
|
children?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,9 +45,17 @@ export interface StandardConfig {
|
|||||||
divide?: string;
|
divide?: string;
|
||||||
milliseconds?: string;
|
milliseconds?: string;
|
||||||
seconds?: 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 {
|
export interface BarConfig {
|
||||||
type?: string;
|
type?: string;
|
||||||
showBackground?: boolean;
|
showBackground?: boolean;
|
||||||
@ -57,6 +65,8 @@ export interface LineConfig extends AreaConfig {
|
|||||||
smooth?: boolean;
|
smooth?: boolean;
|
||||||
showSymbol?: boolean;
|
showSymbol?: boolean;
|
||||||
step?: boolean;
|
step?: boolean;
|
||||||
|
showXAxis?: boolean;
|
||||||
|
showYAxis?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AreaConfig {
|
export interface AreaConfig {
|
||||||
@ -67,7 +77,8 @@ export interface AreaConfig {
|
|||||||
export interface CardConfig {
|
export interface CardConfig {
|
||||||
type?: string;
|
type?: string;
|
||||||
fontSize?: number;
|
fontSize?: number;
|
||||||
showUint: boolean;
|
showUint?: boolean;
|
||||||
|
textAlign?: "center" | "right" | "left";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableConfig {
|
export interface TableConfig {
|
||||||
@ -81,3 +92,21 @@ export interface TopListConfig {
|
|||||||
type?: string;
|
type?: string;
|
||||||
topN: number;
|
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>
|
<div class="about">{{ props.msg }}</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps } from "vue";
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
msg: String,
|
msg: String,
|
||||||
});
|
});
|
||||||
|
@ -18,23 +18,25 @@ limitations under the License. -->
|
|||||||
<grid-layout />
|
<grid-layout />
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="dashboardStore.showConfig"
|
v-model="dashboardStore.showConfig"
|
||||||
title="Edit Graph Options"
|
:title="t('editGraph')"
|
||||||
fullscreen
|
fullscreen
|
||||||
:destroy-on-close="true"
|
:destroy-on-close="true"
|
||||||
@closed="dashboardStore.setConfigPanel(false)"
|
@closed="dashboardStore.setConfigPanel(false)"
|
||||||
>
|
>
|
||||||
<widget-config />
|
<config-edit />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
import GridLayout from "./panel/Layout.vue";
|
import GridLayout from "./panel/Layout.vue";
|
||||||
// import { LayoutConfig } from "@/types/dashboard";
|
// import { LayoutConfig } from "@/types/dashboard";
|
||||||
import Tool from "./panel/Tool.vue";
|
import Tool from "./panel/Tool.vue";
|
||||||
import WidgetConfig from "./configuration/ConfigEdit.vue";
|
import ConfigEdit from "./configuration/ConfigEdit.vue";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
const { t } = useI18n();
|
||||||
// fetch layout data from serve side
|
// fetch layout data from serve side
|
||||||
// const layout: any[] = [
|
// const layout: any[] = [
|
||||||
// { x: 0, y: 0, w: 4, h: 12, i: "0" },
|
// { 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" },
|
// { x: 8, y: 27, w: 4, h: 15, i: "16" },
|
||||||
// ];
|
// ];
|
||||||
// dashboardStore.setLayout(layout);
|
// dashboardStore.setLayout(layout);
|
||||||
|
|
||||||
function handleClick(e: any) {
|
function handleClick(e: any) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (e.target.className === "ds-main") {
|
if (e.target.className === "ds-main") {
|
||||||
|
@ -26,8 +26,8 @@ limitations under the License. -->
|
|||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="label">{{ t("layer") }}</div>
|
<div class="label">{{ t("layer") }}</div>
|
||||||
<Selector
|
<Selector
|
||||||
:value="states.layer"
|
v-model="states.selectedLayer"
|
||||||
:options="Options"
|
:options="states.layers"
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="Select a layer"
|
placeholder="Select a layer"
|
||||||
@change="changeLayer"
|
@change="changeLayer"
|
||||||
@ -37,7 +37,7 @@ limitations under the License. -->
|
|||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="label">{{ t("entityType") }}</div>
|
<div class="label">{{ t("entityType") }}</div>
|
||||||
<Selector
|
<Selector
|
||||||
:value="states.entity"
|
v-model="states.entity"
|
||||||
:options="EntityType"
|
:options="EntityType"
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="Select a entity"
|
placeholder="Select a entity"
|
||||||
@ -53,28 +53,38 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive } from "vue";
|
import { reactive, onBeforeMount } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { EntityType, Options } from "./data";
|
import { EntityType } from "./data";
|
||||||
import uuid from "@/utils/uuid";
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
const states = reactive({
|
const states = reactive({
|
||||||
name: "",
|
name: "",
|
||||||
layer: Options[0].value,
|
selectedLayer: "",
|
||||||
entity: EntityType[0].value,
|
entity: EntityType[0].value,
|
||||||
|
layers: [],
|
||||||
});
|
});
|
||||||
const onCreate = () => {
|
const onCreate = () => {
|
||||||
const id = uuid();
|
const name = states.name.split(" ").join("-");
|
||||||
const path = `/dashboard/edit/${states.layer}/${states.entity}/${id}`;
|
const path = `/dashboard/${states.selectedLayer}/${states.entity}/${name}`;
|
||||||
router.push(path);
|
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 }[]) {
|
function changeLayer(opt: { label: string; value: string }[]) {
|
||||||
states.layer = opt[0].value;
|
states.selectedLayer = opt[0].value;
|
||||||
}
|
}
|
||||||
function changeEntity(opt: { label: string; value: string }[]) {
|
function changeEntity(opt: { label: string; value: string }[]) {
|
||||||
states.entity = opt[0].value;
|
states.entity = opt[0].value;
|
||||||
|
@ -14,23 +14,30 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="widget-config flex-v">
|
<div class="widget-config flex-v">
|
||||||
<div class="graph">
|
<div class="graph" v-loading="loading">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span>{{ states.widget.title }}</span>
|
<span>{{ dashboardStore.selectedGrid.widget.title }}</span>
|
||||||
<div class="tips" v-show="states.widget.tips">
|
<div class="tips" v-show="dashboardStore.selectedGrid.widget.tips">
|
||||||
<el-tooltip :content="states.widget.tips">
|
<el-tooltip :content="dashboardStore.selectedGrid.widget.tips">
|
||||||
<Icon iconName="info_outline" size="sm" />
|
<Icon iconName="info_outline" size="sm" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="render-chart">
|
<div class="render-chart">
|
||||||
<component
|
<component
|
||||||
:is="states.graph.type"
|
:is="dashboardStore.selectedGrid.graph.type"
|
||||||
:intervalTime="appStoreWithOut.intervalTime"
|
:intervalTime="appStoreWithOut.intervalTime"
|
||||||
:data="states.source"
|
: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>
|
</div>
|
||||||
<div class="collapse" :style="{ height: configHeight + 'px' }">
|
<div class="collapse" :style="{ height: configHeight + 'px' }">
|
||||||
@ -38,59 +45,17 @@ limitations under the License. -->
|
|||||||
v-model="states.activeNames"
|
v-model="states.activeNames"
|
||||||
:style="{ '--el-collapse-header-font-size': '15px' }"
|
:style="{ '--el-collapse-header-font-size': '15px' }"
|
||||||
>
|
>
|
||||||
<el-collapse-item :title="t('metricName')" name="1">
|
<el-collapse-item :title="t('selectVisualization')" name="1">
|
||||||
<div>
|
<MetricOptions @update="getSource" @loading="setLoading" />
|
||||||
<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>
|
</el-collapse-item>
|
||||||
<el-collapse-item :title="t('selectVisualization')" name="2">
|
<el-collapse-item :title="t('graphStyles')" name="2">
|
||||||
<div class="chart-types">
|
<component :is="`${dashboardStore.selectedGrid.graph.type}Config`" />
|
||||||
<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>
|
</el-collapse-item>
|
||||||
<el-collapse-item :title="t('graphStyles')" name="3">
|
<el-collapse-item :title="t('widgetOptions')" name="3">
|
||||||
<component
|
<WidgetOptions />
|
||||||
:is="`${states.graph.type}Config`"
|
|
||||||
:config="states.graph"
|
|
||||||
@update="updateGraphOptions"
|
|
||||||
/>
|
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
<el-collapse-item :title="t('widgetOptions')" name="4">
|
<el-collapse-item :title="t('standardOptions')" name="4">
|
||||||
<WidgetOptions
|
<StandardOptions />
|
||||||
: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>
|
</el-collapse-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
</div>
|
</div>
|
||||||
@ -109,19 +74,12 @@ import { reactive, defineComponent, ref } from "vue";
|
|||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import {
|
|
||||||
ValuesTypes,
|
|
||||||
MetricQueryTypes,
|
|
||||||
ChartTypes,
|
|
||||||
DefaultGraphConfig,
|
|
||||||
} from "../data";
|
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import { WidgetConfig, GraphConfig, StandardConfig } from "@/types/dashboard";
|
|
||||||
import graphs from "../graphs";
|
import graphs from "../graphs";
|
||||||
import configs from "./graph-styles";
|
import configs from "./graph-styles";
|
||||||
import WidgetOptions from "./WidgetOptions.vue";
|
import WidgetOptions from "./WidgetOptions.vue";
|
||||||
import StandardOptions from "./StandardOptions.vue";
|
import StandardOptions from "./StandardOptions.vue";
|
||||||
|
import MetricOptions from "./MetricOptions.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "ConfigEdit",
|
name: "ConfigEdit",
|
||||||
@ -130,166 +88,49 @@ export default defineComponent({
|
|||||||
...configs,
|
...configs,
|
||||||
WidgetOptions,
|
WidgetOptions,
|
||||||
StandardOptions,
|
StandardOptions,
|
||||||
|
MetricOptions,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const loading = ref<boolean>(false);
|
const configHeight = document.documentElement.clientHeight - 520;
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const appStoreWithOut = useAppStoreWithOut();
|
const appStoreWithOut = useAppStoreWithOut();
|
||||||
const { selectedGrid } = dashboardStore;
|
const loading = ref<boolean>(false);
|
||||||
const states = reactive<{
|
const states = reactive<{
|
||||||
metrics: string[];
|
|
||||||
valueTypes: Option[];
|
|
||||||
valueType: string;
|
|
||||||
metricQueryType: string;
|
|
||||||
activeNames: string;
|
activeNames: string;
|
||||||
source: any;
|
source: any;
|
||||||
index: string;
|
index: string;
|
||||||
graph: GraphConfig;
|
visType: Option[];
|
||||||
widget: WidgetConfig | any;
|
|
||||||
standard: StandardConfig;
|
|
||||||
}>({
|
}>({
|
||||||
metrics: selectedGrid.metrics || [],
|
|
||||||
valueTypes: [],
|
|
||||||
valueType: "",
|
|
||||||
metricQueryType: "",
|
|
||||||
activeNames: "1",
|
activeNames: "1",
|
||||||
source: {},
|
source: {},
|
||||||
index: selectedGrid.i,
|
index: dashboardStore.selectedGrid.i,
|
||||||
graph: selectedGrid.graph,
|
visType: [],
|
||||||
widget: selectedGrid.widget,
|
|
||||||
standard: selectedGrid.standard,
|
|
||||||
});
|
});
|
||||||
if (states.metrics[0]) {
|
|
||||||
queryMetricType(states.metrics[0]);
|
function getSource(source: unknown) {
|
||||||
|
states.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeMetrics(arr: Option[]) {
|
function setLoading(load: boolean) {
|
||||||
if (!arr.length) {
|
loading.value = load;
|
||||||
states.valueTypes = [];
|
|
||||||
states.valueType = "";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
states.metrics = arr.map((d: Option) => String(d.value));
|
|
||||||
if (arr[0].value) {
|
|
||||||
queryMetricType(String(arr[0].value));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
function applyConfig() {
|
||||||
const opts = {
|
dashboardStore.setConfigs(dashboardStore.selectedGrid);
|
||||||
...dashboardStore.selectedGrid,
|
|
||||||
metrics: states.metrics,
|
|
||||||
queryMetricType: states.valueType,
|
|
||||||
widget: states.widget,
|
|
||||||
graph: states.graph,
|
|
||||||
standard: states.standard,
|
|
||||||
};
|
|
||||||
dashboardStore.setConfigs(opts);
|
|
||||||
dashboardStore.setConfigPanel(false);
|
dashboardStore.setConfigPanel(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
states,
|
states,
|
||||||
changeChartType,
|
loading,
|
||||||
changeValueType,
|
|
||||||
changeMetrics,
|
|
||||||
t,
|
t,
|
||||||
appStoreWithOut,
|
appStoreWithOut,
|
||||||
ChartTypes,
|
|
||||||
metricOpts,
|
|
||||||
updateWidgetOptions,
|
|
||||||
configHeight,
|
configHeight,
|
||||||
updateGraphOptions,
|
dashboardStore,
|
||||||
updateStandardOptions,
|
|
||||||
applyConfig,
|
applyConfig,
|
||||||
loading,
|
getSource,
|
||||||
|
setLoading,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -326,7 +167,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
.render-chart {
|
.render-chart {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
height: 350px;
|
height: 400px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,30 +184,10 @@ export default defineComponent({
|
|||||||
min-width: 1280px;
|
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 {
|
.no-data {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 350px;
|
line-height: 400px;
|
||||||
}
|
|
||||||
|
|
||||||
span.active {
|
|
||||||
background-color: #409eff;
|
|
||||||
color: #fff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
@ -384,4 +205,8 @@ span.active {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ds-name {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
</style>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, defineProps, defineEmits } from "vue";
|
import { reactive } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { SortOrder } from "../data";
|
import { SortOrder } from "../data";
|
||||||
import { StandardConfig } from "@/types/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import type { PropType } from "vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
const dashboardStore = useDashboardStore();
|
||||||
config: {
|
const { selectedGrid } = dashboardStore;
|
||||||
type: Object as PropType<StandardConfig>,
|
|
||||||
default: () => ({ unit: "", sortOrder: "DES" }),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const emits = defineEmits(["update"]);
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
unit: props.config.unit,
|
unit: selectedGrid.standard.unit,
|
||||||
max: "",
|
max: "",
|
||||||
min: "",
|
min: "",
|
||||||
plus: "",
|
plus: "",
|
||||||
@ -140,11 +134,15 @@ const state = reactive({
|
|||||||
divide: "",
|
divide: "",
|
||||||
milliseconds: "",
|
milliseconds: "",
|
||||||
seconds: "",
|
seconds: "",
|
||||||
sortOrder: props.config.sortOrder,
|
sortOrder: selectedGrid.standard.sortOrder,
|
||||||
});
|
});
|
||||||
|
|
||||||
function changeStandardOpt(param: { [key: string]: unknown }) {
|
function changeStandardOpt(param: { [key: string]: unknown }) {
|
||||||
emits("update", param);
|
const standard = {
|
||||||
|
...selectedGrid.standard,
|
||||||
|
...param,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...selectedGrid, standard });
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -35,24 +35,22 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, defineEmits, defineProps } from "vue";
|
import { ref } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { WidgetConfig } from "@/types/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import type { PropType } from "vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
config: {
|
|
||||||
type: Object as PropType<WidgetConfig>,
|
|
||||||
default: () => ({ title: "", tooltips: "" }),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const emits = defineEmits(["update"]);
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const title = ref<string>(props.config.title || "");
|
const dashboardStore = useDashboardStore();
|
||||||
const tips = ref<string>(props.config.tips || "");
|
const { selectedGrid } = dashboardStore;
|
||||||
|
const title = ref<string>(selectedGrid.widget.title || "");
|
||||||
|
const tips = ref<string>(selectedGrid.widget.tips || "");
|
||||||
|
|
||||||
function updateWidgetConfig(param: { [key: string]: unknown }) {
|
function updateWidgetConfig(param: { [key: string]: unknown }) {
|
||||||
emits("update", param);
|
const widget = {
|
||||||
|
...selectedGrid.widget,
|
||||||
|
...param,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...selectedGrid, widget });
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -28,24 +28,22 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, ref, defineEmits } from "vue";
|
import { ref } from "vue";
|
||||||
import type { PropType } from "vue";
|
|
||||||
import { AreaConfig } from "@/types/dashboard";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const { selectedGrid } = dashboardStore;
|
||||||
|
|
||||||
const props = defineProps({
|
const opacity = ref(selectedGrid.graph.opacity);
|
||||||
config: {
|
|
||||||
type: Object as PropType<AreaConfig>,
|
|
||||||
default: () => ({ opacity: 0.4 }),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const emits = defineEmits(["update"]);
|
|
||||||
const opacity = ref(props.config.opacity);
|
|
||||||
|
|
||||||
function updateConfig(param: { [key: string]: unknown }) {
|
function updateConfig(param: { [key: string]: unknown }) {
|
||||||
emits("update", param);
|
const graph = {
|
||||||
|
...selectedGrid.graph,
|
||||||
|
...param,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -24,24 +24,21 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, ref, defineEmits } from "vue";
|
import { ref } from "vue";
|
||||||
import type { PropType } from "vue";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { BarConfig } from "@/types/dashboard";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
const props = defineProps({
|
const { selectedGrid } = dashboardStore;
|
||||||
config: {
|
const showBackground = ref(selectedGrid.graph.showBackground || false);
|
||||||
type: Object as PropType<BarConfig>,
|
|
||||||
default: () => ({ showBackground: true, barWidth: 30 }),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const emits = defineEmits(["update"]);
|
|
||||||
const showBackground = ref(props.config.showBackground || false);
|
|
||||||
|
|
||||||
function changeConfig(param: { [key: string]: unknown }) {
|
function changeConfig(param: { [key: string]: unknown }) {
|
||||||
emits("update", param);
|
const graph = {
|
||||||
|
...selectedGrid.graph,
|
||||||
|
...param,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -20,32 +20,29 @@ limitations under the License. -->
|
|||||||
v-model="fontSize"
|
v-model="fontSize"
|
||||||
show-input
|
show-input
|
||||||
input-size="small"
|
input-size="small"
|
||||||
:min="0.1"
|
:min="10"
|
||||||
:max="1"
|
:max="20"
|
||||||
:step="0.1"
|
:step="1"
|
||||||
@change="updateConfig({ fontSize })"
|
@change="updateConfig({ fontSize })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, ref, defineEmits } from "vue";
|
import { ref } from "vue";
|
||||||
import type { PropType } from "vue";
|
|
||||||
import { CardConfig } from "@/types/dashboard";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
const props = defineProps({
|
const { selectedGrid } = dashboardStore;
|
||||||
config: {
|
const fontSize = ref(selectedGrid.graph.fontSize);
|
||||||
type: Object as PropType<CardConfig>,
|
|
||||||
default: () => ({ fontSize: 12 }),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const emits = defineEmits(["update"]);
|
|
||||||
const fontSize = ref(props.config.fontSize);
|
|
||||||
|
|
||||||
function updateConfig(param: { [key: string]: unknown }) {
|
function updateConfig(param: { [key: string]: unknown }) {
|
||||||
emits("update", param);
|
const graph = {
|
||||||
|
...selectedGrid.graph,
|
||||||
|
...param,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, ref, defineEmits } from "vue";
|
import { ref } from "vue";
|
||||||
import type { PropType } from "vue";
|
|
||||||
import { LineConfig } from "@/types/dashboard";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const dashboardStore = useDashboardStore();
|
||||||
config: {
|
const { selectedGrid } = dashboardStore;
|
||||||
type: Object as PropType<LineConfig>,
|
const smooth = ref(selectedGrid.graph.smooth);
|
||||||
default: () => ({}),
|
const showSymbol = ref(selectedGrid.graph.showSymbol);
|
||||||
},
|
const step = ref(selectedGrid.graph.step);
|
||||||
});
|
|
||||||
const emits = defineEmits(["update"]);
|
|
||||||
const smooth = ref(props.config.smooth);
|
|
||||||
const showSymbol = ref(props.config.showSymbol);
|
|
||||||
const step = ref(props.config.step);
|
|
||||||
|
|
||||||
function updateConfig(param: { [key: string]: unknown }) {
|
function updateConfig(param: { [key: string]: unknown }) {
|
||||||
emits("update", param);
|
const graph = {
|
||||||
|
...selectedGrid.graph,
|
||||||
|
...param,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, ref, defineEmits } from "vue";
|
import { ref } from "vue";
|
||||||
import type { PropType } from "vue";
|
|
||||||
import { TableConfig } from "@/types/dashboard";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const dashboardStore = useDashboardStore();
|
||||||
config: {
|
const { selectedGrid } = dashboardStore;
|
||||||
type: Object as PropType<TableConfig>,
|
const showTableValues = ref(selectedGrid.graph.showTableValues);
|
||||||
default: () => ({
|
const tableHeaderCol1 = ref(selectedGrid.graph.tableHeaderCol1);
|
||||||
showTableValues: true,
|
const tableHeaderCol2 = ref(selectedGrid.graph.tableHeaderCol2);
|
||||||
tableHeaderCol1: "",
|
|
||||||
tableHeaderCol2: "",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const emits = defineEmits(["update"]);
|
|
||||||
const showTableValues = ref(props.config.showTableValues);
|
|
||||||
const tableHeaderCol1 = ref(props.config.tableHeaderCol1);
|
|
||||||
const tableHeaderCol2 = ref(props.config.tableHeaderCol2);
|
|
||||||
|
|
||||||
function updateConfig(param: { [key: string]: unknown }) {
|
function updateConfig(param: { [key: string]: unknown }) {
|
||||||
emits("update", param);
|
const graph = {
|
||||||
|
...selectedGrid.graph,
|
||||||
|
...param,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -28,25 +28,21 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, ref, defineEmits } from "vue";
|
import { ref } from "vue";
|
||||||
import type { PropType } from "vue";
|
|
||||||
import { TopListConfig } from "@/types/dashboard";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const dashboardStore = useDashboardStore();
|
||||||
config: {
|
const { selectedGrid } = dashboardStore;
|
||||||
type: Object as PropType<TopListConfig>,
|
const topN = ref(selectedGrid.graph.topN);
|
||||||
default: () => ({
|
|
||||||
topN: 10,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const emits = defineEmits(["update"]);
|
|
||||||
const topN = ref(props.config.topN);
|
|
||||||
|
|
||||||
function updateConfig(param: { [key: string]: unknown }) {
|
function updateConfig(param: { [key: string]: unknown }) {
|
||||||
emits("update", param);
|
const graph = {
|
||||||
|
...selectedGrid.graph,
|
||||||
|
...param,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -18,9 +18,21 @@
|
|||||||
import AreaConfig from "./Area.vue";
|
import AreaConfig from "./Area.vue";
|
||||||
import LineConfig from "./Line.vue";
|
import LineConfig from "./Line.vue";
|
||||||
import BarConfig from "./Bar.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 {
|
export default {
|
||||||
AreaConfig,
|
AreaConfig,
|
||||||
LineConfig,
|
LineConfig,
|
||||||
BarConfig,
|
BarConfig,
|
||||||
|
InstanceListConfig,
|
||||||
|
EndpointListConfig,
|
||||||
|
ServiceListConfig,
|
||||||
|
TableConfig,
|
||||||
|
CardConfig,
|
||||||
|
TopListConfig,
|
||||||
};
|
};
|
||||||
|
@ -84,12 +84,12 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, reactive, ref, watch } from "vue";
|
import { ref, watch, reactive } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import Widget from "./Widget.vue";
|
import Widget from "./Widget.vue";
|
||||||
import { LayoutConfig } from "@/types/dashboard";
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<LayoutConfig>,
|
type: Object as PropType<LayoutConfig>,
|
||||||
@ -150,9 +150,12 @@ function clickTabGrid(e: Event, item: LayoutConfig) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
document.body.addEventListener("click", handleClick, false);
|
document.body.addEventListener("click", handleClick, false);
|
||||||
|
|
||||||
|
const children = ref(
|
||||||
|
dashboardStore.layout[props.data.i].children[activeTabIndex.value].children
|
||||||
|
);
|
||||||
watch(
|
watch(
|
||||||
() =>
|
() => children.value,
|
||||||
dashboardStore.layout[props.data.i].children[activeTabIndex.value].children,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
state.layout = data;
|
state.layout = data;
|
||||||
}
|
}
|
||||||
|
@ -45,9 +45,14 @@ limitations under the License. -->
|
|||||||
<div class="body" v-if="data.graph?.type" v-loading="loading">
|
<div class="body" v-if="data.graph?.type" v-loading="loading">
|
||||||
<component
|
<component
|
||||||
:is="data.graph.type"
|
:is="data.graph.type"
|
||||||
:intervalTime="appStoreWithOut.intervalTime"
|
:intervalTime="appStore.intervalTime"
|
||||||
:data="state.source"
|
:data="state.source"
|
||||||
:config="data.graph"
|
:config="{
|
||||||
|
...data.graph,
|
||||||
|
metrics: data.metrics,
|
||||||
|
metricTypes: data.metricTypes,
|
||||||
|
i: data.i,
|
||||||
|
}"
|
||||||
:standard="data.standard"
|
:standard="data.standard"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -60,9 +65,11 @@ import type { PropType } from "vue";
|
|||||||
import { LayoutConfig } from "@/types/dashboard";
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import graphs from "../graphs";
|
import graphs from "../graphs";
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useQueryProcessor, useSourceProcessor } from "@/hooks/useProcessor";
|
||||||
|
import { EntityType, TableChartTypes } from "../data";
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
data: {
|
data: {
|
||||||
@ -78,34 +85,27 @@ export default defineComponent({
|
|||||||
setup(props) {
|
setup(props) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
const state = reactive({
|
const state = reactive<{ source: { [key: string]: unknown } }>({
|
||||||
source: {},
|
source: {},
|
||||||
});
|
});
|
||||||
const { data } = toRefs(props);
|
const { data } = toRefs(props);
|
||||||
const appStoreWithOut = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
queryMetrics();
|
const selectorStore = useSelectorStore();
|
||||||
|
|
||||||
async function queryMetrics() {
|
async function queryMetrics() {
|
||||||
|
const params = await useQueryProcessor(props.data);
|
||||||
|
if (!params) {
|
||||||
|
state.source = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const json = await dashboardStore.fetchMetricValue(props.data);
|
const json = await dashboardStore.fetchMetricValue(params);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
if (!json) {
|
if (!json) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (json.error) {
|
state.source = useSourceProcessor(json, props.data);
|
||||||
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,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeWidget() {
|
function removeWidget() {
|
||||||
@ -121,17 +121,41 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
watch(
|
watch(
|
||||||
() => [props.data.queryMetricType, props.data.metrics],
|
() => [props.data.metricTypes, props.data.metrics],
|
||||||
(data, old) => {
|
() => {
|
||||||
if (data[0] === old[0] && data[1] === old[1]) {
|
if (props.data.i !== dashboardStore.selectedGrid.i) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (TableChartTypes.includes(dashboardStore.selectedGrid.graph.type)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
queryMetrics();
|
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 {
|
return {
|
||||||
state,
|
state,
|
||||||
appStoreWithOut,
|
appStore,
|
||||||
removeWidget,
|
removeWidget,
|
||||||
editConfig,
|
editConfig,
|
||||||
data,
|
data,
|
||||||
|
@ -14,18 +14,36 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export const PodsChartTypes = ["EndpointList", "InstanceList"];
|
||||||
|
|
||||||
|
export const TableChartTypes = ["EndpointList", "InstanceList", "ServiceList"];
|
||||||
|
|
||||||
export const ChartTypes = [
|
export const ChartTypes = [
|
||||||
{ label: "Bar", value: "Bar" },
|
{ label: "Bar", value: "Bar" },
|
||||||
{ label: "Line", value: "Line" },
|
{ label: "Line", value: "Line" },
|
||||||
{ label: "Area", value: "Area" },
|
{ label: "Area", value: "Area" },
|
||||||
{ label: "Heatmap", value: "Heatmap" },
|
// { label: "Pie", value: "Pie" },
|
||||||
{ label: "Pie", value: "Pie" },
|
|
||||||
{ label: "Card", value: "Card" },
|
{ label: "Card", value: "Card" },
|
||||||
{ label: "Top List", value: "TopList" },
|
{ label: "Top List", value: "TopList" },
|
||||||
{ label: "Table", value: "Table" },
|
{ label: "Table", value: "Table" },
|
||||||
|
{ label: "Heatmap", value: "Heatmap" },
|
||||||
|
{ label: "Service List", value: "ServiceList" },
|
||||||
{ label: "Endpoint List", value: "EndpointList" },
|
{ label: "Endpoint List", value: "EndpointList" },
|
||||||
{ label: "Instance List", value: "InstanceList" },
|
{ 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 } = {
|
export const DefaultGraphConfig: { [key: string]: any } = {
|
||||||
Bar: {
|
Bar: {
|
||||||
type: "Bar",
|
type: "Bar",
|
||||||
@ -36,36 +54,47 @@ export const DefaultGraphConfig: { [key: string]: any } = {
|
|||||||
step: false,
|
step: false,
|
||||||
smooth: false,
|
smooth: false,
|
||||||
showSymbol: false,
|
showSymbol: false,
|
||||||
|
showXAxis: true,
|
||||||
|
showYAxis: true,
|
||||||
},
|
},
|
||||||
Area: {
|
Area: {
|
||||||
type: "Area",
|
type: "Area",
|
||||||
opacity: 0.4,
|
opacity: 0.4,
|
||||||
|
showXAxis: true,
|
||||||
|
showYAxis: true,
|
||||||
},
|
},
|
||||||
Card: {
|
Card: {
|
||||||
type: "Card",
|
type: "Card",
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
textAlign: "center",
|
||||||
showUint: true,
|
showUint: true,
|
||||||
},
|
},
|
||||||
Table: {
|
Table: {
|
||||||
type: "Card",
|
type: "Table",
|
||||||
showTableValues: true,
|
showTableValues: true,
|
||||||
tableHeaderCol1: "",
|
tableHeaderCol1: "",
|
||||||
tableHeaderCol2: "",
|
tableHeaderCol2: "",
|
||||||
},
|
},
|
||||||
TopList: {
|
TopList: {
|
||||||
type: "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 {
|
export enum MetricsType {
|
||||||
UNKNOWN = "UNKNOWN",
|
UNKNOWN = "UNKNOWN",
|
||||||
REGULAR_VALUE = "REGULAR_VALUE",
|
REGULAR_VALUE = "REGULAR_VALUE",
|
||||||
@ -73,7 +102,7 @@ export enum MetricsType {
|
|||||||
HEATMAP = "HEATMAP",
|
HEATMAP = "HEATMAP",
|
||||||
SAMPLED_RECORD = "SAMPLED_RECORD",
|
SAMPLED_RECORD = "SAMPLED_RECORD",
|
||||||
}
|
}
|
||||||
export const ValuesTypes: {
|
export const MetricTypes: {
|
||||||
[key: string]: Array<{ label: string; value: string }>;
|
[key: string]: Array<{ label: string; value: string }>;
|
||||||
} = {
|
} = {
|
||||||
REGULAR_VALUE: [
|
REGULAR_VALUE: [
|
||||||
@ -97,55 +126,40 @@ export const ValuesTypes: {
|
|||||||
{ label: "get sorted topN values", value: "readSampledRecords" },
|
{ 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 MetricCatalog {
|
||||||
|
SERVICE = "Service",
|
||||||
export enum MetricsName {
|
SERVICE_INSTANCE = "ServiceInstance",
|
||||||
SERVICE_RESP_TIME = "service_resp_time",
|
ENDPOINT = "Endpoint",
|
||||||
SERVICE_SLA = "service_sla",
|
ALL = "All",
|
||||||
SERVICE_CPM = "service_cpm",
|
SERVICE_RELATION = "ServiceRelation",
|
||||||
SERVICE_PERCENTILE = "service_percentile",
|
SERVICE_INSTANCE_RELATION = "ServiceInstanceRelation",
|
||||||
SERVICE_APDEX = "service_apdex",
|
ENDPOINT_RELATION = "EndpointRelation",
|
||||||
}
|
}
|
||||||
export const EntityType = [
|
export const EntityType = [
|
||||||
{ value: "service", label: "Service", key: 1 },
|
{ value: "Service", label: "Service", key: 1 },
|
||||||
{ value: "all", label: "All", key: 10 },
|
{ value: "All", label: "All", key: 10 },
|
||||||
{ value: "endpoint", label: "Service Endpoint", key: 3 },
|
{ value: "Endpoint", label: "Service Endpoint", key: 3 },
|
||||||
{ value: "serviceInstance", label: "Service Instance", key: 3 },
|
{ value: "ServiceInstance", label: "Service Instance", key: 3 },
|
||||||
{ value: "serviceRelationClient", label: "Service Relation(client)", key: 2 },
|
{ value: "ServiceRelationClient", label: "Service Relation(client)", key: 2 },
|
||||||
{ value: "serviceRelationServer", label: "Service Relation(server)", key: 2 },
|
{ value: "ServiceRelationServer", label: "Service Relation(server)", key: 2 },
|
||||||
{
|
{
|
||||||
value: "serviceInstanceRelationClient",
|
value: "ServiceInstanceRelationClient",
|
||||||
label: "Service Instance Relation(client)",
|
label: "Service Instance Relation(client)",
|
||||||
key: 4,
|
key: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "serviceInstanceRelationServer",
|
value: "ServiceInstanceRelationServer",
|
||||||
label: "Service Instance Relation(server)",
|
label: "Service Instance Relation(server)",
|
||||||
key: 4,
|
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 = [
|
export const SortOrder = [
|
||||||
{ label: "DES", value: "DES" },
|
{ label: "DES", value: "DES" },
|
||||||
{ label: "ASC", value: "ASC" },
|
{ label: "ASC", value: "ASC" },
|
||||||
@ -159,69 +173,3 @@ export const ToolIcons = [
|
|||||||
{ name: "settings", content: "Settings", id: "settings" },
|
{ name: "settings", content: "Settings", id: "settings" },
|
||||||
{ name: "save", content: "Apply", id: "applay" },
|
{ 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" />
|
<Line :data="data" :intervalTime="intervalTime" :config="config" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps } from "vue";
|
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import Line from "./Line.vue";
|
import Line from "./Line.vue";
|
||||||
import { AreaConfig } from "@/types/dashboard";
|
import { AreaConfig } from "@/types/dashboard";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
defineProps({
|
defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number[] }>,
|
type: Object as PropType<{ [key: string]: number[] }>,
|
||||||
|
@ -16,11 +16,12 @@ limitations under the License. -->
|
|||||||
<Graph :option="option" />
|
<Graph :option="option" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { Event } from "@/types/events";
|
import { Event } from "@/types/events";
|
||||||
import { BarConfig } from "@/types/dashboard";
|
import { BarConfig } from "@/types/dashboard";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number[] }>,
|
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. -->
|
limitations under the License. -->
|
||||||
|
|
||||||
<template>
|
<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"
|
typeof singleVal === "string"
|
||||||
? data[key]
|
? singleVal
|
||||||
: isNaN(data[key])
|
: isNaN(singleVal)
|
||||||
? null
|
? null
|
||||||
: data[key].toFixed(2)
|
: singleVal.toFixed(2)
|
||||||
}}
|
}}
|
||||||
<span v-show="config.showUint">{{ standard.unit }}</span>
|
<span v-show="config.showUint">{{ standard.unit }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, PropType } from "vue";
|
import { computed, PropType } from "vue";
|
||||||
import { defineProps } from "vue";
|
|
||||||
import { CardConfig, StandardConfig } from "@/types/dashboard";
|
import { CardConfig, StandardConfig } from "@/types/dashboard";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number }>,
|
type: Object as PropType<{ [key: string]: number }>,
|
||||||
@ -37,7 +40,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<CardConfig>,
|
type: Object as PropType<CardConfig>,
|
||||||
default: () => ({ fontSize: 12, showUint: true }),
|
default: () => ({ fontSize: 12, showUint: true, textAlign: "center" }),
|
||||||
},
|
},
|
||||||
standard: {
|
standard: {
|
||||||
type: Object as PropType<StandardConfig>,
|
type: Object as PropType<StandardConfig>,
|
||||||
@ -45,10 +48,16 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const key = computed(() => Object.keys(props.data)[0]);
|
const key = computed(() => Object.keys(props.data)[0]);
|
||||||
|
const singleVal = computed(() => props.data[key.value]);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.chart-card {
|
.chart-card {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: horizontal;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</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
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<el-table :data="data" style="width: 100%">
|
<div class="table">
|
||||||
<el-table-column prop="label" label="Endpoints" />
|
<div class="search">
|
||||||
</el-table>
|
<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>
|
</template>
|
||||||
<script setup lang="ts">
|
<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 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: {
|
data: {
|
||||||
type: Array as PropType<{ label: string; value: string }[]>,
|
type: Object,
|
||||||
default: () => [],
|
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
type: Object,
|
type: Object as PropType<
|
||||||
default: () => ({}),
|
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>
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "./style.scss";
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
height: 39px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -16,10 +16,11 @@ limitations under the License. -->
|
|||||||
<Graph :option="option" />
|
<Graph :option="option" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { StandardConfig } from "@/types/dashboard";
|
import { StandardConfig } from "@/types/dashboard";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ nodes: number[][]; buckets: number[][] }>,
|
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
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<el-table :data="data" style="width: 100%">
|
<div class="table">
|
||||||
<el-table-column prop="label" label="Service Instances" />
|
<div class="search">
|
||||||
</el-table>
|
<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>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps } from "vue";
|
import { ref, watch } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
import type { PropType } from "vue";
|
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({
|
/*global defineProps */
|
||||||
data: {
|
const props = defineProps({
|
||||||
type: Array as PropType<{ label: string; value: string }[]>,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
config: {
|
config: {
|
||||||
type: Object,
|
type: Object as PropType<
|
||||||
default: () => ({}),
|
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>
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "./style.scss";
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -16,11 +16,12 @@ limitations under the License. -->
|
|||||||
<Graph :option="option" />
|
<Graph :option="option" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { Event } from "@/types/events";
|
import { Event } from "@/types/events";
|
||||||
import { LineConfig } from "@/types/dashboard";
|
import { LineConfig } from "@/types/dashboard";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number[] }>,
|
type: Object as PropType<{ [key: string]: number[] }>,
|
||||||
@ -36,6 +37,8 @@ const props = defineProps({
|
|||||||
smooth: false,
|
smooth: false,
|
||||||
showSymbol: false,
|
showSymbol: false,
|
||||||
opacity: 0.4,
|
opacity: 0.4,
|
||||||
|
showXAxis: true,
|
||||||
|
showYAxis: true,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -142,6 +145,8 @@ function getOption() {
|
|||||||
color,
|
color,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
|
zlevel: 1000,
|
||||||
|
z: 60,
|
||||||
backgroundColor: "rgb(50,50,50)",
|
backgroundColor: "rgb(50,50,50)",
|
||||||
textStyle: {
|
textStyle: {
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
@ -170,6 +175,7 @@ function getOption() {
|
|||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: "category",
|
type: "category",
|
||||||
|
show: props.config.showXAxis,
|
||||||
axisTick: {
|
axisTick: {
|
||||||
lineStyle: { color: "#c1c5ca41" },
|
lineStyle: { color: "#c1c5ca41" },
|
||||||
alignWithLabel: true,
|
alignWithLabel: true,
|
||||||
@ -183,7 +189,11 @@ function getOption() {
|
|||||||
axisLine: { show: false },
|
axisLine: { show: false },
|
||||||
axisTick: { show: false },
|
axisTick: { show: false },
|
||||||
splitLine: { lineStyle: { color: "#c1c5ca41", type: "dashed" } },
|
splitLine: { lineStyle: { color: "#c1c5ca41", type: "dashed" } },
|
||||||
axisLabel: { color: "#9da5b2", fontSize: "11" },
|
axisLabel: {
|
||||||
|
color: "#9da5b2",
|
||||||
|
fontSize: "11",
|
||||||
|
show: props.config.showYAxis,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
series: temp,
|
series: temp,
|
||||||
};
|
};
|
||||||
|
@ -16,9 +16,10 @@ limitations under the License. -->
|
|||||||
<Graph :option="option" />
|
<Graph :option="option" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Array as PropType<{ name: string; value: number }[]>,
|
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`">
|
<div class="name" :style="`width: ${nameWidth}px`">
|
||||||
{{ config.tableHeaderCol1 || $t("name") }}
|
{{ config.tableHeaderCol1 || $t("name") }}
|
||||||
<i class="r cp" ref="draggerName"
|
<i class="r cp" ref="draggerName">
|
||||||
><rk-icon icon="settings_ethernet"
|
<Icon iconName="settings_ethernet" size="middle" />
|
||||||
/></i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div class="value-col" v-if="config.showTableValues">
|
<div class="value-col" v-if="config.showTableValues">
|
||||||
{{ config.tableHeaderCol2 || $t("value") }}
|
{{ config.tableHeaderCol2 || $t("value") }}
|
||||||
@ -45,11 +45,12 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, computed, ref, onMounted } from "vue";
|
import { computed, ref, onMounted } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number[][] }>,
|
type: Object as PropType<{ [key: string]: number[] }>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
|
@ -14,57 +14,68 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chart-slow-i" v-for="(i, index) in datas" :key="index">
|
<div class="top-list">
|
||||||
<Icon
|
<div class="chart-slow-i" v-for="(i, index) in datas" :key="index">
|
||||||
iconName="review-list"
|
<div class="ell tools flex-h">
|
||||||
size="sm"
|
<div>
|
||||||
@click="handleClick((i.traceIds && i.traceIds[0]) || i.name)"
|
<span class="calls mr-10">{{ i.value }}</span>
|
||||||
/>
|
<span class="cp mr-20">
|
||||||
<div class="mb-5 ell">
|
{{ i.name + getTraceId(i) }}
|
||||||
<span class="calls sm mr-10">{{ i.value }}</span>
|
</span>
|
||||||
<span class="cp link-hover">
|
</div>
|
||||||
{{ i.name + getTraceId(i) }}
|
<div>
|
||||||
</span>
|
<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>
|
</div>
|
||||||
<el-progress
|
|
||||||
:stroke-width="10"
|
|
||||||
:percentage="(i.value / maxValue) * 100"
|
|
||||||
color="#bf99f8"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { defineProps, computed } from "vue";
|
import { computed } from "vue";
|
||||||
import copy from "@/utils/copy";
|
import copy from "@/utils/copy";
|
||||||
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Array as PropType<
|
type: Object as PropType<{
|
||||||
{ name: string; value: number; traceIds: string[] }[]
|
[key: string]: { name: string; value: number; traceIds: string[] }[];
|
||||||
>,
|
}>,
|
||||||
default: () => [],
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<{ sortOrder: string }>,
|
type: Object as PropType<{ sortOrder: string }>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
});
|
});
|
||||||
|
const key = computed(() => Object.keys(props.data)[0]);
|
||||||
const maxValue = computed(() => {
|
const maxValue = computed(() => {
|
||||||
if (!props.data.length) {
|
if (!(props.data[key.value] && props.data[key.value].length)) {
|
||||||
return 0;
|
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);
|
return Math.max.apply(null, temp);
|
||||||
});
|
});
|
||||||
const getTraceId = (i: { [key: string]: (number | string)[] }): string => {
|
const getTraceId = (i: { [key: string]: (number | string)[] }): string => {
|
||||||
return i.traceIds && i.traceIds[0] ? ` - ${i.traceIds[0]}` : "";
|
return i.traceIds && i.traceIds[0] ? ` - ${i.traceIds[0]}` : "";
|
||||||
};
|
};
|
||||||
const datas: any = () => {
|
const datas = computed(() => {
|
||||||
if (!props.data.length) {
|
if (!(props.data[key.value] && props.data[key.value].length)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const { sortOrder } = props.config;
|
const { sortOrder } = props.config;
|
||||||
const val: any = props.data;
|
const val: any = props.data[key.value];
|
||||||
|
|
||||||
switch (sortOrder) {
|
switch (sortOrder) {
|
||||||
case "DES":
|
case "DES":
|
||||||
@ -74,17 +85,29 @@ const datas: any = () => {
|
|||||||
val.sort((a: any, b: any) => a.value - b.value);
|
val.sort((a: any, b: any) => a.value - b.value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
val.sort((a: any, b: any) => b.value - a.value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
};
|
});
|
||||||
function handleClick(i: string) {
|
function handleClick(i: string) {
|
||||||
copy(i);
|
copy(i);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.top-list {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,14 +117,15 @@ function handleClick(i: string) {
|
|||||||
|
|
||||||
.chart-slow {
|
.chart-slow {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.calls {
|
.calls {
|
||||||
padding: 0 5px;
|
font-size: 12px;
|
||||||
display: inline-block;
|
padding: 0 5px;
|
||||||
background-color: #40454e;
|
display: inline-block;
|
||||||
color: #eee;
|
background-color: #40454e;
|
||||||
border-radius: 4px;
|
color: #eee;
|
||||||
}
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-slow-link {
|
.chart-slow-link {
|
||||||
|
@ -23,6 +23,9 @@ import TopList from "./TopList.vue";
|
|||||||
import Table from "./Table.vue";
|
import Table from "./Table.vue";
|
||||||
import Pie from "./Pie.vue";
|
import Pie from "./Pie.vue";
|
||||||
import Card from "./Card.vue";
|
import Card from "./Card.vue";
|
||||||
|
import InstanceList from "./InstanceList.vue";
|
||||||
|
import EndpointList from "./EndpointList.vue";
|
||||||
|
import ServiceList from "./ServiceList.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Line,
|
Line,
|
||||||
@ -33,4 +36,7 @@ export default {
|
|||||||
Table,
|
Table,
|
||||||
Pie,
|
Pie,
|
||||||
Card,
|
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>
|
<template>
|
||||||
<div class="dashboard-tool flex-h">
|
<div class="dashboard-tool flex-h">
|
||||||
<div class="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>
|
<span class="label">$Service</span>
|
||||||
<Selector
|
<Selector
|
||||||
:value="states.service"
|
v-model="states.currentService"
|
||||||
:options="Options"
|
:options="selectorStore.services"
|
||||||
size="mini"
|
size="mini"
|
||||||
placeholder="Select a service"
|
placeholder="Select a service"
|
||||||
@change="changeService"
|
@change="changeService"
|
||||||
class="selectors"
|
class="selectors"
|
||||||
:borderRadius="4"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="states.key === 3 || states.key === 4">
|
<div class="selectors-item" v-if="states.key === 3 || states.key === 4">
|
||||||
<span class="label">$ServiceInstance</span>
|
<span class="label">
|
||||||
<el-cascader
|
{{
|
||||||
placeholder="Select a instance"
|
dashboardStore.entity === "Endpoint"
|
||||||
:options="SelectOpts"
|
? "$Endpoint"
|
||||||
|
: "$ServiceInstance"
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
<Selector
|
||||||
|
v-model="states.currentPod"
|
||||||
|
:options="selectorStore.pods"
|
||||||
size="mini"
|
size="mini"
|
||||||
filterable
|
placeholder="Select a data"
|
||||||
:style="{ minWidth: '300px' }"
|
@change="changePods"
|
||||||
|
class="selectors"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="states.key === 2">
|
<div class="selectors-item" v-if="states.key === 2">
|
||||||
<span class="label">$DestinationService</span>
|
<span class="label">$DestinationService</span>
|
||||||
<Selector
|
<Selector
|
||||||
:value="states.service"
|
v-model="selectorStore.currentDestService"
|
||||||
:options="Options"
|
:options="selectorStore.services"
|
||||||
size="mini"
|
size="mini"
|
||||||
placeholder="Select a service"
|
placeholder="Select a service"
|
||||||
:borderRadius="0"
|
|
||||||
@change="changeService"
|
@change="changeService"
|
||||||
class="selectors"
|
class="selectors"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="states.key === 4">
|
<div class="selectors-item" v-if="states.key === 4">
|
||||||
<span class="label">$DestinationServiceInstance</span>
|
<span class="label">$DestinationServiceInstance</span>
|
||||||
<el-cascader
|
<Selector
|
||||||
placeholder="Select a instance"
|
v-model="states.currentPod"
|
||||||
:options="SelectOpts"
|
:options="selectorStore.pods"
|
||||||
size="mini"
|
size="mini"
|
||||||
filterable
|
placeholder="Select a data"
|
||||||
:style="{ minWidth: '300px' }"
|
@change="changePods"
|
||||||
|
class="selectors"
|
||||||
|
:borderRadius="4"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -80,33 +87,96 @@ limitations under the License. -->
|
|||||||
import { reactive } from "vue";
|
import { reactive } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { 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 dashboardStore = useDashboardStore();
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
const params = useRoute().params;
|
const params = useRoute().params;
|
||||||
|
const type = EntityType.filter((d: Option) => d.value === params.entity)[0];
|
||||||
const states = reactive<{
|
const states = reactive<{
|
||||||
entity: string | string[];
|
|
||||||
layerId: string | string[];
|
|
||||||
service: string;
|
|
||||||
pod: string;
|
|
||||||
destService: string;
|
destService: string;
|
||||||
destPod: string;
|
destPod: string;
|
||||||
key: number;
|
key: number;
|
||||||
|
currentService: string;
|
||||||
|
currentPod: string;
|
||||||
}>({
|
}>({
|
||||||
service: Options[0].value,
|
|
||||||
pod: Options[0].value, // instances and endpoints
|
|
||||||
destService: "",
|
destService: "",
|
||||||
destPod: "",
|
destPod: "",
|
||||||
key: EntityType.filter((d: any) => d.value === params.entity)[0].key || 0,
|
key: (type && type.key) || 0,
|
||||||
entity: params.entity,
|
currentService: "",
|
||||||
layerId: params.layerId,
|
currentPod: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
dashboardStore.setLayer(states.layerId);
|
dashboardStore.setLayer(String(params.layerId));
|
||||||
dashboardStore.setEntity(states.entity);
|
dashboardStore.setEntity(String(params.entity));
|
||||||
|
|
||||||
function changeService(val: { value: string; label: string }) {
|
if (params.serviceId) {
|
||||||
states.service = val.value;
|
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 }) {
|
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");
|
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>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.dashboard-tool {
|
.dashboard-tool {
|
||||||
|
@ -17,7 +17,7 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps } from "vue";
|
/*global defineProps */
|
||||||
defineProps({
|
defineProps({
|
||||||
msg: { type: String },
|
msg: { type: String },
|
||||||
});
|
});
|
||||||
|
@ -17,7 +17,7 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps } from "vue";
|
/*global defineProps */
|
||||||
defineProps({
|
defineProps({
|
||||||
msg: { type: String },
|
msg: { type: String },
|
||||||
});
|
});
|
||||||
|
@ -17,7 +17,7 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps } from "vue";
|
/*global defineProps */
|
||||||
defineProps({
|
defineProps({
|
||||||
msg: { type: String },
|
msg: { type: String },
|
||||||
});
|
});
|
||||||
|
@ -40,9 +40,19 @@ module.exports = {
|
|||||||
chunks: "all",
|
chunks: "all",
|
||||||
cacheGroups: {
|
cacheGroups: {
|
||||||
echarts: {
|
echarts: {
|
||||||
|
name: "echarts",
|
||||||
|
test: /[\\/]node_modules[\\/]echarts[\\/]/,
|
||||||
|
priority: 1,
|
||||||
|
},
|
||||||
|
elementPlus: {
|
||||||
|
name: "element-plus",
|
||||||
|
test: /[\\/]node_modules[\\/]element-plus[\\/]/,
|
||||||
|
priority: 2,
|
||||||
|
},
|
||||||
|
three: {
|
||||||
name: "three",
|
name: "three",
|
||||||
test: /[\\/]node_modules[\\/]three[\\/]/,
|
test: /[\\/]node_modules[\\/]three[\\/]/,
|
||||||
priority: 2,
|
priority: 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user