Merge pull request #2 from pemeraldy/feature/tabs-with-fullview

Feature/tabs with fullview
This commit is contained in:
Peter Olu 2022-04-23 19:39:24 +01:00 committed by GitHub
commit 06c37e9fc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 140 additions and 91 deletions

View File

@ -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 {}

View File

@ -21,7 +21,6 @@ declare module '@vue/runtime-core' {
ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup'] ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination'] ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
ElPopover: typeof import('element-plus/es')['ElPopover'] ElPopover: typeof import('element-plus/es')['ElPopover']
ElProgress: typeof import('element-plus/es')['ElProgress'] ElProgress: typeof import('element-plus/es')['ElProgress']
ElRadio: typeof import('element-plus/es')['ElRadio'] ElRadio: typeof import('element-plus/es')['ElRadio']

View File

@ -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 See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<div class="flex-h tab-header"> <div ref="tabRef" class="flex-h tab-header">
<div class="tabs"> <div class="tabs">
<span <span
v-for="(child, idx) in data.children || []" v-for="(child, idx) in data.children || []"
@ -87,6 +87,37 @@ limitations under the License. -->
:is-resizable="dashboardStore.editMode" :is-resizable="dashboardStore.editMode"
@layout-updated="layoutUpdatedEvent" @layout-updated="layoutUpdatedEvent"
> >
<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 <grid-item
v-for="item in dashboardStore.currentTabItems" v-for="item in dashboardStore.currentTabItems"
:x="item.x" :x="item.x"
@ -106,12 +137,13 @@ limitations under the License. -->
:needQuery="needQuery" :needQuery="needQuery"
/> />
</grid-item> </grid-item>
</template>
</grid-layout> </grid-layout>
<div class="no-data-tips" v-else>{{ t("noWidget") }}</div> <div class="no-data-tips" v-else>{{ t("noWidget") }}</div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ref, watch, defineComponent, toRefs } from "vue"; import { ref, watch, onMounted, defineComponent, toRefs } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import type { PropType } from "vue"; import type { PropType } from "vue";
import { LayoutConfig } from "@/types/dashboard"; import { LayoutConfig } from "@/types/dashboard";
@ -122,6 +154,7 @@ import Trace from "./Trace.vue";
import Profile from "./Profile.vue"; import Profile from "./Profile.vue";
import Log from "./Log.vue"; import Log from "./Log.vue";
import Text from "./Text.vue"; import Text from "./Text.vue";
import FullVueWrapper from "@/components/FullVueWrapper.vue";
const props = { const props = {
data: { data: {
@ -132,7 +165,7 @@ const props = {
}; };
export default defineComponent({ export default defineComponent({
name: "Tab", name: "Tab",
components: { Topology, Widget, Trace, Profile, Log, Text }, components: { Topology, Widget, Trace, Profile, Log, Text, FullVueWrapper },
props, props,
setup(props) { setup(props) {
const { t } = useI18n(); const { t } = useI18n();
@ -143,6 +176,8 @@ export default defineComponent({
const canEditTabName = ref<boolean>(false); const canEditTabName = ref<boolean>(false);
const needQuery = ref<boolean>(false); const needQuery = ref<boolean>(false);
const showTools = ref<boolean>(false); const showTools = ref<boolean>(false);
const tabRef = ref<any>("");
const currentItem = ref("");
const l = dashboardStore.layout.findIndex( const l = dashboardStore.layout.findIndex(
(d: LayoutConfig) => d.i === props.data.i (d: LayoutConfig) => d.i === props.data.i
); );
@ -151,7 +186,34 @@ export default defineComponent({
dashboardStore.layout[l].children[activeTabIndex.value].children dashboardStore.layout[l].children[activeTabIndex.value].children
); );
dashboardStore.setActiveTabIndex(activeTabIndex.value, props.data.i); 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) { function clickTabs(e: Event, idx: number) {
e.stopPropagation(); e.stopPropagation();
@ -230,7 +292,13 @@ export default defineComponent({
} }
} }
); );
onMounted(() => {
tabRef?.value["parentElement"]?.classList?.toggle("item");
console.log(tabRef.value);
});
return { return {
currentItem,
scrollToGraph,
handleClick, handleClick,
layoutUpdatedEvent, layoutUpdatedEvent,
clickTabGrid, clickTabGrid,
@ -240,6 +308,7 @@ export default defineComponent({
removeTab, removeTab,
clickTabs, clickTabs,
...toRefs(props), ...toRefs(props),
tabRef,
activeTabWidget, activeTabWidget,
dashboardStore, dashboardStore,
activeTabIndex, activeTabIndex,
@ -253,6 +322,53 @@ export default defineComponent({
}); });
</script> </script>
<style lang="scss" scoped> <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 { .tabs {
height: 40px; height: 40px;
color: #ccc; color: #ccc;

View File

@ -104,20 +104,6 @@ limitations under the License. -->
</i> </i>
</el-tooltip> </el-tooltip>
</div> </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 class="switch"> <div class="switch">
<el-switch <el-switch
v-model="dashboardStore.editMode" v-model="dashboardStore.editMode"