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 867af692 feat: add `expressions` to dashboard configurations on the 
dashboard list page (#358)
867af692 is described below

commit 867af6924d86a121d9fca0336b2f48d3f31326f5
Author: Fine0830 <[email protected]>
AuthorDate: Thu Jan 11 13:40:37 2024 +0800

    feat: add `expressions` to dashboard configurations on the dashboard list 
page (#358)
---
 src/components/Tags.vue      |  9 ++++-
 src/locales/lang/en.ts       |  1 +
 src/locales/lang/es.ts       |  1 +
 src/locales/lang/zh.ts       |  1 +
 src/types/dashboard.d.ts     |  1 +
 src/views/dashboard/List.vue | 93 +++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 104 insertions(+), 2 deletions(-)

diff --git a/src/components/Tags.vue b/src/components/Tags.vue
index 90fb670c..b854843a 100644
--- a/src/components/Tags.vue
+++ b/src/components/Tags.vue
@@ -31,7 +31,7 @@ limitations under the License. -->
 </template>
 
 <script lang="ts" setup>
-  import { nextTick, ref } from "vue";
+  import { nextTick, ref, watch } from "vue";
   import type { PropType } from "vue";
   import { ElInput } from "element-plus";
 
@@ -69,6 +69,13 @@ limitations under the License. -->
     inputValue.value = "";
     emits("change", dynamicTags.value);
   };
+
+  watch(
+    () => props.tags,
+    () => {
+      dynamicTags.value = props.tags || [];
+    },
+  );
 </script>
 <style lang="scss" scoped>
   .input-name {
diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts
index 30622ea0..746831fc 100644
--- a/src/locales/lang/en.ts
+++ b/src/locales/lang/en.ts
@@ -385,5 +385,6 @@ const msg = {
   traceDesc:
     "The trace segment serves as a representation of a trace portion executed 
within one single OS process, such as a JVM. It comprises a collection of 
spans, typically associated with and collected from a single request or 
execution context.",
   tabExpressions: "Tab Expressions",
+  hierarchyNodeMetrics: "Metrics related with hierarchy topology nodes",
 };
 export default msg;
diff --git a/src/locales/lang/es.ts b/src/locales/lang/es.ts
index 18a2d46f..ae226a61 100644
--- a/src/locales/lang/es.ts
+++ b/src/locales/lang/es.ts
@@ -385,5 +385,6 @@ const msg = {
   traceDesc:
     "The trace segment serves as a representation of a trace portion executed 
within one single OS process, such as a JVM. It comprises a collection of 
spans, typically associated with and collected from a single request or 
execution context.",
   tabExpressions: "Tab Expressions",
+  hierarchyNodeMetrics: "Metrics related with hierarchy topology nodes",
 };
 export default msg;
diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts
index 36962afc..9aab7cf2 100644
--- a/src/locales/lang/zh.ts
+++ b/src/locales/lang/zh.ts
@@ -383,5 +383,6 @@ const msg = {
   traceDesc:
     "Trace 
Segment代表在单一操作系统进程(例如JVM)中执行的追踪部分。它包含了一组跨度(spans),这些跨度通常与单一请求或执行上下文关联。",
   tabExpressions: "Tab表达式",
+  hierarchyNodeMetrics: "层级拓扑节点关联的指标",
 };
 export default msg;
diff --git a/src/types/dashboard.d.ts b/src/types/dashboard.d.ts
index 3f6aba05..0af42859 100644
--- a/src/types/dashboard.d.ts
+++ b/src/types/dashboard.d.ts
@@ -22,6 +22,7 @@ export type DashboardItem = {
   isRoot: boolean;
   name: string;
   isDefault: boolean;
+  expressions?: string[];
 };
 export interface LayoutConfig {
   x: number;
diff --git a/src/views/dashboard/List.vue b/src/views/dashboard/List.vue
index 25373068..f9489ce0 100644
--- a/src/views/dashboard/List.vue
+++ b/src/views/dashboard/List.vue
@@ -78,7 +78,7 @@ limitations under the License. -->
             <el-popconfirm
               :title="t('rootTitle')"
               @confirm="handleTopLevel(scope.row)"
-              v-if="[EntityType[0].value].includes(scope.row.entity)"
+              v-if="[EntityType[0].value, 
EntityType[3].value].includes(scope.row.entity)"
             >
               <template #reference>
                 <el-button size="small" style="width: 80px">
@@ -97,6 +97,13 @@ limitations under the License. -->
             <el-button size="small" @click="handleRename(scope.row)">
               {{ t("rename") }}
             </el-button>
+            <el-button
+              :disabled="![EntityType[0].value, 
EntityType[3].value].includes(scope.row.entity)"
+              size="small"
+              @click="handleEditMQE(scope.row)"
+            >
+              MQE
+            </el-button>
             <el-popconfirm :title="t('deleteTitle')" 
@confirm="handleDelete(scope.row)">
               <template #reference>
                 <el-button size="small" type="danger">
@@ -139,6 +146,23 @@ limitations under the License. -->
           @next-click="changePage"
         />
       </div>
+      <el-dialog v-model="MQEVisible" title="Edit MQE" width="400px">
+        <div>{{ t("hierarchyNodeMetrics") }}</div>
+        <div class="mt-10 expressions">
+          <Tags
+            :tags="currentRow.expressions || []"
+            :vertical="true"
+            :text="t('addExpressions')"
+            @change="(param) => changeExpressions(param)"
+          />
+        </div>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button @click="MQEVisible = false">Cancel</el-button>
+            <el-button type="primary" @click="saveMQE"> Confirm </el-button>
+          </span>
+        </template>
+      </el-dialog>
     </div>
   </div>
 </template>
@@ -167,6 +191,8 @@ limitations under the License. -->
   const multipleTableRef = ref<InstanceType<typeof ElTable>>();
   const multipleSelection = ref<DashboardItem[]>([]);
   const dashboardFile = ref<Nullable<HTMLDivElement>>(null);
+  const MQEVisible = ref<boolean>(false);
+  const currentRow = ref<any>({});
 
   const handleSelectionChange = (val: DashboardItem[]) => {
     multipleSelection.value = val;
@@ -176,6 +202,55 @@ limitations under the License. -->
     await dashboardStore.setDashboards();
     searchDashboards(1);
   }
+
+  function changeExpressions(params: string[]) {
+    currentRow.value.expressions = params;
+  }
+
+  function handleEditMQE(row: DashboardItem) {
+    MQEVisible.value = !MQEVisible.value;
+    currentRow.value = row;
+  }
+
+  async function saveMQE() {
+    const items: DashboardItem[] = [];
+    loading.value = true;
+    for (const d of dashboardStore.dashboards) {
+      if (d.id === currentRow.value.id) {
+        d.expressions = currentRow.value.expressions;
+        const key = [d.layer, d.entity, d.name].join("_");
+        const layout = sessionStorage.getItem(key) || "{}";
+        const c = {
+          ...JSON.parse(layout).configuration,
+          ...d,
+        };
+        delete c.id;
+        const setting = {
+          id: d.id,
+          configuration: JSON.stringify(c),
+        };
+
+        const res = await dashboardStore.updateDashboard(setting);
+        if (res.data.changeTemplate.status) {
+          sessionStorage.setItem(
+            key,
+            JSON.stringify({
+              id: d.id,
+              configuration: c,
+            }),
+          );
+        } else {
+          loading.value = false;
+          return;
+        }
+      }
+      items.push(d);
+    }
+    dashboardStore.resetDashboards(items);
+    searchDashboards(1);
+    loading.value = false;
+  }
+
   async function importTemplates(event: any) {
     const arr: any = await readFile(event);
     for (const item of arr) {
@@ -352,6 +427,9 @@ limitations under the License. -->
               configuration: c,
             }),
           );
+        } else {
+          loading.value = false;
+          return;
         }
       } else {
         if (
@@ -380,6 +458,9 @@ limitations under the License. -->
                 configuration: c,
               }),
             );
+          } else {
+            loading.value = false;
+            return;
           }
         }
       }
@@ -416,6 +497,9 @@ limitations under the License. -->
               configuration: c,
             }),
           );
+        } else {
+          loading.value = false;
+          return;
         }
       } else {
         if (d.layer === row.layer && [EntityType[0].value].includes(d.entity) 
&& !row.isDefault && d.isDefault) {
@@ -439,6 +523,9 @@ limitations under the License. -->
                 configuration: c,
               }),
             );
+          } else {
+            loading.value = false;
+            return;
           }
         }
       }
@@ -607,4 +694,8 @@ limitations under the License. -->
     display: inline-block;
     margin-left: 10px;
   }
+
+  .expressions {
+    height: 300px;
+  }
 </style>

Reply via email to