fix: polish pages and bugs fix (#36)

This commit is contained in:
Fine0830 2022-03-24 21:35:22 +08:00 committed by GitHub
parent 33365f2a14
commit 4380a874de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 314 additions and 134 deletions

View File

@ -0,0 +1,17 @@
<!-- 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">
<path d="M12.984 14.859q1.266-0.375 1.875-1.875h7.125q-0.375 3.609-2.836 6.141t-6.164 2.859v-7.125zM14.859 11.016q-0.563-1.5-1.875-1.875v-7.125q3.703 0.328 6.164 2.859t2.836 6.141h-7.125zM11.016 9.141q-0.797 0.328-1.406 1.125t-0.609 1.734 0.609 1.734 1.406 1.125v7.125q-3.797-0.375-6.398-3.234t-2.602-6.75 2.602-6.75 6.398-3.234v7.125z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -38,7 +38,7 @@ const props = defineProps({
onMounted(async () => {
await setOptions(props.option);
addResizeListener(unref(chartRef), resize);
chartRef.value && addResizeListener(unref(chartRef), resize);
setTimeout(() => {
const instance = getInstance();

View File

@ -22,6 +22,7 @@ limitations under the License. -->
:multiple="multiple"
:disabled="disabled"
:style="{ borderRadius }"
:clearable="clearable"
>
<el-option
v-for="item in options"
@ -60,6 +61,7 @@ const props = defineProps({
borderRadius: { type: Number, default: 3 },
multiple: { type: Boolean, default: false },
disabled: { type: Boolean, default: false },
clearable: { type: Boolean, default: false },
});
const selected = ref<string[] | string>(props.value);

View File

@ -101,6 +101,18 @@ limitations under the License. -->
@click="controlMenu"
/>
</div>
<div class="version">
<el-popover
trigger="hover"
width="250"
placement="right"
:content="appStore.version"
>
<template #reference>
{{ t("version") }}
</template>
</el-popover>
</div>
</div>
</template>
@ -108,7 +120,10 @@ limitations under the License. -->
import { ref } from "vue";
import { useRouter, RouteRecordRaw } from "vue-router";
import { useI18n } from "vue-i18n";
import { useAppStoreWithOut } from "@/store/modules/app";
import { ElMessage } from "element-plus";
const appStore = useAppStoreWithOut();
const { t } = useI18n();
const name = ref<any>(String(useRouter().currentRoute.value.name));
const theme = ["VirtualMachine", "Kubernetes"].includes(name.value || "")
@ -119,6 +134,7 @@ const isCollapse = ref(false);
const controlMenu = () => {
isCollapse.value = !isCollapse.value;
};
getVersion();
const changePage = (menu: RouteRecordRaw) => {
theme.value = ["VirtualMachine", "Kubernetes"].includes(String(menu.name))
? "light"
@ -127,6 +143,12 @@ const changePage = (menu: RouteRecordRaw) => {
const filterMenus = (menus: any[]) => {
return menus.filter((d) => d.meta && !d.meta.notShow);
};
async function getVersion() {
const res = await appStore.fetchVersion();
if (res.errors) {
ElMessage.error(res.errors);
}
}
</script>
<style lang="scss" scoped>
@ -193,4 +215,13 @@ span.collapse {
display: inline-block;
width: 100%;
}
.version {
color: #eee;
position: fixed;
bottom: 20px;
left: 20px;
font-size: 12px;
cursor: pointer;
}
</style>

View File

@ -23,7 +23,6 @@ const msg = {
serviceMesh: "Service Mesh",
infrastructure: "Infrastructure",
virtualMachine: "Virtual Machine",
kubernetes: "Kubernetes",
dashboardNew: "New Dashboard",
dashboardList: "Dashboard List",
logs: "Logs",
@ -123,6 +122,9 @@ const msg = {
viewWarning: "You are entering view mode",
virtualDatabase: "Virtual Database",
reloadDashboards: "Reload dashboards",
kubernetesService: "Service",
kubernetesCluster: "Cluster",
kubernetes: "Kubernetes",
hourTip: "Select Hour",
minuteTip: "Select Minute",
secondTip: "Select Second",
@ -304,7 +306,7 @@ const msg = {
keywordsOfContentLogTips:
"Current storage of SkyWalking OAP server does not support this.",
setEvent: "Set Event",
instanceAttributes: "Instance Attributes",
viewAttributes: "View Attributes",
serviceEvents: "Service Events",
select: "Select",
eventID: "Event ID",

View File

@ -22,7 +22,6 @@ const msg = {
serviceMesh: "服务网格",
infrastructure: "基础结构",
virtualMachine: "虚拟机",
kubernetes: "Kubernetes",
dashboardNew: "新建仪表板",
dashboardHome: "仪表盘首页",
dashboardList: "仪表盘列表",
@ -123,6 +122,9 @@ const msg = {
viewWarning: "你正在进入预览模式",
virtualDatabase: "虚拟数据库",
reloadDashboards: "重新加载仪表盘",
kubernetesService: "服务",
kubernetesCluster: "集群",
kubernetes: "Kubernetes",
hourTip: "选择小时",
minuteTip: "选择分钟",
secondTip: "选择秒数",
@ -303,7 +305,7 @@ const msg = {
"只有core/default/searchableLogsTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
keywordsOfContentLogTips: "SkyWalking OAP服务器的当前存储不支持此操作",
setEvent: "设置事件",
instanceAttributes: "实例属性",
viewAttributes: "实例属性",
serviceEvents: "服务事件",
select: "选择",
eventID: "事件ID",

View File

@ -26,11 +26,13 @@ import { routesAlarm } from "./alarm";
import { routesSelf } from "./selfObservability";
import { routesFunctions } from "./functions";
import { routesBrowser } from "./browser";
import { routesK8s } from "./k8s";
const routes: Array<RouteRecordRaw> = [
...routesGen,
...routesMesh,
...routesFunctions,
...routesK8s,
...routesInfra,
...routesBrowser,
...routesDatabase,

View File

@ -38,14 +38,6 @@ export const routesInfra: Array<RouteRecordRaw> = [
},
component: () => import("@/views/Layer.vue"),
},
{
path: "/kubernetes",
name: "Kubernetes",
meta: {
title: "kubernetes",
},
component: () => import("@/views/Layer.vue"),
},
// {
// path: "/infrastructure/vm",
// name: "VirtualMachine",

50
src/router/k8s.ts Normal file
View File

@ -0,0 +1,50 @@
/**
* 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 { RouteRecordRaw } from "vue-router";
import Layout from "@/layout/Index.vue";
export const routesK8s: Array<RouteRecordRaw> = [
{
path: "",
name: "Kubernetes",
meta: {
title: "kubernetes",
icon: "donut_small",
hasGroup: true,
},
redirect: "/kubernetes/cluster",
component: Layout,
children: [
{
path: "/kubernetes/cluster",
name: "KubernetesCluster",
meta: {
title: "kubernetesCluster",
},
component: () => import("@/views/Layer.vue"),
},
{
path: "/kubernetes/service",
name: "KubernetesService",
meta: {
title: "kubernetesService",
},
component: () => import("@/views/Layer.vue"),
},
],
},
];

View File

@ -32,6 +32,7 @@ interface AppState {
timer: Nullable<any>;
autoRefresh: boolean;
pageTitle: string;
version: string;
}
export const appStore = defineStore({
@ -49,6 +50,7 @@ export const appStore = defineStore({
timer: null,
autoRefresh: false,
pageTitle: "",
version: "",
}),
getters: {
duration(): Duration {
@ -155,6 +157,16 @@ export const appStore = defineStore({
return res.data;
},
async fetchVersion(): Promise<void> {
const res: AxiosResponse = await graphql
.query("queryOAPVersion")
.params({});
if (res.data.errors) {
return res.data;
}
this.version = res.data.data.version;
return res.data;
},
},
});
export function useAppStoreWithOut(): any {

View File

@ -65,15 +65,15 @@ export const logStore = defineStore({
if (res.data.errors) {
return res.data;
}
this.services = [
{ value: "0", label: "All" },
...res.data.data.services,
] || [{ value: "0", label: "All" }];
this.services = res.data.data.services;
return res.data;
},
async getInstances() {
async getInstances(id: string) {
const serviceId = this.selectorStore.currentService
? this.selectorStore.currentService.id
: id;
const res: AxiosResponse = await graphql.query("queryInstances").params({
serviceId: this.selectorStore.currentService.id,
serviceId,
duration: this.durationTime,
});
@ -86,9 +86,12 @@ export const logStore = defineStore({
] || [{ value: " 0", label: "All" }];
return res.data;
},
async getEndpoints() {
async getEndpoints(id: string) {
const serviceId = this.selectorStore.currentService
? this.selectorStore.currentService.id
: id;
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
serviceId: this.selectorStore.currentService.id,
serviceId,
duration: this.durationTime,
keyword: "",
});

View File

@ -82,10 +82,7 @@ export const profileStore = defineStore({
if (res.data.errors) {
return res.data;
}
this.services = [
{ value: "0", label: "All" },
...res.data.data.services,
] || [{ value: "0", label: "All" }];
this.services = res.data.data.services;
return res.data;
},
async getTaskList() {

View File

@ -80,15 +80,15 @@ export const traceStore = defineStore({
if (res.data.errors) {
return res.data;
}
this.services = [
{ value: "0", label: "All" },
...res.data.data.services,
] || [{ value: "0", label: "All" }];
this.services = res.data.data.services;
return res.data;
},
async getInstances() {
async getInstances(id: string) {
const serviceId = this.selectorStore.currentService
? this.selectorStore.currentService.id
: id;
const res: AxiosResponse = await graphql.query("queryInstances").params({
serviceId: this.selectorStore.currentService.id,
serviceId: serviceId,
duration: this.durationTime,
});
@ -101,9 +101,12 @@ export const traceStore = defineStore({
] || [{ value: " 0", label: "All" }];
return res.data;
},
async getEndpoints() {
async getEndpoints(id: string) {
const serviceId = this.selectorStore.currentService
? this.selectorStore.currentService.id
: id;
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
serviceId: this.selectorStore.currentService.id,
serviceId,
duration: this.durationTime,
keyword: "",
});

View File

@ -35,7 +35,7 @@ const dashboardStore = useDashboardStore();
const routesMap: { [key: string]: string } = {
GeneralServices: "GENERAL",
Database: "VIRTUAL_DATABASE",
MESH: "MESH",
MeshServices: "MESH",
ControlPanel: "MESH_CP",
DataPanel: "MESH_DP",
Linux: "OS_LINUX",
@ -43,7 +43,8 @@ const routesMap: { [key: string]: string } = {
Satellite: "SO11Y_SATELLITE",
Functions: "FAAS",
Browser: "BROWSER",
Kubernetes: "K8S",
KubernetesCluster: "K8S",
KubernetesService: "K8S_SERVICE",
};
const layer = ref<string>("GENERAL");
@ -51,6 +52,7 @@ getDashboard();
async function getDashboard() {
layer.value = routesMap[String(route.name)];
console.log(layer.value);
dashboardStore.setLayer(layer.value);
dashboardStore.setEntity(EntityType[1].value);
dashboardStore.setMode(false);

View File

@ -203,6 +203,9 @@ async function importTemplates(event: any) {
dashboardFile.value = null;
}
function exportTemplates() {
if (!multipleSelection.value.length) {
return;
}
const arr = multipleSelection.value.sort(
(a: DashboardItem, b: DashboardItem) => {
return a.name.localeCompare(b.name);

View File

@ -37,8 +37,9 @@ limitations under the License. -->
metrics: dashboardStore.selectedGrid.metrics,
metricTypes: dashboardStore.selectedGrid.metricTypes,
standard: dashboardStore.selectedGrid.standard,
isEdit: true,
}"
:isEdit="isEdit"
@changeOpt="setStatus"
/>
<div v-show="!dashboardStore.selectedGrid.graph.type" class="no-data">
{{ t("noData") }}
@ -51,7 +52,11 @@ limitations under the License. -->
:style="{ '--el-collapse-header-font-size': '15px' }"
>
<el-collapse-item :title="t('selectVisualization')" name="1">
<MetricOptions @update="getSource" @loading="setLoading" />
<MetricOptions
@update="getSource"
@changeOpt="setStatus"
@loading="setLoading"
/>
</el-collapse-item>
<el-collapse-item :title="t('graphStyles')" name="2">
<component :is="`${dashboardStore.selectedGrid.graph.type}Config`" />
@ -85,6 +90,7 @@ import configs from "./widget/graph-styles";
import WidgetOptions from "./widget/WidgetOptions.vue";
import StandardOptions from "./widget/StandardOptions.vue";
import MetricOptions from "./widget/MetricOptions.vue";
import { ListChartTypes } from "../data";
export default defineComponent({
name: "ConfigEdit",
@ -101,6 +107,7 @@ export default defineComponent({
const dashboardStore = useDashboardStore();
const appStoreWithOut = useAppStoreWithOut();
const loading = ref<boolean>(false);
const isEdit = ref<boolean>(false);
const states = reactive<{
activeNames: string;
source: unknown;
@ -123,8 +130,13 @@ export default defineComponent({
}
function applyConfig() {
dashboardStore.setConfigs(dashboardStore.selectedGrid);
dashboardStore.setConfigPanel(false);
setStatus();
dashboardStore.setConfigs(dashboardStore.selectedGrid);
}
function setStatus() {
isEdit.value = true;
}
function cancelConfig() {
@ -143,6 +155,8 @@ export default defineComponent({
cancelConfig,
getSource,
setLoading,
setStatus,
isEdit,
};
},
});

View File

@ -13,15 +13,16 @@ 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-if="states.isList && states.dashboardList.length" class="ds-name">
<div v-if="states.isList" class="ds-name">
<div>{{ t("dashboards") }}</div>
<Selector
:value="states.dashboardName"
:value="states.dashboardName || ''"
:options="states.dashboardList"
size="small"
placeholder="Please select a dashboard name"
@change="changeDashboard"
class="selectors"
:clearable="true"
/>
</div>
<div>{{ t("metrics") }}</div>
@ -63,7 +64,6 @@ limitations under the License. -->
/>
<Icon
class="cp"
v-show="states.metrics.length > 1"
iconName="remove_circle_outline"
size="middle"
@click="deleteMetric(index)"
@ -105,7 +105,7 @@ import { DashboardItem } from "@/types/dashboard";
/*global defineEmits */
const { t } = useI18n();
const emit = defineEmits(["update", "loading"]);
const emit = defineEmits(["update", "loading", "changeOpt"]);
const dashboardStore = useDashboardStore();
const { metrics, metricTypes, graph } = dashboardStore.selectedGrid;
const states = reactive<{
@ -116,7 +116,7 @@ const states = reactive<{
isList: boolean;
metricList: (Option & { type: string })[];
dashboardName: string;
dashboardList: (DashboardItem & { label: string; value: string })[];
dashboardList: ((DashboardItem & { label: string; value: string }) | any)[];
}>({
metrics: metrics && metrics.length ? metrics : [""],
metricTypes: metricTypes && metricTypes.length ? metricTypes : [""],
@ -125,11 +125,11 @@ const states = reactive<{
isList: false,
metricList: [],
dashboardName: graph.dashboardName,
dashboardList: [],
dashboardList: [{ label: "", value: "" }],
});
states.isList = ListChartTypes.includes(graph.type);
const defaultLen = ref<number>(states.isList ? 5 : 10);
const defaultLen = ref<number>(states.isList ? 5 : 20);
states.visTypes = setVisTypes();
setDashboards();
@ -197,7 +197,7 @@ async function setMetricType() {
function setDashboards() {
const { graph } = dashboardStore.selectedGrid;
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
states.dashboardList = list.reduce(
const arr = list.reduce(
(
prev: (DashboardItem & { label: string; value: string })[],
d: DashboardItem
@ -219,6 +219,8 @@ function setDashboards() {
},
[]
);
states.dashboardList = arr.length ? arr : [{ label: "", value: "" }];
}
function setVisTypes() {
@ -281,6 +283,7 @@ function changeMetrics(
...{ metricTypes: states.metricTypes, metrics: states.metrics },
});
if (states.isList) {
emit("changeOpt");
return;
}
queryMetrics();
@ -311,6 +314,7 @@ function changeMetricType(index: number, opt: Option[] | any) {
...{ metricTypes: states.metricTypes },
});
if (states.isList) {
emit("changeOpt");
return;
}
queryMetrics();
@ -338,7 +342,11 @@ async function queryMetrics() {
}
function changeDashboard(opt: any) {
states.dashboardName = opt[0].value;
if (!opt[0]) {
states.dashboardName = "";
} else {
states.dashboardName = opt[0].value;
}
const graph = {
...dashboardStore.selectedGrid.graph,
dashboardName: states.dashboardName,
@ -358,6 +366,15 @@ function addMetric() {
states.metricTypes.push("");
}
function deleteMetric(index: number) {
if (states.metrics.length === 1) {
states.metrics = [""];
states.metricTypes = [""];
dashboardStore.selectWidget({
...dashboardStore.selectedGrid,
...{ metricTypes: states.metricTypes, metrics: states.metrics },
});
return;
}
states.metrics.splice(index, 1);
states.metricTypes.splice(index, 1);
}

View File

@ -104,26 +104,24 @@ const props = defineProps({
i: string;
metrics: string[];
metricTypes: string[];
isEdit: boolean;
}
>,
default: () => ({ dashboardName: "", fontSize: 12, i: "" }),
},
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
needQuery: { type: Boolean, default: false },
isEdit: { type: Boolean, default: false },
});
// const emit = defineEmits(["changeOpt"]);
const selectorStore = useSelectorStore();
const dashboardStore = useDashboardStore();
const chartLoading = ref<boolean>(false);
const endpoints = ref<Endpoint[]>([]);
const searchEndpoints = ref<Endpoint[]>([]);
const pageSize = 5;
const total = 10;
const searchText = ref<string>("");
if (props.needQuery) {
queryEndpoints(total);
}
queryEndpoints(total);
async function queryEndpoints(limit?: number) {
chartLoading.value = true;
const resp = await selectorStore.getEndpoints({
@ -136,15 +134,14 @@ async function queryEndpoints(limit?: number) {
ElMessage.error(resp.errors);
return;
}
searchEndpoints.value = selectorStore.pods;
endpoints.value = selectorStore.pods.splice(0, pageSize);
if (props.config.isEdit || !endpoints.value.length) {
return;
}
queryEndpointMetrics(endpoints.value);
await queryEndpointMetrics(endpoints.value);
}
async function queryEndpointMetrics(currentPods: Endpoint[]) {
const { metrics } = props.config;
if (!currentPods.length) {
return;
}
const metrics = props.config.metrics.filter((d: string) => d);
if (metrics.length && metrics[0]) {
const params = await useQueryPodsMetrics(
@ -178,7 +175,7 @@ function clickEndpoint(scope: any) {
);
}
function changePage(pageIndex: number) {
endpoints.value = searchEndpoints.value.splice(
endpoints.value = selectorStore.pods.splice(
(pageIndex - 1 || 0) * pageSize,
pageSize * (pageIndex || 1)
);
@ -189,10 +186,11 @@ async function searchList() {
}
watch(
() => [props.config.metricTypes, props.config.metrics],
() => {
if (dashboardStore.showConfig) {
async () => {
if (props.isEdit) {
queryEndpointMetrics(endpoints.value);
}
// emit("changeOpt", false);
}
);
watch(

View File

@ -42,20 +42,6 @@ limitations under the License. -->
</span>
</template>
</el-table-column>
<el-table-column label="Service Instances">
<template #default="scope">
<div class="attributes" v-if="scope.row.attributes.length">
<div
v-for="(attr, index) in scope.row.attributes"
:key="attr.name + index"
:style="{ fontSize: `${config.fontSize}px` }"
>
{{ attr.name }}: {{ attr.value || null }}
</div>
</div>
<div v-else>No Data</div>
</template>
</el-table-column>
<el-table-column
v-for="(metric, index) in config.metrics"
:label="metric"
@ -77,6 +63,25 @@ limitations under the License. -->
</div>
</template>
</el-table-column>
<el-table-column label="Attributes" :width="100">
<template #default="scope">
<el-popover placement="left" :width="400" trigger="click">
<template #reference>
<span class="link">{{ t("viewAttributes") }}</span>
</template>
<div class="attributes" v-if="scope.row.attributes.length">
<div
v-for="(attr, index) in scope.row.attributes"
:key="attr.name + index"
:style="{ fontSize: `${config.fontSize}px` }"
class="mt-5"
>
{{ attr.name }}: {{ attr.value || null }}
</div>
</div>
</el-popover>
</template>
</el-table-column>
</el-table>
</div>
<el-pagination
@ -94,6 +99,7 @@ limitations under the License. -->
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
import { useI18n } from "vue-i18n";
import { ElMessage } from "element-plus";
import type { PropType } from "vue";
import Line from "./Line.vue";
@ -128,7 +134,9 @@ const props = defineProps({
},
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
needQuery: { type: Boolean, default: false },
isEdit: { type: Boolean, default: false },
});
const { t } = useI18n();
const selectorStore = useSelectorStore();
const dashboardStore = useDashboardStore();
const chartLoading = ref<boolean>(false);
@ -137,9 +145,7 @@ const searchInstances = ref<Instance[]>([]); // all instances
const pageSize = 5;
const searchText = ref<string>("");
if (props.needQuery) {
queryInstance();
}
queryInstance();
async function queryInstance() {
chartLoading.value = true;
const resp = await selectorStore.getServiceInstances();
@ -153,13 +159,13 @@ async function queryInstance() {
}
searchInstances.value = selectorStore.pods;
instances.value = searchInstances.value.splice(0, pageSize);
if (props.config.isEdit) {
return;
}
queryInstanceMetrics(instances.value);
}
async function queryInstanceMetrics(currentInstances: Instance[]) {
if (!currentInstances.length) {
return;
}
const { metrics } = props.config;
if (metrics.length && metrics[0]) {
@ -186,6 +192,10 @@ function clickInstance(scope: any) {
layer: dashboardStore.layerId,
entity: EntityType[3].value,
});
if (!d) {
ElMessage.error("No this dashboard");
return;
}
router.push(
`/dashboard/${d.layer}/${d.entity}/${selectorStore.currentService.id}/${
scope.row.id
@ -207,9 +217,7 @@ function searchList() {
watch(
() => [props.config.metricTypes, props.config.metrics],
() => {
if (dashboardStore.showConfig) {
queryInstanceMetrics(instances.value);
}
queryInstanceMetrics(instances.value);
}
);
watch(
@ -231,7 +239,7 @@ watch(
}
.attributes {
max-height: 80px;
max-height: 400px;
overflow: auto;
}
</style>

View File

@ -122,15 +122,16 @@ const props = defineProps({
default: () => ({ dashboardName: "", fontSize: 12 }),
},
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
isEdit: { type: Boolean, default: false },
});
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>("");
const groups = ref<any>({});
const sortServices = ref<(Service & { merge: boolean })[]>([]);
queryServices();
@ -142,7 +143,13 @@ async function queryServices() {
if (resp.errors) {
ElMessage.error(resp.errors);
}
const map: { [key: string]: any[] } = selectorStore.services.reduce(
setServices(selectorStore.services);
queryServiceMetrics(services.value);
}
function setServices(arr: (Service & { merge: boolean })[]) {
groups.value = {};
const map: { [key: string]: any[] } = arr.reduce(
(result: { [key: string]: any[] }, item: any) => {
item.group = item.group || "";
if (result[item.group]) {
@ -156,21 +163,23 @@ async function queryServices() {
},
{}
);
services.value = Object.values(map).flat(1).splice(0, pageSize);
sortServices.value = Object.values(map).flat(1);
const obj = {} as any;
for (const s of services.value) {
for (const s of sortServices.value) {
s.group = s.group || "";
if (!obj[s.group]) {
obj[s.group] = 1;
} else {
if (obj[s.group] % 5 === 0) {
s.merge = false;
}
obj[s.group]++;
}
groups.value[s.group] = obj[s.group];
}
if (props.config.isEdit) {
return;
}
queryServiceMetrics(services.value);
services.value = sortServices.value.filter(
(d: Service, index: number) => index < pageSize
);
}
function clickService(scope: any) {
@ -188,6 +197,9 @@ function clickService(scope: any) {
router.push(path);
}
async function queryServiceMetrics(currentServices: Service[]) {
if (!currentServices.length) {
return;
}
const { metrics } = props.config;
if (metrics.length && metrics[0]) {
@ -219,28 +231,29 @@ function objectSpanMethod(param: any): any {
rowspan: 0,
colspan: 0,
};
} else {
return { rowspan: groups.value[param.row.group], colspan: 1 };
}
return { rowspan: groups.value[param.row.group], colspan: 1 };
}
function changePage(pageIndex: number) {
services.value = services.value.splice(
(pageIndex - 1 || 0) * pageSize,
pageSize * (pageIndex || 1)
);
services.value = sortServices.value.filter((d: Service, index: number) => {
if (
index >= (pageIndex - 1 || 0) * pageSize &&
index < pageSize * (pageIndex || 1)
) {
return d;
}
});
}
function searchList() {
searchServices.value = selectorStore.services.filter((d: { label: string }) =>
const searchServices = sortServices.value.filter((d: { label: string }) =>
d.label.includes(searchText.value)
);
services.value = searchServices.value.splice(0, pageSize);
services.value = searchServices.splice(0, pageSize);
}
watch(
() => [props.config.metricTypes, props.config.metrics],
() => {
if (dashboardStore.showConfig) {
queryServiceMetrics(services.value);
}
queryServiceMetrics(services.value);
}
);
</script>

View File

@ -127,6 +127,7 @@ const params = useRoute().params;
const toolIcons = ref<{ name: string; content: string; id: string }[]>(
EndpointRelationTools
);
const limit = ref<number>(10);
const loading = ref<boolean>(false);
const states = reactive<{
destService: string;
@ -401,7 +402,7 @@ async function fetchPods(type: string, serviceId: string, setPod: boolean) {
let resp;
switch (type) {
case EntityType[2].value:
resp = await selectorStore.getEndpoints({ serviceId });
resp = await selectorStore.getEndpoints({ serviceId, limit });
if (setPod) {
selectorStore.setCurrentPod(
selectorStore.pods.length ? selectorStore.pods[0] : null
@ -419,7 +420,11 @@ async function fetchPods(type: string, serviceId: string, setPod: boolean) {
}
break;
case EntityType[6].value:
resp = await selectorStore.getEndpoints({ serviceId, isRelation: true });
resp = await selectorStore.getEndpoints({
serviceId,
isRelation: true,
limit,
});
if (setPod) {
selectorStore.setCurrentDestPod(
selectorStore.destPods.length ? selectorStore.destPods[0] : null

View File

@ -114,6 +114,7 @@ function setCurrentLog(log: any) {
}
.serviceInstanceName,
.endpointName,
.serviceName {
width: 200px;
}

View File

@ -82,6 +82,7 @@ function showSelectSpan() {
}
.serviceInstanceName,
.endpointName,
.serviceName {
width: 200px;
}
@ -98,6 +99,7 @@ function showSelectSpan() {
border: 1px solid transparent;
border-right: 1px dotted silver;
overflow: hidden;
height: 30px;
line-height: 30px;
text-overflow: ellipsis;
white-space: nowrap;

View File

@ -24,6 +24,10 @@ export const ServiceLogConstants = [
label: "serviceInstanceName",
value: "instance",
},
{
label: "endpointName",
value: "endpoint",
},
{
label: "timestamp",
value: "time",

View File

@ -143,7 +143,7 @@ const isBrowser = ref<boolean>(dashboardStore.layerId === "BROWSER");
const state = reactive<any>({
instance: { value: "0", label: "All" },
endpoint: { value: "0", label: "All" },
service: { value: "0", label: "All" },
service: { value: "", label: "" },
});
init();
@ -154,11 +154,10 @@ async function init() {
ElMessage.error(resp.errors);
return;
}
await fetchSelectors();
await searchLogs();
state.instance = { value: "0", label: "All" };
state.endpoint = { value: "0", label: "All" };
state.service = { value: "0", label: "All" };
searchLogs();
fetchSelectors();
}
function fetchSelectors() {
@ -187,18 +186,20 @@ async function getServices() {
return;
}
state.service = logStore.services[0];
getInstances(state.service.id);
getEndpoints(state.service.id);
}
async function getEndpoints() {
const resp = await logStore.getEndpoints();
async function getEndpoints(id?: string) {
const resp = await logStore.getEndpoints(id);
if (resp.errors) {
ElMessage.error(resp.errors);
return;
}
state.endpoint = logStore.endpoints[0];
}
async function getInstances() {
const resp = await logStore.getInstances();
async function getInstances(id?: string) {
const resp = await logStore.getInstances(id);
if (resp.errors) {
ElMessage.error(resp.errors);
return;
@ -238,8 +239,8 @@ async function queryLogs() {
function changeField(type: string, opt: any) {
state[type] = opt[0];
if (type === "service") {
getEndpoints();
getInstances();
getEndpoints(state.service.id);
getInstances(state.service.id);
}
}
function updateTags(data: { tagsMap: Array<Option>; tagsList: string[] }) {

View File

@ -113,7 +113,7 @@ const state = reactive<any>({
status: { label: "All", value: "ALL" },
instance: { value: "0", label: "All" },
endpoint: { value: "0", label: "All" },
service: { value: "0", label: "All" },
service: { value: "", label: "" },
});
// const dateTime = computed(() => [
@ -121,24 +121,21 @@ const state = reactive<any>({
// appStore.durationRow.end,
// ]);
init();
function init() {
searchTraces();
async function init() {
if (dashboardStore.entity === EntityType[1].value) {
getServices();
return;
await getServices();
}
if (dashboardStore.entity === EntityType[2].value) {
getInstances();
return;
await getInstances();
}
if (dashboardStore.entity === EntityType[3].value) {
getEndpoints();
return;
await getEndpoints();
}
if (dashboardStore.entity === EntityType[0].value) {
getInstances();
getEndpoints();
await getInstances();
await getEndpoints();
}
await searchTraces();
}
async function getServices() {
@ -148,18 +145,20 @@ async function getServices() {
return;
}
state.service = traceStore.services[0];
getEndpoints(state.service.id);
getInstances(state.service.id);
}
async function getEndpoints() {
const resp = await traceStore.getEndpoints();
async function getEndpoints(id?: string) {
const resp = await traceStore.getEndpoints(id);
if (resp.errors) {
ElMessage.error(resp.errors);
return;
}
state.endpoint = traceStore.endpoints[0];
}
async function getInstances() {
const resp = await traceStore.getInstances();
async function getInstances(id?: string) {
const resp = await traceStore.getInstances(id);
if (resp.errors) {
ElMessage.error(resp.errors);
return;
@ -201,8 +200,8 @@ async function queryTraces() {
function changeField(type: string, opt: any) {
state[type] = opt[0];
if (type === "service") {
getEndpoints();
getInstances();
getEndpoints(state.service.id);
getInstances(state.service.id);
}
}
function updateTags(data: { tagsMap: Array<Option>; tagsList: string[] }) {