mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
dashboard: fix styling and enhancements (#8)
Refactoring, visual enhancements and extend readme. Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
f8f0a99e26
commit
33df072505
@ -12,6 +12,8 @@ Install tools and dependencies:
|
||||
|
||||
Build and run:
|
||||
|
||||
npm start
|
||||
or
|
||||
npm run serve
|
||||
|
||||
Production Build:
|
||||
|
||||
@ -152,3 +152,30 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
&.light {
|
||||
box-shadow: none;
|
||||
|
||||
.ant-drawer-content {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-drawer-body {
|
||||
padding: 0
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -48,9 +48,10 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.header-notice{
|
||||
.header-notice {
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
|
||||
span {
|
||||
vertical-align: initial;
|
||||
}
|
||||
|
||||
@ -42,6 +42,10 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.breadcrumb {
|
||||
.mobile & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
placement="bottomRight"
|
||||
:autoAdjustOverflow="true"
|
||||
:arrowPointAtCenter="true"
|
||||
overlayClassName="header-notice-wrapper"
|
||||
overlayClassName="ant-pro-header-notice__popover"
|
||||
:overlayStyle="{ width: '300px', top: '50px' }">
|
||||
<template slot="content">
|
||||
<a-spin :spinning="loadding">
|
||||
@ -38,9 +38,9 @@
|
||||
</a-tabs>
|
||||
</a-spin>
|
||||
</template>
|
||||
<span @click="fetchNotice" class="header-notice">
|
||||
<span @click="fetchNotice" class="ant-pro-header-notice__opener">
|
||||
<a-badge count="12">
|
||||
<a-icon style="font-size: 16px; padding: 4px" type="bell" />
|
||||
<a-icon class="ant-pro-header-notice__icon" type="bell" />
|
||||
</a-badge>
|
||||
</span>
|
||||
</a-popover>
|
||||
@ -71,13 +71,8 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css">
|
||||
.header-notice-wrapper {
|
||||
top: 50px !important;
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.header-notice{
|
||||
.header-notice {
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
|
||||
@ -85,4 +80,25 @@ export default {
|
||||
vertical-align: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-pro-header-notice {
|
||||
|
||||
&__popover {
|
||||
top: 50px !important;
|
||||
}
|
||||
|
||||
&__opener {
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
|
||||
span {
|
||||
vertical-align: initial;
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: 18px;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
|
||||
<a-dropdown>
|
||||
<span class="action ant-dropdown-link">
|
||||
<span class="action ant-dropdown-link ant-pro-translation-menu">
|
||||
<a-icon type="global"></a-icon>
|
||||
</span>
|
||||
<a-menu slot="overlay" @click="onClick">
|
||||
|
||||
@ -76,3 +76,27 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.user-dropdown-menu {
|
||||
span {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.user-dropdown-menu-wrapper.ant-dropdown-menu {
|
||||
padding: 4px 0;
|
||||
|
||||
.ant-dropdown-menu-item {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item > .anticon:first-child,
|
||||
.ant-dropdown-menu-item > a > .anticon:first-child,
|
||||
.ant-dropdown-menu-submenu-title > .anticon:first-child .ant-dropdown-menu-submenu-title > a > .anticon:first-child {
|
||||
min-width: 12px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -87,9 +87,10 @@ const updateTheme = primaryColor => {
|
||||
}
|
||||
}
|
||||
|
||||
const updateColorWeak = colorWeak => {
|
||||
// document.body.className = colorWeak ? 'colorWeak' : '';
|
||||
colorWeak ? document.body.classList.add('colorWeak') : document.body.classList.remove('colorWeak')
|
||||
const updateInvertedMode = invertedMode => {
|
||||
invertedMode = true;
|
||||
console.log(invertedMode);
|
||||
invertedMode ? document.body.classList.add('layout-inverted-mode') : document.body.classList.remove('layout-inverted-mode')
|
||||
}
|
||||
|
||||
export { updateTheme, colorList, updateColorWeak }
|
||||
export { updateTheme, colorList, updateInvertedMode }
|
||||
|
||||
@ -6,7 +6,7 @@ export default {
|
||||
fixedHeader: true, // sticky header
|
||||
fixSiderbar: true, // sticky siderbar
|
||||
autoHideHeader: false, // auto hide header
|
||||
colorWeak: false,
|
||||
invertedMode: true,
|
||||
multiTab: false, // enable to have tab/route history stuff
|
||||
// CloudStack options
|
||||
apiBase: '/client/api',
|
||||
|
||||
4
ui/src/core/bootstrap.js
vendored
4
ui/src/core/bootstrap.js
vendored
@ -6,7 +6,7 @@ import {
|
||||
DEFAULT_COLOR,
|
||||
DEFAULT_THEME,
|
||||
DEFAULT_LAYOUT_MODE,
|
||||
DEFAULT_COLOR_WEAK,
|
||||
DEFAULT_COLOR_INVERTED,
|
||||
SIDEBAR_TYPE,
|
||||
DEFAULT_FIXED_HEADER,
|
||||
DEFAULT_FIXED_HEADER_HIDDEN,
|
||||
@ -24,7 +24,7 @@ export default function Initializer () {
|
||||
store.commit('TOGGLE_FIXED_SIDERBAR', Vue.ls.get(DEFAULT_FIXED_SIDEMENU, config.fixSiderbar))
|
||||
store.commit('TOGGLE_CONTENT_WIDTH', Vue.ls.get(DEFAULT_CONTENT_WIDTH_TYPE, config.contentWidth))
|
||||
store.commit('TOGGLE_FIXED_HEADER_HIDDEN', Vue.ls.get(DEFAULT_FIXED_HEADER_HIDDEN, config.autoHideHeader))
|
||||
store.commit('TOGGLE_WEAK', Vue.ls.get(DEFAULT_COLOR_WEAK, config.colorWeak))
|
||||
store.commit('TOGGLE_INVERTED', Vue.ls.get(DEFAULT_COLOR_INVERTED, config.invertedMode))
|
||||
store.commit('TOGGLE_COLOR', Vue.ls.get(DEFAULT_COLOR, config.primaryColor))
|
||||
store.commit('TOGGLE_MULTI_TAB', Vue.ls.get(DEFAULT_MULTI_TAB, config.multiTab))
|
||||
store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN))
|
||||
|
||||
@ -4,7 +4,7 @@ import {
|
||||
DEFAULT_THEME,
|
||||
DEFAULT_LAYOUT_MODE,
|
||||
DEFAULT_COLOR,
|
||||
DEFAULT_COLOR_WEAK,
|
||||
DEFAULT_COLOR_INVERTED,
|
||||
DEFAULT_FIXED_HEADER,
|
||||
DEFAULT_FIXED_SIDEMENU,
|
||||
DEFAULT_FIXED_HEADER_HIDDEN,
|
||||
@ -23,7 +23,7 @@ const app = {
|
||||
fixSiderbar: false,
|
||||
autoHideHeader: false,
|
||||
color: null,
|
||||
weak: false,
|
||||
inverted: true,
|
||||
multiTab: true
|
||||
},
|
||||
mutations: {
|
||||
@ -67,9 +67,9 @@ const app = {
|
||||
Vue.ls.set(DEFAULT_COLOR, color)
|
||||
state.color = color
|
||||
},
|
||||
TOGGLE_WEAK: (state, flag) => {
|
||||
Vue.ls.set(DEFAULT_COLOR_WEAK, flag)
|
||||
state.weak = flag
|
||||
TOGGLE_INVERTED: (state, flag) => {
|
||||
Vue.ls.set(DEFAULT_COLOR_INVERTED, flag)
|
||||
state.inverted = flag
|
||||
},
|
||||
TOGGLE_MULTI_TAB: (state, bool) => {
|
||||
Vue.ls.set(DEFAULT_MULTI_TAB, bool)
|
||||
@ -110,8 +110,8 @@ const app = {
|
||||
ToggleColor ({ commit }, color) {
|
||||
commit('TOGGLE_COLOR', color)
|
||||
},
|
||||
ToggleWeak ({ commit }, weakFlag) {
|
||||
commit('TOGGLE_WEAK', weakFlag)
|
||||
ToggleInverted ({ commit }, invertedFlag) {
|
||||
commit('TOGGLE_INVERTED', invertedFlag)
|
||||
},
|
||||
ToggleMultiTab ({ commit }, bool) {
|
||||
commit('TOGGLE_MULTI_TAB', bool)
|
||||
|
||||
@ -4,7 +4,7 @@ export const SIDEBAR_TYPE = 'SIDEBAR_TYPE'
|
||||
export const DEFAULT_THEME = 'DEFAULT_THEME'
|
||||
export const DEFAULT_LAYOUT_MODE = 'DEFAULT_LAYOUT_MODE'
|
||||
export const DEFAULT_COLOR = 'DEFAULT_COLOR'
|
||||
export const DEFAULT_COLOR_WEAK = 'DEFAULT_COLOR_WEAK'
|
||||
export const DEFAULT_COLOR_INVERTED = 'DEFAULT_COLOR_INVERTED'
|
||||
export const DEFAULT_FIXED_HEADER = 'DEFAULT_FIXED_HEADER'
|
||||
export const DEFAULT_FIXED_SIDEMENU = 'DEFAULT_FIXED_SIDEMENU'
|
||||
export const DEFAULT_FIXED_HEADER_HIDDEN = 'DEFAULT_FIXED_HEADER_HIDDEN'
|
||||
|
||||
@ -24,13 +24,16 @@
|
||||
2. common
|
||||
- include all rules that reset styles, define global stuffs without classes at all
|
||||
- e.g. body {} p, ul, li {} h1, h2, h3 {}
|
||||
3. frame
|
||||
3. ant-overwrite
|
||||
- any styles that overwrites the existin ant rules by any reason
|
||||
- e.g. classes like .ant-layout-header .anticon {}
|
||||
4. frame
|
||||
- everything that belongs to the frame
|
||||
- e.g. header, footer, nav, sider, content (just the actual content frame, not every component in it)
|
||||
4. layout
|
||||
5. layout
|
||||
- rules that modify the page at all if new layout class is set.
|
||||
- e.g. #html class="layout-ant-black"#
|
||||
5. objects
|
||||
- repeatly used elements like buttons, inputs,
|
||||
6. components
|
||||
6. objects
|
||||
- repeatly used elements like buttons, inputs
|
||||
7. components
|
||||
- complex elements like dropdown, forms, table, search (usualy include this to components/FooterToolbar/ folder)
|
||||
|
||||
33
ui/src/style/ant-overwrite/ant-layout-header.less
Normal file
33
ui/src/style/ant-overwrite/ant-layout-header.less
Normal file
@ -0,0 +1,33 @@
|
||||
.ant-layout-header {
|
||||
.anticon-menu-fold {
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.ant-breadcrumb .anticon {
|
||||
margin-top: -3px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.anticon-home {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.anticon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu {
|
||||
|
||||
.ant-menu-item .anticon,
|
||||
.ant-menu-submenu-title .anticon {
|
||||
font-size: 18px!important; // overwrite ant-menu collaped defaults
|
||||
margin-right: 12px;
|
||||
vertical-align: sub;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-badge-count {
|
||||
top: -15px;
|
||||
}
|
||||
4
ui/src/style/ant-overwrite/ant-progress.less
Normal file
4
ui/src/style/ant-overwrite/ant-progress.less
Normal file
@ -0,0 +1,4 @@
|
||||
.ant-progress-circle .ant-progress-text {
|
||||
font-size: 16px;
|
||||
transform: translateY(-67%); // position text centered to down cut off progress circle
|
||||
}
|
||||
@ -1,7 +1,3 @@
|
||||
body {
|
||||
overflow-y: scroll;
|
||||
|
||||
&.colorWeak {
|
||||
filter: invert(80%);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
|
||||
.ant-drawer.drawer-sider {
|
||||
.sider {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&.dark {
|
||||
.ant-drawer-content {
|
||||
background-color: rgb(0, 21, 41);
|
||||
}
|
||||
}
|
||||
&.light {
|
||||
box-shadow: none;
|
||||
.ant-drawer-content {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-drawer-body {
|
||||
padding: 0
|
||||
}
|
||||
}
|
||||
36
ui/src/style/component/dashboard.less
Normal file
36
ui/src/style/component/dashboard.less
Normal file
@ -0,0 +1,36 @@
|
||||
.ant-pro-capacity-dashboard {
|
||||
&__wrapper {
|
||||
display: flex;
|
||||
margin-bottom: 24px;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
.mobile & {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
&__select {
|
||||
width: 100%;
|
||||
padding: 0 12px;
|
||||
|
||||
.mobile & {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
width: auto;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
&__tile-wrapper:after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
|
||||
&__alert-wrapper {
|
||||
clear: both;
|
||||
padding: 0 12px;
|
||||
}
|
||||
}
|
||||
0
ui/src/style/frame/header/header-notice.less
Normal file
0
ui/src/style/frame/header/header-notice.less
Normal file
4
ui/src/style/frame/header/translation-menu.less
Normal file
4
ui/src/style/frame/header/translation-menu.less
Normal file
@ -0,0 +1,4 @@
|
||||
.ant-pro-translation-menu {
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
.user-dropdown-menu {
|
||||
span {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.user-dropdown-menu-wrapper.ant-dropdown-menu {
|
||||
padding: 4px 0;
|
||||
|
||||
.ant-dropdown-menu-item {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item > .anticon:first-child,
|
||||
.ant-dropdown-menu-item > a > .anticon:first-child,
|
||||
.ant-dropdown-menu-submenu-title > .anticon:first-child .ant-dropdown-menu-submenu-title > a > .anticon:first-child {
|
||||
min-width: 12px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
@ -3,18 +3,21 @@
|
||||
@import "~ant-design-vue/lib/style/core/index";
|
||||
|
||||
//* import all ## custom ## variables, mixins and styles
|
||||
|
||||
|
||||
@import "variables/prefixes";
|
||||
|
||||
@import "common/common";
|
||||
|
||||
@import "component/ant-drawer";
|
||||
@import "layout/ant";
|
||||
@import "layout/inverted-mode";
|
||||
@import "ant-overwrite/ant-layout-header";
|
||||
@import "ant-overwrite/ant-progress";
|
||||
|
||||
@import "frame/header/translation-menu";
|
||||
@import "frame/content";
|
||||
@import "frame/search";
|
||||
@import "frame/sider";
|
||||
@import "frame/top-menu";
|
||||
@import "frame/user-dropdown";
|
||||
|
||||
@import "layout/ant";
|
||||
|
||||
@import "objects/table";
|
||||
|
||||
@ -126,8 +126,10 @@
|
||||
|
||||
.action {
|
||||
cursor: pointer;
|
||||
padding: 0 12px;
|
||||
display: inline-block;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
float: left;
|
||||
transition: all .3s;
|
||||
height: 100%;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
|
||||
3
ui/src/style/layout/inverted-mode.less
Normal file
3
ui/src/style/layout/inverted-mode.less
Normal file
@ -0,0 +1,3 @@
|
||||
body.layout-inverted-mode {
|
||||
filter: invert(80%);
|
||||
}
|
||||
@ -11,7 +11,7 @@ const mixin = {
|
||||
layoutMode: state => state.app.layout,
|
||||
navTheme: state => state.app.theme,
|
||||
primaryColor: state => state.app.color,
|
||||
colorWeak: state => state.app.weak,
|
||||
invertedMode: state => state.app.inverted,
|
||||
fixedHeader: state => state.app.fixedHeader,
|
||||
fixSiderbar: state => state.app.fixSiderbar,
|
||||
fixSidebar: state => state.app.fixSiderbar,
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="page-header-index-wide">
|
||||
<a-row :gutter="24" :style="{ marginTop: '24px' }">
|
||||
<a-col :sm="24" :md="6" :xl="18" :style="{ marginBottom: '24px' }">
|
||||
<a-col :sm="24" :md="6" :xl="20" :style="{ marginBottom: '24px' }">
|
||||
<a-col :sm="24" :md="24" :xl="18" :style="{ marginBottom: '24px' }">
|
||||
<div class="ant-pro-capacity-dashboard__wrapper">
|
||||
<div class="ant-pro-capacity-dashboard__select">
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
@ -14,16 +15,18 @@
|
||||
{{ zone.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-col>
|
||||
<a-col :sm="24" :md="6" :xl="4" :style="{ marginBottom: '24px' }">
|
||||
</div>
|
||||
<div class="ant-pro-capacity-dashboard__button">
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="listCapacity(zoneSelected, true)">Fetch Latest Statistics</a-button>
|
||||
</a-col>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="ant-pro-capacity-dashboard__tile-wrapper">
|
||||
<a-col
|
||||
:xs="12"
|
||||
:sm="12"
|
||||
:md="12"
|
||||
:md="8"
|
||||
:xl="6"
|
||||
:style="{ marginBottom: '28px' }"
|
||||
v-for="stat in stats"
|
||||
@ -31,25 +34,32 @@
|
||||
<chart-card :loading="loading" style="padding-top: 40px">
|
||||
<div style="text-align: center">
|
||||
<h4>{{ stat.name }}</h4>
|
||||
<a-progress type="dashboard" :percent="parseFloat(stat.percentused, 10)" :width="100" />
|
||||
<a-progress type="dashboard" :percent="Number(parseFloat(stat.percentused, 10).toFixed(2))" :width="100" />
|
||||
</div>
|
||||
<template slot="footer"><span>{{ stat.capacityused }} / {{ stat.capacitytotal }}</span></template>
|
||||
</chart-card>
|
||||
</a-col>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :xl="6">
|
||||
<a-row class="ant-pro-capacity-dashboard__alert-wrapper" :gutter="24">
|
||||
<a-col :md="8" :xl="24">
|
||||
<chart-card style="margin-bottom: 24px">
|
||||
<div style="text-align: center">
|
||||
<h4>Alerts</h4>
|
||||
<p>Some event data here...</p>
|
||||
</div>
|
||||
</chart-card>
|
||||
</a-col>
|
||||
<a-col :md="8" :xl="24">
|
||||
<chart-card style="margin-bottom: 24px">
|
||||
<div style="text-align: center">
|
||||
<h4>Host Alerts</h4>
|
||||
<p>Some event data here...</p>
|
||||
</div>
|
||||
</chart-card>
|
||||
</a-col>
|
||||
<a-col :md="8" :xl="24">
|
||||
<chart-card style="margin-bottom: 24px">
|
||||
<div style="text-align: center">
|
||||
<h4>Events</h4>
|
||||
@ -58,6 +68,8 @@
|
||||
</chart-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -159,4 +171,21 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-pro-capacity-dashboard {
|
||||
&__wrapper {
|
||||
display: flex;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
&__select {
|
||||
width: 100%;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
&__button {
|
||||
width: auto;
|
||||
padding: 0 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user