This is an automated email from the ASF dual-hosted git repository. wusheng pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/skywalking-booster-ui.git
The following commit(s) were added to refs/heads/main by this push: new 7dcc67f4 feat: implement the Status API on Settings page (#470) 7dcc67f4 is described below commit 7dcc67f455e3b85e373ee7cd28d774b41e8cfb98 Author: Fine0830 <fanxue0...@gmail.com> AuthorDate: Fri May 30 12:53:22 2025 +0800 feat: implement the Status API on Settings page (#470) --- src/graphql/base.ts | 10 +- src/graphql/{fetch.ts => custom-query.ts} | 8 +- src/graphql/fragments/app.ts | 14 +- src/graphql/{fetch.ts => http/index.ts} | 13 +- .../infrastructure.d.ts => graphql/http/url.ts} | 19 +-- src/graphql/index.ts | 4 +- src/layout/components/NavBar.vue | 7 +- src/locales/lang/en.ts | 4 + src/locales/lang/es.ts | 4 + src/locales/lang/zh.ts | 4 + src/store/modules/app.ts | 10 +- src/store/modules/dashboard.ts | 4 +- src/store/modules/settings.ts | 65 ++++++++ src/store/modules/topology.ts | 6 +- src/types/{alarm.d.ts => alarm.ts} | 0 src/types/{app.d.ts => app.ts} | 18 ++- src/types/components.d.ts | 2 + ...inous-profiling.d.ts => continous-profiling.ts} | 2 +- src/types/{dashboard.d.ts => dashboard.ts} | 0 src/types/{ebpf.d.ts => ebpf.ts} | 8 +- src/types/{events.d.ts => events.ts} | 10 +- src/types/{monaco-editor.ts => monaco-editor.d.ts} | 0 src/types/{profile.d.ts => profile.ts} | 0 src/types/{selector.d.ts => selector.ts} | 10 -- src/types/{monaco-editor.ts => settings.ts} | 15 +- src/types/{topology.d.ts => topology.ts} | 0 src/types/{trace.d.ts => trace.ts} | 3 +- src/views/Settings.vue | 168 +-------------------- src/views/alarm/Header.vue | 2 +- src/views/dashboard/related/log/Header.vue | 10 +- src/views/dashboard/related/trace/Filter.vue | 2 +- src/views/settings/Index.vue | 47 ++++++ src/views/settings/components/ClusterNodes.vue | 71 +++++++++ .../settings/components/DebuggingConfigDump.vue | 70 +++++++++ .../components/General.vue} | 19 +-- src/views/settings/components/TTL.vue | 64 ++++++++ src/views/settings/data.ts | 120 +++++++++++++++ vite.config.ts | 5 + 38 files changed, 562 insertions(+), 256 deletions(-) diff --git a/src/graphql/base.ts b/src/graphql/base.ts index 2ad064e4..7a2d33dc 100644 --- a/src/graphql/base.ts +++ b/src/graphql/base.ts @@ -34,23 +34,23 @@ class HTTPError extends Error { } } -const BasePath = `/graphql`; +export const BasePath = `/graphql`; export async function httpQuery({ - path = "", + url = "", method = "GET", json, headers = {}, }: { - path?: string; method: string; json: unknown; - headers: Recordable; + headers?: Recordable; + url: string; }) { const timeoutId = setTimeout(() => { abortRequestsAndUpdate(); }, Timeout); - const url = `${BasePath}${path}`; + const response: Response = await fetch(url, { method, headers: { diff --git a/src/graphql/fetch.ts b/src/graphql/custom-query.ts similarity index 85% copy from src/graphql/fetch.ts copy to src/graphql/custom-query.ts index f475c6a4..376dcf6d 100644 --- a/src/graphql/fetch.ts +++ b/src/graphql/custom-query.ts @@ -14,13 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { httpQuery } from "./base"; +import { httpQuery, BasePath } from "./base"; -async function fetchQuery(param: { queryStr: string; conditions: { [key: string]: unknown } }) { +async function customQuery(param: { queryStr: string; conditions: { [key: string]: unknown } }) { const response = await httpQuery({ + url: BasePath, method: "post", json: { query: param.queryStr, variables: { ...param.conditions } }, - headers: {}, }); if (response.errors) { response.errors = response.errors.map((e: { message: string }) => e.message).join(" "); @@ -28,4 +28,4 @@ async function fetchQuery(param: { queryStr: string; conditions: { [key: string] return response; } -export default fetchQuery; +export default customQuery; diff --git a/src/graphql/fragments/app.ts b/src/graphql/fragments/app.ts index a91f07e6..e3f7551b 100644 --- a/src/graphql/fragments/app.ts +++ b/src/graphql/fragments/app.ts @@ -52,10 +52,16 @@ export const MenuItems = { export const RecordsTTL = { query: `getRecordsTTL { - value - superDataset - coldValue - coldSuperDataset + normal + trace + zipkinTrace + log + browserErrorLog + coldNormal + coldTrace + coldZipkinTrace + coldLog + coldBrowserErrorLog }`, }; export const MetricsTTL = { diff --git a/src/graphql/fetch.ts b/src/graphql/http/index.ts similarity index 78% rename from src/graphql/fetch.ts rename to src/graphql/http/index.ts index f475c6a4..d9825404 100644 --- a/src/graphql/fetch.ts +++ b/src/graphql/http/index.ts @@ -14,18 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { httpQuery } from "./base"; +import { httpQuery } from "../base"; +import { HttpURL } from "./url"; -async function fetchQuery(param: { queryStr: string; conditions: { [key: string]: unknown } }) { +export default async function fetchQuery({ method, json, path }: { method: string; json?: unknown; path: string }) { const response = await httpQuery({ - method: "post", - json: { query: param.queryStr, variables: { ...param.conditions } }, - headers: {}, + method, + json, + url: (HttpURL as { [key: string]: string })[path], }); if (response.errors) { response.errors = response.errors.map((e: { message: string }) => e.message).join(" "); } return response; } - -export default fetchQuery; diff --git a/src/types/infrastructure.d.ts b/src/graphql/http/url.ts similarity index 73% rename from src/types/infrastructure.d.ts rename to src/graphql/http/url.ts index 788f0102..695f1acd 100644 --- a/src/types/infrastructure.d.ts +++ b/src/graphql/http/url.ts @@ -14,18 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export interface HexagonCreateParams { - hexagonParam: number[]; - count: number; - radius: number; - origin?: number[]; - getShader?: any; -} -export interface HexagonGeo { - vertices: number[]; - normals: number[]; - insCenters: number[]; - indices: number[]; - origins: number[]; -} +export const HttpURL = { + ClusterNodes: `/api/status/cluster/nodes`, + ConfigTTL: `/api/status/config/ttl`, + DebuggingConfigDump: `/api/debugging/config/dump`, +}; diff --git a/src/graphql/index.ts b/src/graphql/index.ts index 435118d6..9c72887c 100644 --- a/src/graphql/index.ts +++ b/src/graphql/index.ts @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { httpQuery } from "./base"; +import { httpQuery, BasePath } from "./base"; import * as app from "./query/app"; import * as selector from "./query/selector"; import * as dashboard from "./query/dashboard"; @@ -50,8 +50,8 @@ class Graphql { } async params(variables: unknown) { const response = await httpQuery({ + url: BasePath, method: "post", - headers: {}, json: { query: query[this.queryData], variables, diff --git a/src/layout/components/NavBar.vue b/src/layout/components/NavBar.vue index ba7626da..274f3912 100644 --- a/src/layout/components/NavBar.vue +++ b/src/layout/components/NavBar.vue @@ -222,9 +222,9 @@ limitations under the License. --> appStore.setDuration(timeFormat(val)); } - function setTTL() { - getMetricsTTL(); - getRecordsTTL(); + async function setTTL() { + await getMetricsTTL(); + await getRecordsTTL(); changeDataMode(); } async function getRecordsTTL() { @@ -250,6 +250,7 @@ limitations under the License. --> } const gap = Math.max(day, hour, minute); const dates: Date[] = [new Date(new Date().getTime() - dayToMS(gap + 1)), new Date()]; + appStore.setMaxRange(dates); } diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts index 75597f1e..12de6d03 100644 --- a/src/locales/lang/en.ts +++ b/src/locales/lang/en.ts @@ -397,5 +397,9 @@ const msg = { instances: "Instances", snapshot: "Snapshot", expression: "Expression", + metricsTTL: "Metrics TTL", + recordsTTL: "Records TTL", + clusterNodes: "Cluster Nodes", + debuggingConfigDump: "Dump Effective Configurations", }; export default msg; diff --git a/src/locales/lang/es.ts b/src/locales/lang/es.ts index 1e714278..3a8dc0b2 100644 --- a/src/locales/lang/es.ts +++ b/src/locales/lang/es.ts @@ -397,5 +397,9 @@ const msg = { snapshot: "Snapshot", expression: "Expression", asSelector: "As Selector", + metricsTTL: "Metrics TTL", + recordsTTL: "Records TTL", + clusterNodes: "Cluster Nodes", + debuggingConfigDump: "Dump Effective Configurations", }; export default msg; diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts index b6c1fbb8..72b548cf 100644 --- a/src/locales/lang/zh.ts +++ b/src/locales/lang/zh.ts @@ -395,5 +395,9 @@ const msg = { instances: "实例", snapshot: "快照", expression: "表达式", + metricsTTL: "Metrics TTL", + recordsTTL: "Records TTL", + clusterNodes: "集群节点", + debuggingConfigDump: "转储有效配置", }; export default msg; diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index 5cfc40af..58a1d4bf 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -223,12 +223,12 @@ export const appStore = defineStore({ return res.data; }, async queryMetricsTTL() { - const res = await graphql.query("queryMetricsTTL").params({}); - if (res.errors) { - return res; + const response = await graphql.query("queryMetricsTTL").params({}); + if (response.errors) { + return response; } - this.metricsTTL = res.data.getMetricsTTL; - return res.data; + this.metricsTTL = response.data.getMetricsTTL; + return response.data; }, async queryRecordsTTL() { const res = await graphql.query("queryRecordsTTL").params({}); diff --git a/src/store/modules/dashboard.ts b/src/store/modules/dashboard.ts index 1eb35f71..57ee704d 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 type { LayoutConfig } from "@/types/dashboard"; import graphql from "@/graphql"; -import fetchQuery from "@/graphql/fetch"; +import customQuery from "@/graphql/custom-query"; import type { DashboardItem } from "@/types/dashboard"; import { useSelectorStore } from "@/store/modules/selectors"; import { NewControl, TextConfig, TimeRangeConfig, ControlsTypes } from "../data"; @@ -299,7 +299,7 @@ export const dashboardStore = defineStore({ } }, async fetchMetricValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) { - return await fetchQuery(param); + return await customQuery(param); }, async fetchTemplates() { const res = await graphql.query("getTemplates").params({}); diff --git a/src/store/modules/settings.ts b/src/store/modules/settings.ts new file mode 100644 index 00000000..e9dd3708 --- /dev/null +++ b/src/store/modules/settings.ts @@ -0,0 +1,65 @@ +/** + * 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 { defineStore } from "pinia"; +import { store } from "@/store"; +import fetchQuery from "@/graphql/http"; +import type { ClusterNode, ConfigTTL } from "@/types/settings"; + +interface SettingsState { + clusterNodes: ClusterNode[]; + debuggingConfig: Indexable<string>; + configTTL: Recordable<ConfigTTL>; +} + +export const settingsStore = defineStore({ + id: "settings", + state: (): SettingsState => ({ + clusterNodes: [], + debuggingConfig: {}, + configTTL: {}, + }), + actions: { + async getClusterNodes() { + const response = await fetchQuery({ + method: "get", + path: "ClusterNodes", + }); + this.clusterNodes = response.nodes; + return response; + }, + async getConfigTTL() { + const response = await fetchQuery({ + method: "get", + path: "ConfigTTL", + }); + this.configTTL = response; + return response; + }, + async getDebuggingConfigDump() { + const response = await fetchQuery({ + method: "get", + path: "DebuggingConfigDump", + }); + this.debuggingConfig = response; + return response; + }, + }, +}); + +export function useSettingsStore(): Recordable { + return settingsStore(store); +} diff --git a/src/store/modules/topology.ts b/src/store/modules/topology.ts index b16d7611..081aa4be 100644 --- a/src/store/modules/topology.ts +++ b/src/store/modules/topology.ts @@ -21,7 +21,7 @@ import graphql from "@/graphql"; import { useSelectorStore } from "@/store/modules/selectors"; import { useDashboardStore } from "@/store/modules/dashboard"; import { useAppStoreWithOut } from "@/store/modules/app"; -import fetchQuery from "@/graphql/fetch"; +import customQuery from "@/graphql/custom-query"; import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor"; interface MetricVal { @@ -431,7 +431,7 @@ export const topologyStore = defineStore({ }); const queryStr = `query queryData(${variables}) {${fragment}}`; const conditions = { duration }; - const res = await fetchQuery({ queryStr, conditions }); + const res = await customQuery({ queryStr, conditions }); if (res.errors) { return res; @@ -448,7 +448,7 @@ export const topologyStore = defineStore({ return { calls, nodes }; }, async getTopologyExpressionValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) { - const res = await fetchQuery(param); + const res = await customQuery(param); if (res.errors) { return res; diff --git a/src/types/alarm.d.ts b/src/types/alarm.ts similarity index 100% rename from src/types/alarm.d.ts rename to src/types/alarm.ts diff --git a/src/types/app.d.ts b/src/types/app.ts similarity index 88% rename from src/types/app.d.ts rename to src/types/app.ts index 36958b54..b7fa8150 100644 --- a/src/types/app.d.ts +++ b/src/types/app.ts @@ -39,14 +39,12 @@ export type EventParams = { seriesIndex: number; seriesName: string; name: string; - dataIndex: number; data: unknown; dataType: string; value: number | any[]; color: string; - event: Record<string, T>; + event: Recordable; dataIndex: number; - event: any; }; export interface MenuOptions extends SubItem { @@ -79,8 +77,14 @@ export interface MetricsTTL { } export interface RecordsTTL { - value: number; - superDataset: number; - coldValue: number; - coldSuperDataset: number; + normal: number; + trace: number; + zipkinTrace: number; + log: number; + browserErrorLog: number; + coldNormal: number; + coldTrace: number; + coldZipkinTrace: number; + coldLog: number; + coldBrowserErrorLog: number; } diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 64e8c17e..56f60832 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -42,6 +42,8 @@ declare module 'vue' { ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElTable: typeof import('element-plus/es')['ElTable'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] + ElTabPane: typeof import('element-plus/es')['ElTabPane'] + ElTabs: typeof import('element-plus/es')['ElTabs'] ElTag: typeof import('element-plus/es')['ElTag'] ElTooltip: typeof import('element-plus/es')['ElTooltip'] Graph: typeof import('./../components/Graph/Graph.vue')['default'] diff --git a/src/types/continous-profiling.d.ts b/src/types/continous-profiling.ts similarity index 97% rename from src/types/continous-profiling.d.ts rename to src/types/continous-profiling.ts index 98c5b121..50dce59b 100644 --- a/src/types/continous-profiling.d.ts +++ b/src/types/continous-profiling.ts @@ -35,7 +35,7 @@ export interface MonitorInstance { lastTriggerTimestamp: number; processes: MonitorProcess[]; } -interface MonitorProcess { +export interface MonitorProcess { id: string; name: string; detectType: string; diff --git a/src/types/dashboard.d.ts b/src/types/dashboard.ts similarity index 100% rename from src/types/dashboard.d.ts rename to src/types/dashboard.ts diff --git a/src/types/ebpf.d.ts b/src/types/ebpf.ts similarity index 95% rename from src/types/ebpf.d.ts rename to src/types/ebpf.ts index 53badf56..53f84d32 100644 --- a/src/types/ebpf.d.ts +++ b/src/types/ebpf.ts @@ -15,7 +15,8 @@ * limitations under the License. */ -import type { Process } from "./selector"; +import type { Process as selectorProcess } from "./selector"; + export interface EBPFTaskCreationRequest { serviceId: string; processLabels: string[]; @@ -58,12 +59,12 @@ interface ProfilingCause { export interface EBPFProfilingSchedule { scheduleId: string; taskId: string; - process: Process; + process: selectorProcess; endTime: number; startTime: number; } -export type Process = Process; +export type Process = selectorProcess; export type StackElement = { id: string; originId: string; @@ -106,7 +107,6 @@ export type ProcessNode = { serviceName: string; serviceInstanceId: string; serviceInstanceName: string; - name: string; isReal: boolean; x?: number; y?: number; diff --git a/src/types/events.d.ts b/src/types/events.ts similarity index 90% rename from src/types/events.d.ts rename to src/types/events.ts index e4684134..5c1dc7a7 100644 --- a/src/types/events.d.ts +++ b/src/types/events.ts @@ -14,11 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import type { Duration } from "./app"; + +const enum EventType { + ALL = "", + NORMAL = "Normal", + ERROR = "Error", +} + export type Event = { uuid: string; source: SourceInput; name: string; - type: string; + type: EventType; message: string; parameters: { key: string; value: string }[]; startTime: number | string; diff --git a/src/types/monaco-editor.ts b/src/types/monaco-editor.d.ts similarity index 100% copy from src/types/monaco-editor.ts copy to src/types/monaco-editor.d.ts diff --git a/src/types/profile.d.ts b/src/types/profile.ts similarity index 100% rename from src/types/profile.d.ts rename to src/types/profile.ts diff --git a/src/types/selector.d.ts b/src/types/selector.ts similarity index 90% rename from src/types/selector.d.ts rename to src/types/selector.ts index cf8b07d5..928e1244 100644 --- a/src/types/selector.d.ts +++ b/src/types/selector.ts @@ -42,16 +42,6 @@ export type Endpoint = { merge?: string; }; -export type Service = { - id: string; - value: string; - label: string; - group: string; - normal: boolean; - layers: string[]; - shortName: string; -}; - export type Process = { id: string; name: string; diff --git a/src/types/monaco-editor.ts b/src/types/settings.ts similarity index 78% rename from src/types/monaco-editor.ts rename to src/types/settings.ts index ebf98eaf..5a345107 100644 --- a/src/types/monaco-editor.ts +++ b/src/types/settings.ts @@ -14,5 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -declare module "monaco-editor"; -export {}; + +import type { MetricsTTL, RecordsTTL } from "@/types/app"; + +export type ClusterNode = { + host: string; + port: number; + self: boolean; +}; + +export type ConfigTTL = { + metrics: MetricsTTL; + records: RecordsTTL; +}; diff --git a/src/types/topology.d.ts b/src/types/topology.ts similarity index 100% rename from src/types/topology.d.ts rename to src/types/topology.ts diff --git a/src/types/trace.d.ts b/src/types/trace.ts similarity index 98% rename from src/types/trace.d.ts rename to src/types/trace.ts index 8d8d4457..a78db87e 100644 --- a/src/types/trace.d.ts +++ b/src/types/trace.ts @@ -47,7 +47,6 @@ export interface Span { tags?: Array<Map<string, string>>; logs?: log[]; parentSegmentId?: string; - refs?: Ref[]; key?: string; } export type Ref = { @@ -75,7 +74,7 @@ export interface StatisticsGroupRef { type: string; } -export class TraceTreeRef { +export interface TraceTreeRef { segmentMap: Map<string, Span>; segmentIdGroup: string[]; } diff --git a/src/views/Settings.vue b/src/views/Settings.vue index 12e139e6..e2530337 100644 --- a/src/views/Settings.vue +++ b/src/views/Settings.vue @@ -13,172 +13,8 @@ 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="settings"> - <div class="flex-h item"> - <span class="label">{{ t("language") }}</span> - <Selector - v-model="lang" - :options="Languages" - placeholder="Select a language" - @change="setLang" - size="small" - style="font-size: 14px; width: 180px" - /> - </div> - <div class="flex-h item"> - <span class="label">{{ t("serverZone") }}</span> - <div> - <span>UTC</span> - <span class="ml-5 mr-5">{{ utcHour >= 0 ? "+" : "" }}</span> - <input type="number" v-model="utcHour" min="-12" max="14" class="utc-input" @change="setUTCHour" /> - <span class="ml-5 mr-5">:</span> - <span class="utc-min">{{ utcMin > 9 || utcMin === 0 ? null : 0 }}</span> - <input type="number" v-model="utcMin" min="0" max="59" class="utc-input" @change="setUTCMin" /> - </div> - </div> - <div class="flex-h item"> - <span class="label">{{ t("auto") }}</span> - <el-switch v-model="auto" @change="handleAuto" style="height: 25px" /> - <div class="auto-time ml-5"> - <span class="auto-select"> - <input type="number" v-model="autoTime" @change="changeAutoTime" min="1" /> - </span> - {{ t("second") }} - <i class="ml-10">{{ t("timeReload") }}</i> - </div> - </div> - </div> + <Content /> </template> <script lang="ts" setup> - import { ref } from "vue"; - import { useI18n } from "vue-i18n"; - import { useAppStoreWithOut } from "@/store/modules/app"; - import timeFormat from "@/utils/timeFormat"; - import { Languages } from "@/constants/data"; - import Selector from "@/components/Selector.vue"; - import getLocalTime from "@/utils/localtime"; - - const { t, locale } = useI18n(); - const appStore = useAppStoreWithOut(); - const lang = ref<string>(locale.value || "en"); - const autoTime = ref<number>(6); - const auto = ref<boolean>(appStore.autoRefresh || false); - const utcHour = ref<number>(appStore.utcHour); - const utcMin = ref<number>(appStore.utcMin); - - const handleReload = () => { - const gap = appStore.duration.end.getTime() - appStore.duration.start.getTime(); - const dates: Date[] = [ - getLocalTime(appStore.utc, new Date(new Date().getTime() - gap)), - getLocalTime(appStore.utc, new Date()), - ]; - appStore.setDuration(timeFormat(dates)); - }; - const handleAuto = () => { - if (autoTime.value < 1) { - return; - } - appStore.setAutoRefresh(auto.value); - if (auto.value) { - handleReload(); - appStore.setReloadTimer(setInterval(handleReload, autoTime.value * 1000)); - } else { - if (appStore.reloadTimer) { - clearInterval(appStore.reloadTimer); - } - } - }; - const changeAutoTime = () => { - if (autoTime.value < 1) { - return; - } - if (appStore.reloadTimer) { - clearInterval(appStore.reloadTimer); - } - if (auto.value) { - handleReload(); - appStore.setReloadTimer(setInterval(handleReload, autoTime.value * 1000)); - } - }; - const setLang = (): void => { - locale.value = lang.value; - window.localStorage.setItem("language", lang.value); - }; - const setUTCHour = () => { - if (utcHour.value < -12) { - utcHour.value = -12; - } - if (utcHour.value > 14) { - utcHour.value = 14; - } - if (isNaN(utcHour.value)) { - utcHour.value = 0; - } - appStore.setUTC(utcHour.value, utcMin.value); - }; - const setUTCMin = () => { - if (utcMin.value < 0) { - utcMin.value = 0; - } - if (utcMin.value > 59) { - utcMin.value = 59; - } - if (isNaN(utcMin.value)) { - utcMin.value = 0; - } - appStore.setUTC(utcHour.value, utcMin.value); - }; + import Content from "./settings/Index.vue"; </script> -<style lang="scss" scoped> - .utc-input { - color: inherit; - background: 0; - border: 0; - outline: none; - padding-bottom: 0; - } - - .utc-min { - display: inline-block; - padding-top: 2px; - } - - .auto-select { - border-radius: 3px; - background-color: $theme-background; - padding: 1px; - - input { - width: 38px; - border-style: unset; - outline: 0; - } - } - - .settings { - color: var(--sw-setting-color); - font-size: 13px; - padding: 20px; - - .item { - margin-top: 10px; - } - - input { - outline: 0; - width: 50px; - border-radius: 3px; - border: 1px solid $disabled-color; - text-align: center; - height: 25px; - } - - .label { - width: 180px; - display: inline-block; - font-weight: 500; - color: $font-color; - line-height: 25px; - } - } -</style> diff --git a/src/views/alarm/Header.vue b/src/views/alarm/Header.vue index 869743d9..5d01988f 100644 --- a/src/views/alarm/Header.vue +++ b/src/views/alarm/Header.vue @@ -87,7 +87,7 @@ limitations under the License. --> alarmStore.alarms.length === pageSize ? pageSize * pageNum.value + 1 : pageSize * pageNum.value, ); const maxRange = computed(() => - getMaxRange(appStore.coldStageMode ? appStore.recordsTTL.coldValue : appStore.recordsTTL.value), + getMaxRange(appStore.coldStageMode ? appStore.recordsTTL.coldNormal : appStore.recordsTTL.normal), ); refreshAlarms({ pageNum: 1 }); diff --git a/src/views/dashboard/related/log/Header.vue b/src/views/dashboard/related/log/Header.vue index 856b366b..04a94b22 100644 --- a/src/views/dashboard/related/log/Header.vue +++ b/src/views/dashboard/related/log/Header.vue @@ -176,7 +176,15 @@ limitations under the License. --> category: { value: "ALL", label: "All" }, }); const maxRange = computed(() => - getMaxRange(appStore.coldStageMode ? appStore.recordsTTL.coldSuperDataset : appStore.recordsTTL.superDataset), + getMaxRange( + appStore.coldStageMode + ? isBrowser.value + ? appStore.recordsTTL.coldBrowserErrorLog + : appStore.recordsTTL.coldLog + : isBrowser.value + ? appStore.recordsTTL.browserErrorLog + : appStore.recordsTTL.log, + ), ); if (props.needQuery) { init(); diff --git a/src/views/dashboard/related/trace/Filter.vue b/src/views/dashboard/related/trace/Filter.vue index 9652b44c..95e39aca 100644 --- a/src/views/dashboard/related/trace/Filter.vue +++ b/src/views/dashboard/related/trace/Filter.vue @@ -132,7 +132,7 @@ limitations under the License. --> }); const durationRow = ref<Duration>(InitializationDurationRow); const maxRange = computed(() => - getMaxRange(appStore.coldStageMode ? appStore.recordsTTL.coldSuperDataset : appStore.recordsTTL.superDataset), + getMaxRange(appStore.coldStageMode ? appStore.recordsTTL.coldTrace : appStore.recordsTTL.trace), ); if (filters.queryOrder) { traceStore.setTraceCondition({ diff --git a/src/views/settings/Index.vue b/src/views/settings/Index.vue new file mode 100644 index 00000000..604bc72f --- /dev/null +++ b/src/views/settings/Index.vue @@ -0,0 +1,47 @@ +<!-- 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> + <el-tabs v-model="activeName" class="settings-tabs"> + <el-tab-pane v-for="tab in SettingsTabs" :label="tab.label" :name="tab.value" :key="tab.value"> + <component :is="TabPanes[tab.value]" /> + </el-tab-pane> + </el-tabs> +</template> +<script lang="ts" setup> + import { ref } from "vue"; + import { SettingsTabs } from "./data"; + import ClusterNodes from "./components/ClusterNodes.vue"; + import General from "./components/General.vue"; + import TTL from "./components/TTL.vue"; + import DebuggingConfigDump from "./components/DebuggingConfigDump.vue"; + /*global Indexable*/ + const TabPanes: Indexable = { + general: General, + ttl: TTL, + clusterNodes: ClusterNodes, + dumpEffectiveConfigurations: DebuggingConfigDump, + }; + const activeName = ref(SettingsTabs[0].value); +</script> +<style lang="scss" scoped> + .settings-tabs { + padding: 10px 20px; + } + + .settings-tabs > .el-tabs__content { + color: var(--sw-setting-color); + padding-top: 10px; + } +</style> diff --git a/src/views/settings/components/ClusterNodes.vue b/src/views/settings/components/ClusterNodes.vue new file mode 100644 index 00000000..8407baeb --- /dev/null +++ b/src/views/settings/components/ClusterNodes.vue @@ -0,0 +1,71 @@ +<!-- 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="cluster-nodes"> + <el-table + :data="settingsStore.clusterNodes" + class="mb-5" + :row-style="{ backgroundColor: 'var(--layout-background)' }" + > + <el-table-column + v-for="item in ClusterNodeRow" + :prop="item.value" + :label="item.label" + :key="item.value" + :width="item.width" + /> + </el-table> + <el-pagination + class="pagination" + layout="prev, pager, next" + :page-size="pageSize" + :total="settingsStore.clusterNodes.length" + v-model="currentPage" + @current-change="changePage" + @prev-click="changePage" + @next-click="changePage" + /> + </div> +</template> +<script lang="ts" setup> + import { ref, onMounted } from "vue"; + import { useSettingsStore } from "@/store/modules/settings"; + import { ClusterNodeRow } from "../data"; + + const settingsStore = useSettingsStore(); + const pageSize = 16; + const currentPage = ref<number>(1); + + onMounted(() => { + settingsStore.getClusterNodes(); + }); + + const changePage = (pageIndex: number) => { + currentPage.value = pageIndex; + }; +</script> +<style lang="scss" scoped> + .cluster-nodes { + font-size: 13px; + width: 100%; + } + + .label { + width: 200px; + display: inline-block; + font-weight: 500; + color: $font-color; + } +</style> diff --git a/src/views/settings/components/DebuggingConfigDump.vue b/src/views/settings/components/DebuggingConfigDump.vue new file mode 100644 index 00000000..6a8bd983 --- /dev/null +++ b/src/views/settings/components/DebuggingConfigDump.vue @@ -0,0 +1,70 @@ +<!-- 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="debugging-config-dump"> + <div class="config-dump-content"> + <div + class="mb-10 flex-h" + v-for="(item, index) of Object.keys(settingsStore.debuggingConfig)" + :key="`${item}${index}`" + > + <div class="config-key">{{ item }}: </div> + <div>{{ settingsStore.debuggingConfig[item] }}</div> + </div> + <div v-if="!Object.keys(settingsStore.debuggingConfig).length" class="tips">No Data</div> + </div> + </div> +</template> +<script lang="ts" setup> + import { onMounted } from "vue"; + import { useSettingsStore } from "@/store/modules/settings"; + + const settingsStore = useSettingsStore(); + + onMounted(() => { + settingsStore.getDebuggingConfigDump(); + }); +</script> +<style lang="scss" scoped> + .config-dump-content { + border: 1px solid var(--el-color-info-light-8); + overflow: auto; + padding: 5px; + border-radius: 5px 3px; + height: 700px; + } + + .tips { + text-align: center; + width: 100%; + color: var(--el-text-color-secondary); + } + + .config-key { + width: 30%; + } + + .debugging-config-dump { + color: var(--sw-setting-color); + font-size: 13px; + } + + .label { + width: 200px; + display: inline-block; + font-weight: 500; + color: $font-color; + } +</style> diff --git a/src/views/Settings.vue b/src/views/settings/components/General.vue similarity index 93% copy from src/views/Settings.vue copy to src/views/settings/components/General.vue index 12e139e6..40d16049 100644 --- a/src/views/Settings.vue +++ b/src/views/settings/components/General.vue @@ -13,9 +13,9 @@ 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="settings"> + <div class="general-settings"> <div class="flex-h item"> - <span class="label">{{ t("language") }}</span> + <div class="label">{{ t("language") }}</div> <Selector v-model="lang" :options="Languages" @@ -26,7 +26,7 @@ limitations under the License. --> /> </div> <div class="flex-h item"> - <span class="label">{{ t("serverZone") }}</span> + <div class="label">{{ t("serverZone") }}</div> <div> <span>UTC</span> <span class="ml-5 mr-5">{{ utcHour >= 0 ? "+" : "" }}</span> @@ -37,7 +37,7 @@ limitations under the License. --> </div> </div> <div class="flex-h item"> - <span class="label">{{ t("auto") }}</span> + <div class="label">{{ t("auto") }}</div> <el-switch v-model="auto" @change="handleAuto" style="height: 25px" /> <div class="auto-time ml-5"> <span class="auto-select"> @@ -155,13 +155,11 @@ limitations under the License. --> } } - .settings { - color: var(--sw-setting-color); + .general-settings { font-size: 13px; - padding: 20px; .item { - margin-top: 10px; + margin-top: 15px; } input { @@ -174,11 +172,10 @@ limitations under the License. --> } .label { - width: 180px; + width: 200px; display: inline-block; - font-weight: 500; color: $font-color; - line-height: 25px; + font-weight: 500; } } </style> diff --git a/src/views/settings/components/TTL.vue b/src/views/settings/components/TTL.vue new file mode 100644 index 00000000..4e0ba92e --- /dev/null +++ b/src/views/settings/components/TTL.vue @@ -0,0 +1,64 @@ +<!-- 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="ttl"> + <div class="label">{{ t("metricsTTL") }}</div> + <el-table + :data="[settingsStore.configTTL.metrics]" + class="mb-5" + :row-style="{ backgroundColor: 'var(--layout-background)' }" + > + <el-table-column v-for="item in MetricsTTLRow" :prop="item.value" :label="item.label" :key="item.value"> + <template #default="scope">{{ scope.row[item.value] < 0 ? "N/A" : scope.row[item.value] }}</template> + </el-table-column> + </el-table> + <div class="label">{{ t("recordsTTL") }}</div> + <el-table + :data="[settingsStore.configTTL.records]" + class="mb-5" + :row-style="{ backgroundColor: 'var(--layout-background)' }" + > + <el-table-column v-for="item in RecordsTTLRow" :prop="item.value" :label="item.label" :key="item.value"> + <template #default="scope">{{ scope.row[item.value] < 0 ? "N/A" : scope.row[item.value] }}</template> + </el-table-column> + </el-table> + </div> +</template> +<script lang="ts" setup> + import { onMounted } from "vue"; + import { useI18n } from "vue-i18n"; + import { useSettingsStore } from "@/store/modules/settings"; + import { MetricsTTLRow, RecordsTTLRow } from "../data"; + + const { t } = useI18n(); + const settingsStore = useSettingsStore(); + + onMounted(() => { + settingsStore.getConfigTTL(); + }); +</script> +<style lang="scss" scoped> + .ttl { + color: var(--sw-setting-color); + font-size: 13px; + + .label { + margin: 15px 0; + display: inline-block; + font-weight: 600; + color: $font-color; + } + } +</style> diff --git a/src/views/settings/data.ts b/src/views/settings/data.ts new file mode 100644 index 00000000..83adaea8 --- /dev/null +++ b/src/views/settings/data.ts @@ -0,0 +1,120 @@ +/** + * 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 const ClusterNodeRow = [ + { + label: "Host", + value: "host", + }, + { + label: "Port", + value: "port", + width: 180, + }, + { + label: "Self", + value: "self", + width: 180, + }, +]; + +export const SettingsTabs = [ + { + label: "General", + value: "general", + }, + { + label: "TTL", + value: "ttl", + }, + { + label: "Cluster Nodes", + value: "clusterNodes", + }, + { + label: "Dump Effective Configurations", + value: "dumpEffectiveConfigurations", + }, +]; +export const MetricsTTLRow = [ + { + label: "Day", + value: "day", + }, + { + label: "Hour", + value: "hour", + }, + { + label: "Minute", + value: "minute", + }, + { + label: "Cold Day", + value: "coldDay", + }, + { + label: "Cold Hour", + value: "coldHour", + }, + { + label: "Cold Minute", + value: "coldMinute", + }, +]; + +export const RecordsTTLRow = [ + { + label: "Normal", + value: "normal", + }, + { + label: "Trace", + value: "trace", + }, + { + label: "Log", + value: "log", + }, + { + label: "Zipkin Trace", + value: "zipkinTrace", + }, + { + label: "Browser Error Log", + value: "browserErrorLog", + }, + { + label: "Cold Normal", + value: "coldNormal", + }, + { + label: "Cold Trace", + value: "coldTrace", + }, + { + label: "Cold Zipkin Trace", + value: "coldZipkinTrace", + }, + { + label: "Cold Log", + value: "coldLog", + }, + { + label: "Cold Browser Error Log", + value: "coldBrowserErrorLog", + }, +]; diff --git a/vite.config.ts b/vite.config.ts index 0928bd3b..ebd5ce9e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -75,6 +75,11 @@ export default ({ mode }: ConfigEnv): UserConfig => { target: `${VITE_SW_PROXY_TARGET || "http://127.0.0.1:12800"}`, changeOrigin: true, }, + "/api": { + target: `${VITE_SW_PROXY_TARGET || "http://127.0.0.1:12800"}`, + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api/, ""), + }, }, }, build: {