blob: 6dd5c530fa5bc980708322f87f916448d8f79b02 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, 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>
<a-affix v-if="this.$store.getters.shutdownTriggered" >
<a-alert :message="$t('message.shutdown.triggered')" type="error" banner :showIcon="false" class="shutdownHeader" />
</a-affix>
<a-layout class="layout" :class="[device]">
<a-affix style="z-index: 200" :offsetTop="this.$store.getters.shutdownTriggered ? 25 : 0">
<template v-if="isSideMenu()">
<a-drawer
v-if="isMobile()"
:wrapClassName="'drawer-sider ' + navTheme"
:closable="false"
:visible="collapsed"
placement="left"
@close="() => this.collapsed = false"
>
<side-menu
:menus="menus"
:theme="navTheme"
:collapsed="false"
:collapsible="true"
mode="inline"
@menuSelect="menuSelect"></side-menu>
</a-drawer>
<side-menu
v-else
mode="inline"
:menus="menus"
:theme="navTheme"
:collapsed="collapsed"
:collapsible="true"></side-menu>
</template>
<template v-else>
<a-drawer
v-if="isMobile()"
:wrapClassName="'drawer-sider ' + navTheme"
placement="left"
@close="() => this.collapsed = false"
:closable="false"
:visible="collapsed"
>
<side-menu
:menus="menus"
:theme="navTheme"
:collapsed="false"
:collapsible="true"
mode="inline"
@menuSelect="menuSelect"></side-menu>
</a-drawer>
</template>
<drawer :visible="showSetting" placement="right" v-if="isAdmin && (isDevelopmentMode || allowSettingTheme)">
<template #handler>
<a-button type="primary" size="large">
<close-outlined v-if="showSetting" />
<setting-outlined v-else />
</a-button>
</template>
<template #drawer>
<setting :visible="showSetting" />
</template>
</drawer>
</a-affix>
<a-layout :class="[layoutMode, `content-width-${contentWidth}`]" :style="{ paddingLeft: contentPaddingLeft, minHeight: '100vh' }">
<!-- layout header -->
<a-affix style="z-index: 100">
<global-header
:style="this.$store.getters.shutdownTriggered ? 'margin-top: 25px;' : null"
:mode="layoutMode"
:menus="menus"
:theme="navTheme"
:collapsed="collapsed"
:device="device"
@toggle="toggle"
/>
</a-affix>
<a-button
v-if="showClear"
type="default"
size="small"
class="button-clear-notification"
@click="onClearNotification">{{ $t('label.clear.notification') }}</a-button>
<!-- layout content -->
<a-layout-content
class="layout-content"
:class="{'is-header-fixed': fixedHeader}">
<slot></slot>
</a-layout-content>
<!-- layout footer -->
<a-layout-footer style="padding: 0">
<global-footer />
</a-layout-footer>
</a-layout>
</a-layout>
</div>
</template>
<script>
import SideMenu from '@/components/menu/SideMenu'
import GlobalHeader from '@/components/page/GlobalHeader'
import GlobalFooter from '@/components/page/GlobalFooter'
import { triggerWindowResizeEvent } from '@/utils/util'
import { mapState, mapActions } from 'vuex'
import { mixin, mixinDevice } from '@/utils/mixin.js'
import { isAdmin } from '@/role'
import { api } from '@/api'
import Drawer from '@/components/widgets/Drawer'
import Setting from '@/components/view/Setting.vue'
export default {
name: 'GlobalLayout',
components: {
SideMenu,
GlobalHeader,
GlobalFooter,
Drawer,
Setting
},
mixins: [mixin, mixinDevice],
data () {
return {
collapsed: false,
menus: [],
showSetting: false,
showClear: false
}
},
computed: {
...mapState({
mainMenu: state => state.permission.addRouters
}),
isAdmin () {
return isAdmin()
},
isDevelopmentMode () {
return process.env.NODE_ENV === 'development'
},
allowSettingTheme () {
return this.$config.allowSettingTheme
},
contentPaddingLeft () {
if (!this.fixSidebar || this.isMobile()) {
return '0'
}
if (this.sidebarOpened) {
return '256px'
}
return '80px'
}
},
watch: {
sidebarOpened (val) {
this.collapsed = !val
},
mainMenu (newMenu) {
this.menus = newMenu.find((item) => item.path === '/').children
},
'$store.getters.darkMode' (darkMode) {
if (darkMode) {
document.body.classList.add('dark-mode')
} else {
document.body.classList.remove('dark-mode')
}
},
'$store.getters.countNotify' (countNotify) {
this.showClear = false
if (countNotify && countNotify > 0) {
this.showClear = true
}
}
},
provide: function () {
return {
parentToggleSetting: this.toggleSetting
}
},
created () {
this.menus = this.mainMenu.find((item) => item.path === '/').children
this.collapsed = !this.sidebarOpened
if ('readyForShutdown' in this.$store.getters.apis) {
const readyForShutdownPollingJob = setInterval(this.checkShutdown, 5000)
this.$store.commit('SET_READY_FOR_SHUTDOWN_POLLING_JOB', readyForShutdownPollingJob)
}
},
mounted () {
const layoutMode = this.$config.theme['@layout-mode'] || 'light'
this.$store.dispatch('SetDarkMode', (layoutMode === 'dark'))
if (layoutMode === 'dark') {
document.body.classList.add('dark-mode')
}
const userAgent = navigator.userAgent
if (userAgent.indexOf('Edge') > -1) {
this.$nextTick(() => {
this.collapsed = !this.collapsed
setTimeout(() => {
this.collapsed = !this.collapsed
}, 16)
})
}
const countNotify = this.$store.getters.countNotify
this.showClear = false
if (countNotify && countNotify > 0) {
this.showClear = true
}
},
beforeUnmount () {
document.body.classList.remove('dark')
},
methods: {
...mapActions(['setSidebar']),
toggle () {
this.collapsed = !this.collapsed
this.setSidebar(!this.collapsed)
triggerWindowResizeEvent()
},
paddingCalc () {
let left = ''
if (this.sidebarOpened) {
left = this.isDesktop() ? '256px' : '80px'
} else {
left = this.isMobile() ? '0' : (this.fixSidebar ? '80px' : '0')
}
return left
},
menuSelect () {
if (!this.isDesktop()) {
this.collapsed = false
}
},
toggleSetting (showSetting) {
this.showSetting = showSetting
},
onClearNotification () {
this.$notification.destroy()
this.$store.commit('SET_COUNT_NOTIFY', 0)
},
checkShutdown () {
api('readyForShutdown', {}).then(json => {
this.$store.dispatch('SetShutdownTriggered', json.readyforshutdownresponse.readyforshutdown.shutdowntriggered || false)
})
}
}
}
</script>
<style lang="less">
.layout-content {
&.is-header-fixed {
margin: 78px 12px 0;
}
}
// Todo try to get this rules scoped
.ant-drawer.drawer-sider {
.sider {
box-shadow: none;
}
&.dark {
.ant-drawer-content {
background-color: rgb(0, 21, 41);
max-width: 256px;
}
.ant-drawer-content-wrapper {
width: 256px !important;;
}
}
&.light {
box-shadow: none;
.ant-drawer-content {
background-color: #fff;
max-width: 256px;
}
.ant-drawer-content-wrapper {
width: 256px !important;
}
}
.ant-drawer-body {
padding: 0;
}
}
.shutdownHeader {
font-weight: bold;
height: 25px;
text-align: center;
padding: 0px;
margin: 0px;
width: 100vw;
position: absolute;
}
</style>