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 8746d3c9 feat: add Support for dragging in the trace panel (#377) 8746d3c9 is described below commit 8746d3c98530ca85a8bb152936c16a33f0961e96 Author: Starry <codeprince2...@163.com> AuthorDate: Sat Apr 6 19:17:17 2024 +0800 feat: add Support for dragging in the trace panel (#377) --- .../Table/table.scss => utils/mutation.ts} | 84 +++++---------- src/views/dashboard/controls/Trace.vue | 116 ++++++++++++++++++++- src/views/dashboard/related/trace/Detail.vue | 2 +- src/views/dashboard/related/trace/Filter.vue | 3 +- src/views/dashboard/related/trace/TraceList.vue | 8 +- .../related/trace/components/D3Graph/Index.vue | 19 ++-- .../trace/components/Table/TableContainer.vue | 1 + .../related/trace/components/Table/table.scss | 14 +-- 8 files changed, 166 insertions(+), 81 deletions(-) diff --git a/src/views/dashboard/related/trace/components/Table/table.scss b/src/utils/mutation.ts similarity index 50% copy from src/views/dashboard/related/trace/components/Table/table.scss copy to src/utils/mutation.ts index e48b8e29..219d9337 100644 --- a/src/views/dashboard/related/trace/components/Table/table.scss +++ b/src/utils/mutation.ts @@ -14,63 +14,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -.argument { - width: 150px; -} - -.start-time { - width: 150px; -} - -.exec-ms { - width: 80px; -} - -.exec-percent { - width: 100px; -} - -.self { - width: 100px; -} - -.api { - width: 120px; -} - -.agent { - width: 150px; -} - -.application { - width: 150px; - text-align: center; -} - -.max-time { - width: 150px; -} - -.method { - width: 300px; -} - -.avg-time { - width: 150px; -} - -.min-time { - width: 150px; -} - -.count { - width: 120px; -} - -.sum-time { - width: 150px; -} -.type { - width: 60px; +export class mutationObserver { + private static mutationObserverMap: Map<string, MutationObserver> = new Map<string, MutationObserver>(); + + static create(key: string, callback: MutationCallback) { + const observer = new MutationObserver(callback); + mutationObserver.mutationObserverMap.set(key, observer); + } + + static observe(key: string, target: Node, options?: MutationObserverInit) { + const observer = mutationObserver.mutationObserverMap.get(key); + if (observer) { + observer.observe(target, options); + } + } + + static deleteObserve(key: string): void { + this.disconnect(key); + this.mutationObserverMap.delete(key); + } + + static disconnect(key: string): void { + const observer = this.mutationObserverMap.get(key); + if (observer) { + observer.disconnect(); + } + } } diff --git a/src/views/dashboard/controls/Trace.vue b/src/views/dashboard/controls/Trace.vue index 4daa614b..4db7e77a 100644 --- a/src/views/dashboard/controls/Trace.vue +++ b/src/views/dashboard/controls/Trace.vue @@ -25,22 +25,34 @@ limitations under the License. --> </div> </el-popover> <div class="header"> - <Filter :needQuery="needQuery" :data="data" @get="getService" /> + <Filter :needQuery="needQuery" :data="data" @get="getService" @search="popSegmentList" /> </div> <div class="trace flex-h"> - <TraceList /> + <TraceList class="trace-list" :style="`width: ${currentWidth}px;`" /> + <div + @mouseover="showIcon = true" + @mouseout="showIcon = false" + @mousedown="mousedown($event)" + @mouseup="mouseup($event)" + > + <div class="trace-line" /> + <span class="trace-icon" v-show="showIcon" @mousedown="triggerArrow" @mouseup="stopObserve($event)"> + <Icon class="trace-arrow" :icon-name="isLeft ? 'chevron-left' : 'chevron-right'" size="lg" /> + </span> + </div> <TraceDetail :serviceId="serviceId" /> </div> </div> </template> <script lang="ts" setup> - import { provide, ref } from "vue"; + import { provide, ref, onMounted, onUnmounted } from "vue"; import type { PropType } from "vue"; import Filter from "../related/trace/Filter.vue"; import TraceList from "../related/trace/TraceList.vue"; import TraceDetail from "../related/trace/Detail.vue"; import { useI18n } from "vue-i18n"; import { useDashboardStore } from "@/store/modules/dashboard"; + import { mutationObserver } from "@/utils/mutation"; /* global defineProps */ const props = defineProps({ @@ -52,15 +64,76 @@ limitations under the License. --> needQuery: { type: Boolean, default: true }, }); provide("options", props.data); + const defaultWidth = 280, + minArrowLeftWidth = 120; const serviceId = ref<string>(""); const { t } = useI18n(); const dashboardStore = useDashboardStore(); + const isLeft = ref<boolean>(true); + const showIcon = ref<boolean>(false); + const currentWidth = ref<number>(defaultWidth); + const isDrag = ref<boolean>(false); + function removeWidget() { dashboardStore.removeControls(props.data); } function getService(id: string) { serviceId.value = id; } + // When click the arrow, the width of the segment list is determined by the direction it points to. + function triggerArrow() { + currentWidth.value = isLeft.value ? 0 : defaultWidth; + isLeft.value = !isLeft.value; + startObserve(); + } + function popSegmentList() { + if (currentWidth.value >= defaultWidth) { + return; + } + currentWidth.value = defaultWidth; + isLeft.value = true; + } + function startObserve() { + mutationObserver.observe("trigger-resize", document.querySelector(".trace-list")!, { + attributes: true, + attributeFilter: ["style"], + }); + } + function stopObserve(event: MouseEvent) { + mutationObserver.disconnect("trigger-resize"); + event.stopPropagation(); + } + const mousemove = (event: MouseEvent) => { + if (!isDrag.value) { + return; + } + const diffX = event.clientX; + let leftWidth = document.querySelector(".trace-list")!.getBoundingClientRect(); + currentWidth.value = diffX - leftWidth.left; + isLeft.value = currentWidth.value >= minArrowLeftWidth; + }; + const mouseup = (event: MouseEvent) => { + showIcon.value = false; + isDrag.value = false; + stopObserve(event); + }; + const mousedown = (event: MouseEvent) => { + if ((event.target as HTMLDivElement)?.className === "trace-line") { + isDrag.value = true; + startObserve(); + event.stopPropagation(); + } + }; + onMounted(() => { + document.addEventListener("mousedown", mousedown); + document.addEventListener("mousemove", mousemove); + document.addEventListener("mouseup", mouseup); + }); + onUnmounted(() => { + document.removeEventListener("mousedown", mousedown); + document.removeEventListener("mousemove", mousemove); + document.removeEventListener("mouseup", mouseup); + }); </script> <style lang="scss" scoped> .trace-wrapper { @@ -68,7 +141,6 @@ limitations under the License. --> height: 100%; font-size: $font-size-smaller; position: relative; - overflow: auto; } .delete { @@ -103,4 +175,40 @@ limitations under the License. --> overflow: auto; min-width: 1000px; } + + .trace-list { + max-width: 480px; + } + + .trace-line { + position: relative; + width: 2px; + height: 900px; + background-color: #e8e8e8; + cursor: ew-resize; + + &:hover { + color: $active-color; + background-color: $active-background; + } + } + + .trace-icon { + position: absolute; + cursor: pointer; + top: calc(50% - 15px); + text-align: center; + width: 24px; + height: 24px; + transform: translateX(-11px); + line-height: 24px; + border-radius: 50%; + background-color: $layout-background; + box-shadow: 0 3px 5px rgb(45 60 80 / 20%); + } + + .trace-arrow { + padding-bottom: 1px; + color: $active-color; + } </style> diff --git a/src/views/dashboard/related/trace/Detail.vue b/src/views/dashboard/related/trace/Detail.vue index c5c1ea2a..f115f602 100644 --- a/src/views/dashboard/related/trace/Detail.vue +++ b/src/views/dashboard/related/trace/Detail.vue @@ -166,8 +166,8 @@ limitations under the License. --> </script> <style lang="scss" scoped> .trace-detail { + flex: 1; height: 100%; - width: 100%; overflow: hidden; } diff --git a/src/views/dashboard/related/trace/Filter.vue b/src/views/dashboard/related/trace/Filter.vue index 0ca285a1..a5092214 100644 --- a/src/views/dashboard/related/trace/Filter.vue +++ b/src/views/dashboard/related/trace/Filter.vue @@ -91,7 +91,7 @@ limitations under the License. --> import type { LayoutConfig } from "@/types/dashboard"; /*global defineProps, defineEmits, Recordable */ - const emits = defineEmits(["get"]); + const emits = defineEmits(["get", "search"]); const props = defineProps({ needQuery: { type: Boolean, default: true }, data: { @@ -227,6 +227,7 @@ limitations under the License. --> return param; } function searchTraces() { + emits("search"); traceStore.setTraceCondition(setCondition()); queryTraces(); } diff --git a/src/views/dashboard/related/trace/TraceList.vue b/src/views/dashboard/related/trace/TraceList.vue index ba2991a8..6013cbe4 100644 --- a/src/views/dashboard/related/trace/TraceList.vue +++ b/src/views/dashboard/related/trace/TraceList.vue @@ -13,7 +13,7 @@ limitations under the License. --> <template> <div class="trace-t flex-v"> <div class="trace-t-tool flex-h"> - <div class="title"> + <div class="title ell"> <span class="mr-5">Trace Segments</span> <el-popover :width="310" @@ -144,6 +144,7 @@ limitations under the License. --> </script> <style lang="scss" scoped> .trace-t-tool { + overflow: hidden; background-color: rgb(196 200 225 / 20%); justify-content: space-between; border-bottom: 1px solid #c1c5ca41; @@ -163,7 +164,7 @@ limitations under the License. --> } .trace-t-wrapper { - overflow: auto; + overflow: hidden; border-right: 1px solid var(--sw-trace-list-border); } @@ -187,7 +188,8 @@ limitations under the License. --> } .list { - width: 280px; + min-width: 120px; + width: 100%; } .trace-tr { diff --git a/src/views/dashboard/related/trace/components/D3Graph/Index.vue b/src/views/dashboard/related/trace/components/D3Graph/Index.vue index ff4705e7..6a107a0b 100644 --- a/src/views/dashboard/related/trace/components/D3Graph/Index.vue +++ b/src/views/dashboard/related/trace/components/D3Graph/Index.vue @@ -30,8 +30,9 @@ limitations under the License. --> import SpanDetail from "./SpanDetail.vue"; import { useAppStoreWithOut } from "@/store/modules/app"; import { debounce } from "@/utils/debounce"; + import { mutationObserver } from "@/utils/mutation"; - /* global defineProps, Nullable, defineExpose,Recordable*/ + /* global defineProps, Nullable, defineExpose, Recordable */ const props = defineProps({ data: { type: Array as PropType<Span[]>, default: () => [] }, traceId: { type: String, default: "" }, @@ -60,6 +61,13 @@ limitations under the License. --> } draw(); loading.value = false; + + // monitor segment list width changes. + mutationObserver.create("trigger-resize", () => { + d3.selectAll(".d3-tip").remove(); + debounceFunc(); + }); + window.addEventListener("resize", debounceFunc); }); @@ -286,6 +294,7 @@ limitations under the License. --> onBeforeUnmount(() => { d3.selectAll(".d3-tip").remove(); window.removeEventListener("resize", debounceFunc); + mutationObserver.deleteObserve("trigger-resize"); }); watch( () => props.data, @@ -295,12 +304,8 @@ limitations under the License. --> } loading.value = true; changeTree(); - tree.value.init({ label: "TRACE_ROOT", children: segmentId.value }, props.data, fixSpansSize.value); - tree.value.draw(() => { - setTimeout(() => { - loading.value = false; - }, 200); - }); + draw(); + loading.value = false; }, ); watch( diff --git a/src/views/dashboard/related/trace/components/Table/TableContainer.vue b/src/views/dashboard/related/trace/components/Table/TableContainer.vue index 125eee1f..e5ac2380 100644 --- a/src/views/dashboard/related/trace/components/Table/TableContainer.vue +++ b/src/views/dashboard/related/trace/components/Table/TableContainer.vue @@ -88,6 +88,7 @@ limitations under the License. --> return; } drag.onmousedown = (event: MouseEvent) => { + event.stopPropagation(); const diffX = event.clientX; const copy = method.value; document.onmousemove = (documentEvent) => { diff --git a/src/views/dashboard/related/trace/components/Table/table.scss b/src/views/dashboard/related/trace/components/Table/table.scss index e48b8e29..7de1ae12 100644 --- a/src/views/dashboard/related/trace/components/Table/table.scss +++ b/src/views/dashboard/related/trace/components/Table/table.scss @@ -48,29 +48,29 @@ } .max-time { - width: 150px; + width: 13%; } .method { - width: 300px; + width: 28%; } .avg-time { - width: 150px; + width: 13%; } .min-time { - width: 150px; + width: 13%; } .count { - width: 120px; + width: 12%; } .sum-time { - width: 150px; + width: 13%; } .type { - width: 60px; + width: 8%; }