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: {


Reply via email to