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>