From 1377703185c83bd3bf530efdc169e5d017905c14 Mon Sep 17 00:00:00 2001 From: Fine0830 Date: Fri, 4 Mar 2022 15:35:29 +0800 Subject: [PATCH] feat: Implement adding controls in Tabs (#21) --- src/components/Icon.vue | 13 +- src/locales/lang/en.ts | 1 + src/locales/lang/zh.ts | 1 + src/router/index.ts | 3 +- src/store/modules/dashboard.ts | 105 +++++-- src/types/dashboard.ts | 1 + src/views/dashboard/Edit.vue | 1 + src/views/dashboard/controls/Tab.vue | 267 +++++++++++------- src/views/dashboard/controls/Widget.vue | 8 +- src/views/dashboard/data.ts | 6 +- src/views/dashboard/panel/Layout.vue | 1 + src/views/dashboard/panel/Tool.vue | 50 +++- .../dashboard/related/profile/Content.vue | 9 +- .../related/profile/components/SpanTree.vue | 28 +- .../trace/components/Table/TableItem.vue | 3 +- 15 files changed, 347 insertions(+), 150 deletions(-) diff --git a/src/components/Icon.vue b/src/components/Icon.vue index 10becdac..fc6a0ce1 100644 --- a/src/components/Icon.vue +++ b/src/components/Icon.vue @@ -21,7 +21,7 @@ limitations under the License. --> lg: size === 'lg', xl: size === 'xl', logo: size === 'logo', - loading: loading, + loading, }" > @@ -73,4 +73,15 @@ defineProps({ width: 30px; } } +@keyframes loading { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + to { + -webkit-transform: rotate(1turn); + transform: rotate(1turn); + } +} diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts index 29feac0c..b3649192 100644 --- a/src/locales/lang/en.ts +++ b/src/locales/lang/en.ts @@ -95,6 +95,7 @@ const msg = { topChildren: "Top 5 of children", taskList: "Task List", sampledTraces: "Sampled Traces", + editTab: "Enable editing tab names", hourTip: "Select Hour", minuteTip: "Select Minute", secondTip: "Select Second", diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts index 5764eeed..d60322cf 100644 --- a/src/locales/lang/zh.ts +++ b/src/locales/lang/zh.ts @@ -95,6 +95,7 @@ const msg = { showDepth: "展示深度选择器", taskList: "任务列表", sampledTraces: "采样的追踪", + editTab: "开启编辑Tab的名称", hourTip: "选择小时", minuteTip: "选择分钟", secondTip: "选择秒数", diff --git a/src/router/index.ts b/src/router/index.ts index 80068c3e..4ab9d190 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -26,7 +26,6 @@ import { routesEvent } from "./event"; import { routesAlert } from "./alert"; import { routesSetting } from "./setting"; import { routesAlarm } from "./alarm"; -import { useTimeoutFn } from "@/hooks/useTimeout"; const routes: Array = [ ...routesGen, @@ -52,7 +51,7 @@ router.beforeEach((to, from, next) => { // const token = window.localStorage.getItem("skywalking-authority"); if ((window as any).axiosCancel.length !== 0) { for (const func of (window as any).axiosCancel) { - useTimeoutFn(func(), 0); + setTimeout(func(), 0); } (window as any).axiosCancel = []; } diff --git a/src/store/modules/dashboard.ts b/src/store/modules/dashboard.ts index 24a19e33..ad15f257 100644 --- a/src/store/modules/dashboard.ts +++ b/src/store/modules/dashboard.ts @@ -43,6 +43,7 @@ interface DashboardState { durationTime: Duration; selectorStore: any; showTopology: boolean; + currentTabItems: LayoutConfig[]; } export const dashboardStore = defineStore({ @@ -57,6 +58,7 @@ export const dashboardStore = defineStore({ durationTime: useAppStoreWithOut().durationTime, selectorStore: useSelectorStore(), showTopology: false, + currentTabItems: [], }), actions: { setLayout(data: LayoutConfig[]) { @@ -71,7 +73,8 @@ export const dashboardStore = defineStore({ metrics: [""], }; if (type === "Tab") { - newItem.h = 24; + newItem.h = 36; + newItem.activedTabIndex = 0; newItem.children = [ { name: "Tab1", @@ -96,14 +99,15 @@ export const dashboardStore = defineStore({ }; } if (type === "Trace" || type === "Profile") { - newItem.h = 36; + newItem.h = 24; } + this.activedGridItem = newItem.i; + this.selectedGrid = newItem; this.layout = this.layout.map((d: LayoutConfig) => { d.y = d.y + newItem.h; return d; }); this.layout.push(newItem); - this.activedGridItem = newItem.i; }, addTabItem(item: LayoutConfig) { const idx = this.layout.findIndex((d: LayoutConfig) => d.i === item.i); @@ -117,7 +121,7 @@ export const dashboardStore = defineStore({ }; this.layout[idx].children?.push(i); }, - addTabWidget(tabIndex: number) { + addTabControls(type: string) { const activedGridItem = this.activedGridItem.split("-")[0]; const idx = this.layout.findIndex( (d: LayoutConfig) => d.i === activedGridItem @@ -125,37 +129,91 @@ export const dashboardStore = defineStore({ if (idx < 0) { return; } + const tabIndex = this.layout[idx].activedTabIndex; const { children } = this.layout[idx].children[tabIndex]; - const newWidget = { - x: 0, - y: 0, - w: 24, - h: 12, + const newItem: LayoutConfig = { + ...NewControl, i: String(children.length), - type: "Widget", - widget: { - title: "Title", - }, - graph: {}, - standard: {}, + type, + metricTypes: [""], + metrics: [""], }; + if (type === "Topology") { + newItem.w = 4; + newItem.h = 6; + newItem.graph = { + fontColor: "white", + backgroundColor: "green", + iconTheme: true, + content: "Topology", + fontSize: 18, + showDepth: true, + }; + } + if (type === "Trace" || type === "Profile") { + newItem.h = 24; + } if (this.layout[idx].children) { const items = children.map((d: LayoutConfig) => { - d.y = d.y + newWidget.h; + d.y = d.y + newItem.h; return d; }); - items.push(newWidget); + items.push(newItem); this.layout[idx].children[tabIndex].children = items; + this.currentTabItems = items; } }, activeGridItem(index: string) { this.activedGridItem = index; }, + setActiveTabIndex(index: number) { + const idx = this.layout.findIndex( + (d: LayoutConfig) => d.i === this.activedGridItem + ); + if (idx < 0) { + return; + } + this.layout[idx].activedTabIndex = index; + }, + setCurrentTabItems(items: LayoutConfig[]) { + this.currentTabItems = items; + }, + removeTab(item: LayoutConfig) { + if (this.selectedGrid && this.selectedGrid.i === item.i) { + this.selectedGrid = null; + } + this.layout = this.layout.filter((d: LayoutConfig) => d.i !== item.i); + }, removeControls(item: LayoutConfig) { + const actived = this.activedGridItem.split("-"); + const index = this.layout.findIndex( + (d: LayoutConfig) => actived[0] === d.i + ); + + if (this.selectedGrid && this.selectedGrid.i === item.i) { + this.selectedGrid = null; + } + if (actived.length === 3) { + const tabIndex = Number(actived[1]); + const itemIndex = this.layout[index].children[ + tabIndex + ].children.findIndex((d: LayoutConfig) => actived[2] === d.i); + + this.layout[index].children[tabIndex].children.splice(itemIndex, 1); + this.setCurrentTabItems(this.layout[index].children[tabIndex].children); + return; + } this.layout = this.layout.filter((d: LayoutConfig) => d.i !== item.i); }, removeTabItem(item: LayoutConfig, index: number) { const idx = this.layout.findIndex((d: LayoutConfig) => d.i === item.i); + if (this.selectedGrid) { + for (const item of this.layout[idx].children[index].children) { + if (this.selectedGrid.i === item.i) { + this.selectedGrid = null; + } + } + } if (this.layout[idx].children) { this.layout[idx].children?.splice(index, 1); } @@ -204,11 +262,18 @@ export const dashboardStore = defineStore({ ); if (actived.length === 3) { - this.layout[index].children[actived[1]].children[actived[2]] = { - ...this.layout[index], + const tabIndex = Number(actived[1]); + const itemIndex = this.layout[index].children[ + tabIndex + ].children.findIndex((d: LayoutConfig) => actived[2] === d.i); + + this.layout[index].children[tabIndex].children[itemIndex] = { + ...this.layout[index].children[tabIndex].children[itemIndex], ...param, }; - this.selectedGrid = this.layout[index]; + this.selectedGrid = + this.layout[index].children[tabIndex].children[itemIndex]; + this.setCurrentTabItems(this.layout[index].children[tabIndex].children); return; } this.layout[index] = { diff --git a/src/types/dashboard.ts b/src/types/dashboard.ts index b8c0544e..c0ec3d86 100644 --- a/src/types/dashboard.ts +++ b/src/types/dashboard.ts @@ -27,6 +27,7 @@ export interface LayoutConfig { type: string; metricTypes: string[]; children?: any; + activedTabIndex?: number; } export interface WidgetConfig { diff --git a/src/views/dashboard/Edit.vue b/src/views/dashboard/Edit.vue index 075b0ec2..d6b3e24a 100644 --- a/src/views/dashboard/Edit.vue +++ b/src/views/dashboard/Edit.vue @@ -75,6 +75,7 @@ function handleClick(e: any) { e.stopPropagation(); if (e.target.className === "ds-main") { dashboardStore.activeGridItem(""); + dashboardStore.selectWidget(null); } } diff --git a/src/views/dashboard/controls/Tab.vue b/src/views/dashboard/controls/Tab.vue index 5c31a87d..20c106dd 100644 --- a/src/views/dashboard/controls/Tab.vue +++ b/src/views/dashboard/controls/Tab.vue @@ -33,38 +33,62 @@ limitations under the License. --> v-show="activeTabIndex === idx" size="sm" iconName="cancel" - @click="deleteTabItem(idx)" + @click="deleteTabItem($event, idx)" /> - + - - - - -
- + + +
+ {{ t("editTab") }} +
+
+ {{ t("delete") }} +
+
-
+
@click="clickTabGrid($event, item)" :class="{ active: activeTabWidget === item.i }" > -
Please add widgets.
- diff --git a/src/views/dashboard/controls/Widget.vue b/src/views/dashboard/controls/Widget.vue index 74ca377c..56de4729 100644 --- a/src/views/dashboard/controls/Widget.vue +++ b/src/views/dashboard/controls/Widget.vue @@ -77,6 +77,7 @@ const props = { default: () => ({ widget: {} }), }, activeIndex: { type: String, default: "" }, + needQuery: { type: Boolean, default: false }, }; export default defineComponent({ name: "Widget", @@ -93,7 +94,7 @@ export default defineComponent({ const dashboardStore = useDashboardStore(); const selectorStore = useSelectorStore(); - if (dashboardStore.entity === EntityType[1].value) { + if (dashboardStore.entity === EntityType[1].value || props.needQuery) { queryMetrics(); } @@ -128,7 +129,10 @@ export default defineComponent({ watch( () => [props.data.metricTypes, props.data.metrics], () => { - if (props.data.i !== dashboardStore.selectedGrid.i) { + if ( + dashboardStore.selectedGrid && + props.data.i !== dashboardStore.selectedGrid.i + ) { return; } if (TableChartTypes.includes(dashboardStore.selectedGrid.graph.type)) { diff --git a/src/views/dashboard/data.ts b/src/views/dashboard/data.ts index 17a186f3..396de2cd 100644 --- a/src/views/dashboard/data.ts +++ b/src/views/dashboard/data.ts @@ -165,9 +165,9 @@ export const SortOrder = [ export const ToolIcons = [ { name: "playlist_add", content: "Add Widget", id: "addWidget" }, { name: "all_inbox", content: "Add Tab", id: "addTab" }, - { name: "device_hub", content: "Add Topology", id: "topology" }, - { name: "merge", content: "Add Trace", id: "trace" }, - { name: "timeline", content: "Add Profile", id: "profile" }, + { name: "device_hub", content: "Add Topology", id: "addTopology" }, + { name: "merge", content: "Add Trace", id: "addTrace" }, + { name: "timeline", content: "Add Profile", id: "addProfile" }, // { name: "save_alt", content: "Export", id: "export" }, // { name: "folder_open", content: "Import", id: "import" }, // { name: "settings", content: "Settings", id: "settings" }, diff --git a/src/views/dashboard/panel/Layout.vue b/src/views/dashboard/panel/Layout.vue index 72c95881..bc3938f8 100644 --- a/src/views/dashboard/panel/Layout.vue +++ b/src/views/dashboard/panel/Layout.vue @@ -53,6 +53,7 @@ export default defineComponent({ } function clickGrid(item: LayoutConfig) { dashboardStore.activeGridItem(item.i); + dashboardStore.selectWidget(item); } return { dashboardStore, diff --git a/src/views/dashboard/panel/Tool.vue b/src/views/dashboard/panel/Tool.vue index 7e5774a8..b052257e 100644 --- a/src/views/dashboard/panel/Tool.vue +++ b/src/views/dashboard/panel/Tool.vue @@ -107,7 +107,6 @@ import { EntityType, ToolIcons, hasTopology, TraceEntitys } from "../data"; import { useSelectorStore } from "@/store/modules/selectors"; import { ElMessage } from "element-plus"; import { Option } from "@/types/app"; -import { Service } from "@/types/selector"; const dashboardStore = useDashboardStore(); const selectorStore = useSelectorStore(); @@ -260,7 +259,7 @@ async function getServices() { } } -async function changeService(service: Service[]) { +async function changeService(service: any) { if (service[0]) { states.currentService = service[0].value; selectorStore.setCurrentService(service[0]); @@ -270,7 +269,7 @@ async function changeService(service: Service[]) { } } -function changeDestService(service: Service[]) { +function changeDestService(service: any) { if (service[0]) { states.currentDestService = service[0].value; selectorStore.setCurrentDestService(service[0]); @@ -279,7 +278,7 @@ function changeDestService(service: Service[]) { } } -function changePods(pod: Option[]) { +function changePods(pod: any) { if (pod[0]) { selectorStore.setCurrentPod(pod[0]); } else { @@ -288,20 +287,55 @@ function changePods(pod: Option[]) { } function clickIcons(t: { id: string; content: string; name: string }) { - switch (t.id) { + if ( + dashboardStore.selectedGrid && + dashboardStore.selectedGrid.type === "Tab" + ) { + setTabControls(t.id); + return; + } + if (dashboardStore.activedGridItem.split("-").length === 3) { + setTabControls(t.id); + return; + } + setControls(t.id); +} + +function setTabControls(id: string) { + switch (id) { + case "addWidget": + dashboardStore.addTabControls("Widget"); + break; + case "addTrace": + dashboardStore.addTabControls("Trace"); + break; + case "addProfile": + dashboardStore.addTabControls("Profile"); + break; + case "addTopology": + dashboardStore.addTabControls("Topology"); + break; + default: + ElMessage.info("Don't support this control"); + break; + } +} + +function setControls(id: string) { + switch (id) { case "addWidget": dashboardStore.addControl("Widget"); break; case "addTab": dashboardStore.addControl("Tab"); break; - case "trace": + case "addTrace": dashboardStore.addControl("Trace"); break; - case "profile": + case "addProfile": dashboardStore.addControl("Profile"); break; - case "topology": + case "addTopology": dashboardStore.addControl("Topology"); break; case "settings": diff --git a/src/views/dashboard/related/profile/Content.vue b/src/views/dashboard/related/profile/Content.vue index 4679ba67..18bd2658 100644 --- a/src/views/dashboard/related/profile/Content.vue +++ b/src/views/dashboard/related/profile/Content.vue @@ -65,19 +65,16 @@ function loadTrees(l: boolean) { } .thread-stack { - padding: 5px 12px; - height: calc(50% - 50px); + padding: 5px; + height: calc(50% - 20px); overflow: auto; width: 100%; } .t-loading { text-align: center; - position: absolute; width: 100%; - height: 70px; - margin-top: 40px; - line-height: 88px; overflow: hidden; + height: calc(50% - 20px); } diff --git a/src/views/dashboard/related/profile/components/SpanTree.vue b/src/views/dashboard/related/profile/components/SpanTree.vue index 63df51d9..0913b7dc 100644 --- a/src/views/dashboard/related/profile/components/SpanTree.vue +++ b/src/views/dashboard/related/profile/components/SpanTree.vue @@ -35,16 +35,18 @@ limitations under the License. --> {{ t("analyze") }}
- +
+
+