mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-15 01:33:54 +00:00
Merge pull request #2 from pemeraldy/feature/tabs-with-fullview
Feature/tabs with fullview
This commit is contained in:
commit
06c37e9fc9
52
src/types/auto-imports.d.ts
vendored
52
src/types/auto-imports.d.ts
vendored
@ -1,52 +0,0 @@
|
||||
// Generated by 'unplugin-auto-import'
|
||||
// We suggest you to commit this file into source control
|
||||
declare global {
|
||||
const computed: typeof import('vue')['computed']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const h: typeof import('vue')['h']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const markRaw: typeof import('vue')['markRaw']
|
||||
const nextTick: typeof import('vue')['nextTick']
|
||||
const onActivated: typeof import('vue')['onActivated']
|
||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
}
|
||||
export {}
|
1
src/types/components.d.ts
vendored
1
src/types/components.d.ts
vendored
@ -21,7 +21,6 @@ declare module '@vue/runtime-core' {
|
||||
ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElProgress: typeof import('element-plus/es')['ElProgress']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
|
@ -13,7 +13,7 @@ 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="flex-h tab-header">
|
||||
<div ref="tabRef" class="flex-h tab-header">
|
||||
<div class="tabs">
|
||||
<span
|
||||
v-for="(child, idx) in data.children || []"
|
||||
@ -87,31 +87,63 @@ limitations under the License. -->
|
||||
:is-resizable="dashboardStore.editMode"
|
||||
@layout-updated="layoutUpdatedEvent"
|
||||
>
|
||||
<grid-item
|
||||
v-for="item in dashboardStore.currentTabItems"
|
||||
:x="item.x"
|
||||
:y="item.y"
|
||||
:w="item.w"
|
||||
:h="item.h"
|
||||
:i="item.i"
|
||||
:key="item.i"
|
||||
@click="clickTabGrid($event, item)"
|
||||
:class="{ active: activeTabWidget === item.i }"
|
||||
drag-ignore-from="svg.d3-trace-tree, .dragger, .micro-topo-chart"
|
||||
>
|
||||
<component
|
||||
:is="item.type"
|
||||
:data="item"
|
||||
:activeIndex="`${data.i}-${activeTabIndex}-${item.i}`"
|
||||
:needQuery="needQuery"
|
||||
/>
|
||||
</grid-item>
|
||||
<div class="scroll-snap-container" v-if="dashboardStore.fullView">
|
||||
<div
|
||||
v-if="dashboardStore.currentTabItems.length > 1"
|
||||
class="scroll-handler__wrapper"
|
||||
>
|
||||
<div
|
||||
@click="scrollToGraph(item.i)"
|
||||
v-for="item in dashboardStore.currentTabItems"
|
||||
:key="item.i"
|
||||
:class="[currentItem === `tabitem${item.i}` ? 'active': '']"
|
||||
class="scroll-to"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
class="tabitem"
|
||||
:id="`tabitem${item.i}`"
|
||||
v-for="item in dashboardStore.currentTabItems"
|
||||
:key="item.i"
|
||||
>
|
||||
<component
|
||||
:is="item.type"
|
||||
:data="item"
|
||||
:activeIndex="`${data.i}-${activeTabIndex}-${item.i}`"
|
||||
:needQuery="needQuery"
|
||||
@click="clickTabGrid($event, item)"
|
||||
:class="{ active: activeTabWidget === item.i }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<grid-item
|
||||
v-for="item in dashboardStore.currentTabItems"
|
||||
:x="item.x"
|
||||
:y="item.y"
|
||||
:w="item.w"
|
||||
:h="item.h"
|
||||
:i="item.i"
|
||||
:key="item.i"
|
||||
@click="clickTabGrid($event, item)"
|
||||
:class="{ active: activeTabWidget === item.i }"
|
||||
drag-ignore-from="svg.d3-trace-tree, .dragger, .micro-topo-chart"
|
||||
>
|
||||
<component
|
||||
:is="item.type"
|
||||
:data="item"
|
||||
:activeIndex="`${data.i}-${activeTabIndex}-${item.i}`"
|
||||
:needQuery="needQuery"
|
||||
/>
|
||||
</grid-item>
|
||||
</template>
|
||||
</grid-layout>
|
||||
<div class="no-data-tips" v-else>{{ t("noWidget") }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { ref, watch, defineComponent, toRefs } from "vue";
|
||||
import { ref, watch, onMounted, defineComponent, toRefs } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import type { PropType } from "vue";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
@ -122,6 +154,7 @@ import Trace from "./Trace.vue";
|
||||
import Profile from "./Profile.vue";
|
||||
import Log from "./Log.vue";
|
||||
import Text from "./Text.vue";
|
||||
import FullVueWrapper from "@/components/FullVueWrapper.vue";
|
||||
|
||||
const props = {
|
||||
data: {
|
||||
@ -132,7 +165,7 @@ const props = {
|
||||
};
|
||||
export default defineComponent({
|
||||
name: "Tab",
|
||||
components: { Topology, Widget, Trace, Profile, Log, Text },
|
||||
components: { Topology, Widget, Trace, Profile, Log, Text, FullVueWrapper },
|
||||
props,
|
||||
setup(props) {
|
||||
const { t } = useI18n();
|
||||
@ -143,6 +176,8 @@ export default defineComponent({
|
||||
const canEditTabName = ref<boolean>(false);
|
||||
const needQuery = ref<boolean>(false);
|
||||
const showTools = ref<boolean>(false);
|
||||
const tabRef = ref<any>("");
|
||||
const currentItem = ref("");
|
||||
const l = dashboardStore.layout.findIndex(
|
||||
(d: LayoutConfig) => d.i === props.data.i
|
||||
);
|
||||
@ -151,7 +186,34 @@ export default defineComponent({
|
||||
dashboardStore.layout[l].children[activeTabIndex.value].children
|
||||
);
|
||||
dashboardStore.setActiveTabIndex(activeTabIndex.value, props.data.i);
|
||||
setTimeout(() => {
|
||||
observeItems()
|
||||
}, 1500)
|
||||
}
|
||||
function scrollToGraph(e: any) {
|
||||
document?.getElementById(`tabitem${e}`)?.scrollIntoView();
|
||||
}
|
||||
|
||||
function observeItems() {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach((element) => {
|
||||
console.log("Inter ratio:", element.intersectionRatio, 'Ele:', element.target.id);
|
||||
if (element.intersectionRatio > 0) {
|
||||
currentItem.value = element.target.id;
|
||||
console.log(element.target.id)
|
||||
}
|
||||
});
|
||||
});
|
||||
document.querySelectorAll(".tabitem").forEach((element) => {
|
||||
observer.observe(element);
|
||||
});
|
||||
}
|
||||
|
||||
watch(() => dashboardStore.currentTabItems, () => {
|
||||
setTimeout(() => {
|
||||
observeItems();
|
||||
}, 500)
|
||||
} )
|
||||
|
||||
function clickTabs(e: Event, idx: number) {
|
||||
e.stopPropagation();
|
||||
@ -165,7 +227,7 @@ export default defineComponent({
|
||||
dashboardStore.setCurrentTabItems(
|
||||
dashboardStore.layout[l].children[activeTabIndex.value].children
|
||||
);
|
||||
needQuery.value = true;
|
||||
needQuery.value = true;
|
||||
}
|
||||
function removeTab(e: Event) {
|
||||
e.stopPropagation();
|
||||
@ -230,7 +292,13 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
);
|
||||
onMounted(() => {
|
||||
tabRef?.value["parentElement"]?.classList?.toggle("item");
|
||||
console.log(tabRef.value);
|
||||
});
|
||||
return {
|
||||
currentItem,
|
||||
scrollToGraph,
|
||||
handleClick,
|
||||
layoutUpdatedEvent,
|
||||
clickTabGrid,
|
||||
@ -240,6 +308,7 @@ export default defineComponent({
|
||||
removeTab,
|
||||
clickTabs,
|
||||
...toRefs(props),
|
||||
tabRef,
|
||||
activeTabWidget,
|
||||
dashboardStore,
|
||||
activeTabIndex,
|
||||
@ -253,6 +322,53 @@ export default defineComponent({
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tab-layout::-webkit-scrollbar {
|
||||
display: none !important;
|
||||
}
|
||||
.scroll-snap-container {
|
||||
position: relative;
|
||||
height: 80vh;
|
||||
display: block;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scroll-snap-points-y: repeat(100%);
|
||||
scroll-snap-destination: 0 0;
|
||||
scroll-snap-type: y mandatory;
|
||||
scroll-snap-type: mandatory;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
.scroll-snap-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.tabitem {
|
||||
scroll-snap-align: start;
|
||||
height: 100%;
|
||||
}
|
||||
.scroll-handler__wrapper {
|
||||
z-index: 20;
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
right: 0;
|
||||
top: 40vh;
|
||||
height: auto;
|
||||
width: 20px;
|
||||
.scroll-to {
|
||||
opacity: 0.5;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin: 5px 0;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
background: #4f4f4f;
|
||||
}
|
||||
.scroll-to.active {
|
||||
opacity: 1;
|
||||
padding: 6px;
|
||||
background: #252a2f;
|
||||
}
|
||||
}
|
||||
.tabs {
|
||||
height: 40px;
|
||||
color: #ccc;
|
||||
|
@ -103,21 +103,7 @@ limitations under the License. -->
|
||||
<Icon class="icon-btn" size="sm" iconName="save" />
|
||||
</i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="switch">
|
||||
<span style="margin-right: 5px">Toggle full view</span>
|
||||
<el-switch
|
||||
v-model="dashboardStore.fullView"
|
||||
active-text="Full view"
|
||||
inactive-text="FV"
|
||||
size="small"
|
||||
inline-prompt
|
||||
active-color="#409eff"
|
||||
inactive-color="#999"
|
||||
@change="toggleFullView"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="switch">
|
||||
<el-switch
|
||||
v-model="dashboardStore.editMode"
|
||||
|
Loading…
Reference in New Issue
Block a user