diff --git a/src/assets/icons/retry.svg b/src/assets/icons/retry.svg new file mode 100755 index 00000000..dfff9254 --- /dev/null +++ b/src/assets/icons/retry.svg @@ -0,0 +1,16 @@ + + +icn/retry \ No newline at end of file diff --git a/src/hooks/useProcessor.ts b/src/hooks/useProcessor.ts index 888694f0..e50e6fb6 100644 --- a/src/hooks/useProcessor.ts +++ b/src/hooks/useProcessor.ts @@ -19,7 +19,7 @@ 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"; +import { Instance, Endpoint, Service } from "@/types/selector"; export function useQueryProcessor(config: any) { if (!(config.metrics && config.metrics[0])) { @@ -28,7 +28,7 @@ export function useQueryProcessor(config: any) { const appStore = useAppStoreWithOut(); const dashboardStore = useDashboardStore(); const selectorStore = useSelectorStore(); - if (!selectorStore.currentService) { + if (!selectorStore.currentService && dashboardStore.entity !== "All") { return; } const conditions: { [key: string]: unknown } = { @@ -190,7 +190,7 @@ export function useSourceProcessor( } export function useQueryPodsMetrics( - pods: Array, + pods: Array, config: { metrics: string[]; metricTypes: string[] }, scope: string ) { @@ -202,25 +202,30 @@ export function useQueryPodsMetrics( 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, + const fragmentList = pods.map( + ( + d: (Instance | Endpoint | Service) & { normal: boolean }, + index: number + ) => { + const param = { + scope, + serviceName: scope === "Service" ? d.label : currentService.label, + serviceInstanceName: scope === "ServiceInstance" ? d.label : undefined, + endpointName: scope === "Endpoint" ? d.label : undefined, + normal: scope === "Service" ? d.normal : currentService.normal, }; - variables.push(`$condition${index}${idx}: MetricsCondition!`); - return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, duration: $duration)${RespFields[metricType]}`; - }); - return f; - }); + 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}}`; diff --git a/src/layout/components/NavBar.vue b/src/layout/components/NavBar.vue index d5185707..bec073a5 100644 --- a/src/layout/components/NavBar.vue +++ b/src/layout/components/NavBar.vue @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. --> @@ -66,6 +66,12 @@ const time = computed(() => [ appStore.durationRow.start, appStore.durationRow.end, ]); +const handleReload = () => { + const gap = + appStore.duration.end.getTime() - appStore.duration.start.getTime(); + const time: Date[] = [new Date(new Date().getTime() - gap), new Date()]; + appStore.setDuration(timeFormat(time)); +}; function changeTimeRange(val: Date[]) { timeRange.value = val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0; diff --git a/src/store/data.ts b/src/store/data.ts index 25caaecf..5a26937a 100644 --- a/src/store/data.ts +++ b/src/store/data.ts @@ -101,3 +101,24 @@ export const ConfigData2: any = { }, children: [], }; +export const ConfigData3: any = { + x: 0, + y: 0, + w: 8, + h: 12, + i: "0", + metrics: ["all_heatmap"], + metricTypes: ["readHeatMap"], + type: "Widget", + widget: { + title: "all_heatmap", + tips: "Tooltip", + }, + graph: { + type: "HeatMap", + }, + standard: { + unit: "min", + }, + children: [], +}; diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index e89f1e3b..bf55be26 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -28,6 +28,8 @@ interface AppState { utcMin: number; eventStack: (() => unknown)[]; timer: Nullable; + autoRefresh: boolean; + pageTitle: string; } export const appStore = defineStore({ @@ -39,6 +41,8 @@ export const appStore = defineStore({ utcMin: 0, eventStack: [], timer: null, + autoRefresh: false, + pageTitle: "", }), getters: { duration(): Duration { @@ -117,6 +121,12 @@ export const appStore = defineStore({ setEventStack(funcs: (() => void)[]): void { this.eventStack = funcs; }, + setAutoRefresh(auto: boolean) { + this.autoRefresh = auto; + }, + setPageTitle(title: string) { + this.pageTitle = title; + }, runEventStack() { if (this.timer) { clearTimeout(this.timer); diff --git a/src/store/modules/dashboard.ts b/src/store/modules/dashboard.ts index 47fc4a71..88264c2e 100644 --- a/src/store/modules/dashboard.ts +++ b/src/store/modules/dashboard.ts @@ -18,7 +18,7 @@ import { defineStore } from "pinia"; import { store } from "@/store"; import { LayoutConfig } from "@/types/dashboard"; import graph from "@/graph"; -import { ConfigData, ConfigData1, ConfigData2 } from "../data"; +import { ConfigData, ConfigData1, ConfigData2, ConfigData3 } from "../data"; import { useAppStoreWithOut } from "@/store/modules/app"; import { useSelectorStore } from "@/store/modules/selectors"; import { NewControl } from "../data"; @@ -146,12 +146,19 @@ export const dashboardStore = defineStore({ }, setEntity(type: string) { this.entity = type; + // todo if (type === "ServiceInstance") { this.layout = [ConfigData1]; } if (type === "Endpoint") { this.layout = [ConfigData2]; } + if (type == "All") { + this.layout = [ConfigData3]; + } + if (type == "Service") { + this.layout = [ConfigData]; + } }, setConfigs(param: { [key: string]: unknown }) { const actived = this.activedGridItem.split("-"); diff --git a/src/styles/lib.scss b/src/styles/lib.scss index 43a06b88..e49087a4 100644 --- a/src/styles/lib.scss +++ b/src/styles/lib.scss @@ -126,3 +126,14 @@ .mr-20 { margin-right: 20px; } +@keyframes loading { + 0% { + transform: rotate(0deg); + transform: rotate(0deg); + } + + to { + transform: rotate(1turn); + transform: rotate(1turn); + } +} diff --git a/src/views/Log.vue b/src/views/Log.vue index f70cb63a..9b188c71 100644 --- a/src/views/Log.vue +++ b/src/views/Log.vue @@ -16,6 +16,10 @@ limitations under the License. -->
{{ props.msg }}
+ diff --git a/src/views/dashboard/controls/Widget.vue b/src/views/dashboard/controls/Widget.vue index d78f94a1..254e71fc 100644 --- a/src/views/dashboard/controls/Widget.vue +++ b/src/views/dashboard/controls/Widget.vue @@ -93,6 +93,10 @@ export default defineComponent({ const dashboardStore = useDashboardStore(); const selectorStore = useSelectorStore(); + if (dashboardStore.entity === EntityType[1].value) { + queryMetrics(); + } + async function queryMetrics() { const params = await useQueryProcessor(props.data); if (!params) { @@ -133,7 +137,7 @@ export default defineComponent({ } ); watch( - () => [selectorStore.currentService], + () => selectorStore.currentService, () => { if (dashboardStore.entity === EntityType[0].value) { queryMetrics(); @@ -141,12 +145,9 @@ export default defineComponent({ } ); watch( - () => [selectorStore.currentPod], + () => selectorStore.currentPod, () => { - if ( - dashboardStore.entity === EntityType[0].value || - dashboardStore.entity === EntityType[1].value - ) { + if (dashboardStore.entity === EntityType[0].value) { return; } queryMetrics(); diff --git a/src/views/dashboard/data.ts b/src/views/dashboard/data.ts index bff6c578..50d0e3e7 100644 --- a/src/views/dashboard/data.ts +++ b/src/views/dashboard/data.ts @@ -41,7 +41,7 @@ export const MetricChartType: any = { ], sortMetrics: [{ label: "Top List", value: "TopList" }], readLabeledMetricsValues: [{ label: "Line", value: "Line" }], - readHeatMap: [{ label: "Heatmap", value: "Heatmap" }], + readHeatMap: [{ label: "Heat Map", value: "HeatMap" }], readSampledRecords: [{ label: "Top List", value: "TopList" }], }; export const DefaultGraphConfig: { [key: string]: any } = { @@ -93,6 +93,9 @@ export const DefaultGraphConfig: { [key: string]: any } = { dashboardName: "", fontSize: 12, }, + HeatMap: { + type: "HeatMap", + }, }; export enum MetricsType { @@ -141,16 +144,10 @@ export const EntityType = [ { value: "All", label: "All", key: 10 }, { value: "Endpoint", label: "Service Endpoint", key: 3 }, { value: "ServiceInstance", label: "Service Instance", key: 3 }, - { value: "ServiceRelationClient", label: "Service Relation(client)", key: 2 }, - { value: "ServiceRelationServer", label: "Service Relation(server)", key: 2 }, + { value: "ServiceRelation", label: "Service Relation", key: 2 }, { - value: "ServiceInstanceRelationClient", - label: "Service Instance Relation(client)", - key: 4, - }, - { - value: "ServiceInstanceRelationServer", - label: "Service Instance Relation(server)", + value: "ServiceInstanceRelation", + label: "Service Instance Relation", key: 4, }, { value: "EndpointRelation", label: "Endpoint Relation", key: 4 }, diff --git a/src/views/dashboard/graphs/EndpointList.vue b/src/views/dashboard/graphs/EndpointList.vue index a895349c..397548e6 100644 --- a/src/views/dashboard/graphs/EndpointList.vue +++ b/src/views/dashboard/graphs/EndpointList.vue @@ -49,10 +49,16 @@ limitations under the License. --> @@ -79,6 +85,7 @@ import { Endpoint } from "@/types/selector"; import { useDashboardStore } from "@/store/modules/dashboard"; import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor"; import Line from "./Line.vue"; +import Card from "./Card.vue"; import { EntityType } from "../data"; /*global defineProps */ @@ -158,7 +165,9 @@ function searchList() { watch( () => [props.config.metricTypes, props.config.metrics], () => { - queryEndpointMetrics(endpoints.value); + if (dashboardStore.showConfig) { + queryEndpointMetrics(endpoints.value); + } } ); diff --git a/src/views/dashboard/graphs/HeatMap.vue b/src/views/dashboard/graphs/HeatMap.vue index 952658e1..76036c64 100644 --- a/src/views/dashboard/graphs/HeatMap.vue +++ b/src/views/dashboard/graphs/HeatMap.vue @@ -23,7 +23,9 @@ import { StandardConfig } from "@/types/dashboard"; /*global defineProps */ const props = defineProps({ data: { - type: Object as PropType<{ nodes: number[][]; buckets: number[][] }>, + type: Object as PropType<{ + [key: string]: { nodes: number[][]; buckets: number[][] }; + }>, default: () => ({}), }, intervalTime: { type: Array as PropType, default: () => [] }, @@ -37,8 +39,11 @@ const props = defineProps({ }, }); const option = computed(() => getOption()); + function getOption() { - const source = (props.data.nodes || []).map((d: number[]) => d[2]); + const metric = props.config.metrics[0]; + const nodes = (props.data[metric] && props.data[metric].nodes) || []; + const source = (nodes || []).map((d: number[]) => d[2]); const maxItem = Math.max(...source); const minItem = Math.min(...source); const colorBox = [ @@ -63,15 +68,16 @@ function getOption() { "#761212", "#671010", ]; + return { tooltip: { position: "top", - formatter: (a: any) => - `${a.data[1] * 100}${props.standard.unit} [ ${a.data[2]} ]`, - textStyle: { - fontSize: 13, - color: "#ccc", - }, + // formatter: (a: any) => + // `${a.data[1] * 100}${props.standard.unit} [ ${a.data[2]} ]`, + // textStyle: { + // fontSize: 13, + // color: "#ccc", + // }, }, grid: { top: 15, @@ -112,7 +118,7 @@ function getOption() { series: [ { type: "heatmap", - data: props.data.nodes || [], + data: nodes || [], emphasis: { itemStyle: { shadowBlur: 10, diff --git a/src/views/dashboard/graphs/InstanceList.vue b/src/views/dashboard/graphs/InstanceList.vue index aadcb2b0..1ec86a4c 100644 --- a/src/views/dashboard/graphs/InstanceList.vue +++ b/src/views/dashboard/graphs/InstanceList.vue @@ -170,7 +170,9 @@ function searchList() { watch( () => [props.config.metricTypes, props.config.metrics], () => { - queryInstanceMetrics(instances.value); + if (dashboardStore.showConfig) { + queryInstanceMetrics(instances.value); + } } ); diff --git a/src/views/dashboard/graphs/ServiceList.vue b/src/views/dashboard/graphs/ServiceList.vue index b5f1430d..71707a47 100644 --- a/src/views/dashboard/graphs/ServiceList.vue +++ b/src/views/dashboard/graphs/ServiceList.vue @@ -34,7 +34,7 @@ limitations under the License. --> diff --git a/src/views/service/Panel.vue b/src/views/service/Panel.vue index 1febb4c1..bb51cc47 100644 --- a/src/views/service/Panel.vue +++ b/src/views/service/Panel.vue @@ -50,7 +50,10 @@ import Endpoints from "./Endpoints.vue"; import Topology from "./Topology.vue"; import Traces from "./Traces.vue"; import Profiles from "./Profiles.vue"; +import { useAppStoreWithOut } from "@/store/modules/app"; +const appStore = useAppStoreWithOut(); +appStore.setPageTitle("General Service"); const route = useRoute(); const { t } = useI18n(); const tabs = ["metrics", "topologies", "endpoints", "traces", "profiles"]; @@ -69,30 +72,36 @@ function handleClick(tab: string) { .service-detail { text-align: left; } + .tabs { padding: 15px 15px 0 15px; border-bottom: 1px solid var(--el-border-color-light); } + .tab { display: inline-block; margin-right: 30px; font-size: 13px; font-weight: 400; height: 30px; + &:hover { color: var(--el-color-primary); } + &.active { color: var(--el-color-primary); border-bottom: 1px solid var(--el-color-primary); } } + .title { padding: 5px 0 5px 15px; font-size: 14px; font-weight: 400; border-bottom: 1px solid #dfe4e8; background-color: #c4c8e133; + span { display: inline-block; margin-right: 10px;