Merge branch '4.15' into main

This commit is contained in:
nicolas 2021-08-11 12:36:48 -03:00
commit 0011d45b22
37 changed files with 2035 additions and 69 deletions

View File

@ -617,6 +617,7 @@
"label.copy": "Copy",
"label.copy.clipboard": "Copy to clipboard",
"label.copy.text": "Copy Text",
"label.copy.setting.success": "Copy success, Please replace theme setting in public/config.js",
"label.copyid": "Copy ID",
"label.copying.iso": "Copying ISO",
"label.corrections.saved": "Corrections saved",
@ -669,6 +670,7 @@
"label.daily": "Daily",
"label.dashboard": "Dashboard",
"label.dashboard.endpoint": "Dashboard endpoint",
"label.dark.mode": "Dark mode",
"label.data.disk": "Data Disk",
"label.data.disk.offering": "Data Disk Offering",
"label.date": "Date",
@ -1831,6 +1833,7 @@
"label.reservedsystemnetmask": "Reserved system netmask",
"label.reservedsystemstartip": "Start Reserved system IP",
"label.reset": "Reset",
"label.reset.to.default": "Reset to default",
"label.reset.ssh.key.pair": "Reset SSH Key Pair",
"label.reset.ssh.key.pair.on.vm": "Reset SSH Key Pair on VM",
"label.reset.vpn.connection": "Reset VPN connection",
@ -1902,6 +1905,7 @@
"label.save.and.continue": "Save and continue",
"label.save.changes": "Save changes",
"label.save.new.rule": "Save new Rule",
"label.save.setting": "Save setting",
"label.saving.processing": "Saving....",
"label.scale.vm": "Scale VM",
"label.scale.up.policy": "SCALE UP POLICY",
@ -2151,9 +2155,28 @@
"label.template.select.existing": "Select an existing template",
"label.tftp.dir": "TFTP Directory",
"label.tftpdir": "Tftp root directory",
"label.theme.alert": "The settings panel is only visible in the development environment, please save for the changes to take effect.",
"label.theme.color": "Theme Color",
"label.theme.cyan": "Cyan",
"label.theme.dark": "Dark Style",
"label.theme.daybreak.blue": "Daybreak Blue",
"label.theme.default": "Default Theme",
"label.theme.dust.red": "Dust Red",
"label.theme.geek.blue": "Geek Blue",
"label.theme.golden.purple": "Golden Purple",
"label.theme.grey": "Custom - Grey",
"label.theme.light": "Light Style",
"label.theme.lightblue": "Custom - Light Blue",
"label.theme.navigation.bgColor": "Background Color",
"label.theme.navigation.setting": "Navigation setting",
"label.theme.navigation.txtColor": "Text Color",
"label.theme.page.style.setting": "Page style setting",
"label.theme.polar.green": "Polar Green",
"label.theme.project": "Project Style",
"label.theme.project.navigation.setting": "Project Navigation setting",
"label.theme.sunset.orange": "Sunset Orange",
"label.theme.volcano": "Volcano",
"label.theme.white": "White",
"label.threshold": "Threshold",
"label.thursday": "Thursday",
"label.tier.details": "Tier details",

View File

@ -36,7 +36,12 @@ export default {
}
},
created () {
window.less.modifyVars(this.$config.theme)
const userThemeSetting = this.$store.getters.themeSetting || {}
if (Object.keys(userThemeSetting).length === 0) {
window.less.modifyVars(this.$config.theme)
} else {
window.less.modifyVars(userThemeSetting)
}
console.log('config and theme applied')
}
}

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
<filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="darkModeIcon" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
<g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
<g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="Rectangle-18">
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
<use fill="#303648" fill-rule="evenodd" xlink:href="#path-2"></use>
</g>
<rect id="Rectangle-11" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
<rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Group 5</title>
<desc>Created with Sketch.</desc>
<defs>
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
<filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="lightModeIcon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
<g id="Group-8" transform="translate(1167.000000, 0.000000)">
<g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="Rectangle-18">
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
<use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
</g>
<rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="44"></rect>
<rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="-1" y="0" width="49" height="10"></rect>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -49,18 +49,8 @@ export default {
.line {
margin-bottom: 8px;
a {
color: rgba(0, 0, 0, .45);
&:hover {
color: rgba(0, 0, 0, .65);
}
}
}
.copyright {
color: rgba(0, 0, 0, .45);
font-size: 14px;
}
}

View File

@ -63,6 +63,17 @@
</a-drawer>
</template>
<template>
<drawer :visible="showSetting" placement="right">
<div slot="handler">
<a-button type="primary" size="large">
<a-icon :type="showSetting ? 'close' : 'setting'"/>
</a-button>
</div>
<setting slot="drawer" :visible="showSetting" />
</drawer>
</template>
<a-layout :class="[layoutMode, `content-width-${contentWidth}`]" :style="{ paddingLeft: contentPaddingLeft, minHeight: '100vh' }">
<!-- layout header -->
<global-header
@ -94,19 +105,24 @@ import GlobalFooter from '@/components/page/GlobalFooter'
import { triggerWindowResizeEvent } from '@/utils/util'
import { mapState, mapActions } from 'vuex'
import { mixin, mixinDevice } from '@/utils/mixin.js'
import Drawer from '@/components/widgets/Drawer'
import Setting from '@/components/view/Setting.vue'
export default {
name: 'GlobalLayout',
components: {
SideMenu,
GlobalHeader,
GlobalFooter
GlobalFooter,
Drawer,
Setting
},
mixins: [mixin, mixinDevice],
data () {
return {
collapsed: false,
menus: []
menus: [],
showSetting: false
}
},
computed: {
@ -129,6 +145,18 @@ export default {
},
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')
}
}
},
provide: function () {
return {
parentToggleSetting: this.toggleSetting
}
},
created () {
@ -136,6 +164,9 @@ export default {
this.collapsed = !this.sidebarOpened
},
mounted () {
if (this.$store.getters.darkMode) {
document.body.classList.add('dark-mode')
}
const userAgent = navigator.userAgent
if (userAgent.indexOf('Edge') > -1) {
this.$nextTick(() => {
@ -146,6 +177,9 @@ export default {
})
}
},
beforeDestroy () {
document.body.classList.remove('dark')
},
methods: {
...mapActions(['setSidebar']),
toggle () {
@ -166,6 +200,9 @@ export default {
if (!this.isDesktop()) {
this.collapsed = false
}
},
toggleSetting (showSetting) {
this.showSetting = showSetting
}
}
}

View File

@ -44,7 +44,11 @@
:dataSource="Object.keys(detailOptions)"
:placeholder="$t('label.name')"
@change="e => onAddInputChange(e, 'newKey')" />
<a-input style=" width: 30px; border-left: 0; pointer-events: none; backgroundColor: #fff" placeholder="=" disabled />
<a-input
class="tag-disabled-input"
style=" width: 30px; border-left: 0; pointer-events: none; text-align: center"
placeholder="="
disabled />
<a-auto-complete
class="detail-input"
:filterOption="filterOption"

View File

@ -632,13 +632,21 @@
@keyup.enter="handleInputConfirm"
compact>
<a-input ref="input" :value="inputKey" @change="handleKeyChange" style="width: 30%; text-align: center" :placeholder="$t('label.key')" />
<a-input style=" width: 30px; border-left: 0; pointer-events: none; backgroundColor: #fff" placeholder="=" disabled />
<a-input
class="tag-disabled-input"
style="width: 30px; border-left: 0; pointer-events: none; text-align: center"
placeholder="="
disabled />
<a-input :value="inputValue" @change="handleValueChange" style="width: 30%; text-align: center; border-left: 0" :placeholder="$t('label.value')" />
<tooltip-button :tooltip="$t('label.ok')" icon="check" size="small" @click="handleInputConfirm" />
<tooltip-button :tooltip="$t('label.cancel')" icon="close" size="small" @click="inputVisible=false" />
</a-input-group>
</div>
<a-tag @click="showInput" style="background: #fff; borderStyle: dashed;" v-else-if="isAdminOrOwner() && 'createTags' in $store.getters.apis">
<a-tag
@click="showInput"
class="btn-add-tag"
style="borderStyle: dashed;"
v-else-if="isAdminOrOwner() && 'createTags' in $store.getters.apis">
<a-icon type="plus" /> {{ $t('label.new.tag') }}
</a-tag>
</div>

View File

@ -604,14 +604,6 @@ export default {
/deep/ .ant-table-small > .ant-table-content > .ant-table-body {
margin: 0;
}
/deep/ .light-row {
background-color: #fff;
}
/deep/ .dark-row {
background-color: #f9f9f9;
}
</style>
<style scoped lang="scss">

View File

@ -74,7 +74,11 @@
size="small"
compact>
<a-input ref="input" :value="inputKey" @change="e => inputKey = e.target.value" style="width: 50px; text-align: center" :placeholder="$t('label.key')" />
<a-input style=" width: 20px; border-left: 0; pointer-events: none; backgroundColor: #fff" placeholder="=" disabled />
<a-input
class="tag-disabled-input"
style=" width: 20px; border-left: 0; pointer-events: none; text-align: center"
placeholder="="
disabled />
<a-input :value="inputValue" @change="handleValueChange" style="width: 50px; text-align: center; border-left: 0" :placeholder="$t('label.value')" />
<tooltip-button :tooltip="$t('label.clear')" icon="close" size="small" @click="inputKey = inputValue = ''" />
</a-input-group>

View File

@ -0,0 +1,406 @@
// 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 class="side-setting">
<setting-item :title="$t('label.theme.page.style.setting')" view-type="item">
<a-radio-group
class="setting-group"
name="themeGroup"
v-model="layoutMode"
@change="switchLayoutMode">
<setting-item
view-type="radio-group"
:items="pageStyles"
:checked="layoutMode"></setting-item>
</a-radio-group>
</setting-item>
<setting-item :title="$t('label.theme.color')" view-type="item" style="display: block;">
<a-radio-group
class="setting-group"
name="colorGroup"
:default-value="colorPick"
@change="switchColor">
<setting-item
view-type="radio-group"
:items="colors"
:checked="colorPick"></setting-item>
</a-radio-group>
<a-divider style="margin-top: 45px;" />
</setting-item>
<setting-item
v-if="!projectView"
:title="$t('label.theme.navigation.setting')"
view-type="item">
<a-list :split="false">
<a-list-item>
<div class="input-group">
<label>{{ $t('label.theme.navigation.bgColor') }}</label>
<div class="color-picker" :style="{ backgroundColor: navBgColorPick }">
<a-input
:disabled="layoutMode === 'dark'"
type="color"
v-model="navBgColorPick"
@blur="(e) => updateSetting('@navigation-background-color', e.target.value)" />
</div>
</div>
</a-list-item>
<a-list-item>
<div class="input-group">
<label>{{ $t('label.theme.navigation.txtColor') }}</label>
<div class="color-picker" :style="{ backgroundColor: navTextColorPick }">
<a-input
:disabled="layoutMode === 'dark'"
type="color"
v-model="navBgColorPick"
@blur="(e) => updateSetting('@navigation-text-color', e.target.value)" />
</div>
</div>
</a-list-item>
</a-list>
</setting-item>
<setting-item
v-if="projectView"
:title="$t('label.theme.project.navigation.setting')"
view-type="item">
<a-list :split="false">
<a-list-item>
<div class="input-group">
<label>{{ $t('label.theme.navigation.bgColor') }}</label>
<div class="color-picker" :style="{ backgroundColor: projectNavBgColorPick }">
<a-input
type="color"
v-model="projectNavBgColorPick"
@blur="(e) => updateSetting('@project-nav-background-color', e.target.value)" />
</div>
</div>
</a-list-item>
<a-list-item>
<div class="input-group">
<label>{{ $t('label.theme.navigation.txtColor') }}</label>
<div class="color-picker" :style="{ backgroundColor: projectNavTextColorPick }">
<a-input
type="color"
v-model="projectNavTextColorPick"
@blur="(e) => updateSetting('@project-nav-text-color', e.target.value)" />
</div>
</div>
</a-list-item>
</a-list>
</setting-item>
<div class="setting-action">
<a-divider style="margin: 15px 0;" />
<a-alert class="setting-action-alert" :message="$t('label.theme.alert')" type="warning" show-icon />
<a-button
class="setting-action-btn"
icon="copy"
@click="saveSetting">{{ $t('label.save.setting') }}</a-button>
<a-button
class="setting-action-btn"
icon="undo"
@click="resetSetting">{{ $t('label.reset.to.default') }}</a-button>
</div>
</div>
</template>
<script>
import SettingItem from '@/components/view/SettingItem'
export default {
name: 'Setting',
components: {
SettingItem
},
props: {
visible: {
type: Boolean,
default: false
}
},
data () {
return {
layoutMode: 'light',
colorPick: this.$store.getters.themeSetting['@primary-color'] || this.$config.theme['@primary-color'],
navBgColorPick: this.$store.getters.themeSetting['@navigation-background-color'] || this.$config.theme['@navigation-background-color'],
navTextColorPick: this.$store.getters.themeSetting['@navigation-text-color'] || this.$config.theme['@navigation-text-color'],
projectNavBgColorPick: this.$store.getters.themeSetting['@project-nav-background-color'] || this.$config.theme['@project-nav-background-color'],
projectNavTextColorPick: this.$store.getters.themeSetting['@project-nav-text-color'] || this.$config.theme['@project-nav-text-color'],
uiSettings: {},
originalSetting: {}
}
},
computed: {
projectView () {
return Boolean(this.$store.getters.project && this.$store.getters.project.id)
},
pageStyles () {
const arrStyle = [
{
name: 'light',
type: 'image-checkbox',
component: () => import('@/assets/icons/light.svg?inline')
},
{
name: 'dark',
type: 'image-checkbox',
component: () => import('@/assets/icons/dark.svg?inline')
}
]
return arrStyle
},
colors () {
return [
{
name: 'daybreak.blue',
type: 'color-checkbox',
color: '#1890ff'
},
{
name: 'dust.red',
type: 'color-checkbox',
color: '#f5222d'
},
{
name: 'volcano',
type: 'color-checkbox',
color: '#fa541c'
},
{
name: 'sunset.orange',
type: 'color-checkbox',
color: '#faad14'
},
{
name: 'cyan',
type: 'color-checkbox',
color: '#13c2c2'
},
{
name: 'polar.green',
type: 'color-checkbox',
color: '#52c41a'
},
{
name: 'geek.blue',
type: 'color-checkbox',
color: '#2f54eb'
},
{
name: 'golden.purple',
type: 'color-checkbox',
color: '#722ed1'
}
]
}
},
inject: ['parentToggleSetting'],
watch: {
projectView () {
this.fetchData()
}
},
created () {
this.fetchData()
},
methods: {
fetchData () {
this.originalSetting = Object.assign({}, this.$config.theme)
this.layoutMode = 'light'
if (this.$store.getters.darkMode) {
this.layoutMode = 'dark'
}
this.uiSettings = this.$config.theme
},
switchLayoutMode () {
this.$store.dispatch('SetDarkMode', (this.layoutMode === 'dark'))
},
switchColor (e) {
this.colorPick = e.target.value
this.updateSetting('@primary-color', this.colorPick)
},
updateSetting (name, value) {
this.uiSettings[name] = value
if (['@navigation-background-color'].includes(name)) {
this.uiSettings['@logo-background-color'] = value
}
window.less.modifyVars(this.uiSettings)
},
onClose () {
this.parentToggleSetting(false)
},
saveSetting () {
const loading = this.$message.loading(this.$t('label.save.setting'), 0)
this.$store.dispatch('SetThemeSetting', this.uiSettings)
setTimeout(() => {
loading()
this.$message.success(this.$t('label.success'))
}, 1000)
},
resetSetting () {
this.layoutMode = 'light'
this.colorPick = this.originalSetting['@primary-color']
this.navBgColorPick = this.originalSetting['@navigation-background-color']
this.navTextColorPick = this.originalSetting['@navigation-text-color']
this.projectNavBgColorPick = this.originalSetting['@project-nav-background-color']
this.projectNavTextColorPick = this.originalSetting['@project-nav-text-color']
this.$store.dispatch('SetThemeSetting', {})
this.switchLayoutMode()
this.$config.theme = this.originalSetting
window.less.modifyVars(this.$config.theme)
this.$message.success(this.$t('label.success'))
},
formatConfig (obj, dep) {
dep = dep || 1
const LN = '\n'
const TAB = ' '
let indent = ''
for (let i = 0; i < dep; i++) {
indent += TAB
}
let isArray = false
let arrayLastIsObj = false
let str = ''
let prefix = '{'
let subfix = '}'
if (Array.isArray(obj)) {
isArray = true
prefix = '['
subfix = ']'
str = obj.map((item, index) => {
let format = ''
if (typeof item === 'function') {
//
} else if (typeof item === 'object') {
arrayLastIsObj = true
format = `${LN}${indent}${this.formatConfig(item, dep + 1)},`
} else if ((typeof item === 'number' && !isNaN(item)) || typeof item === 'boolean') {
format = `${item},`
} else if (typeof item === 'string') {
format = `'${item}',`
}
if (index === obj.length - 1) {
format = format.substring(0, format.length - 1)
} else {
arrayLastIsObj = false
}
return format
}).join('')
} else if (typeof obj !== 'function' && typeof obj === 'object') {
str = Object.keys(obj).map((key, index, keys) => {
const val = obj[key]
let format = ''
if (typeof val === 'function') {
//
} else if (typeof val === 'object') {
format = `${LN}${indent}${key}: ${this.formatConfig(val, dep + 1)},`
} else if ((typeof val === 'number' && !isNaN(val)) || typeof val === 'boolean') {
format = `${LN}${indent}${key}: ${val},`
} else if (typeof val === 'string') {
format = `${LN}${indent}${key}: '${val}',`
}
if (index === keys.length - 1) {
format = format.substring(0, format.length - 1)
}
return format
}).join('')
}
const len = TAB.length
if (indent.length >= len) {
indent = indent.substring(0, indent.length - len)
}
if (!isArray || arrayLastIsObj) {
subfix = LN + indent + subfix
}
return `${prefix}${str}${subfix}`
}
}
}
</script>
<style lang="less" scoped>
.side-setting {
min-height: 100%;
font-size: 14px;
line-height: 1.5;
word-wrap: break-word;
position: relative;
padding: 20px 0;
.flex{
display: flex;
}
.select-item{
width: 80px;
}
}
.setting-group {
width: 100%;
}
.input-group {
display: inline-flex;
width: 100%;
position: relative;
.color-picker {
position: absolute;
width: 20px;
height: 20px;
overflow: hidden;
top: 0;
right: 0;
border: 1px solid;
cursor: pointer;
.ant-input {
opacity: 0;
height: 20px;
width: 20px;
position: absolute;
top: 0;
left: 0;
cursor: pointer;
}
}
}
.setting-action {
width: 100%;
padding: 0 24px;
&-alert {
margin: 20px 0 8px;
word-break: break-word;
}
&-btn {
width: 100%;
margin-bottom: 5px;
}
}
</style>

View File

@ -0,0 +1,185 @@
// 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>
<div class="setting-item" v-if="viewType === 'item'">
<h3 class="title">{{ title }}</h3>
<slot></slot>
</div>
<div class="setting-image-item" v-if="viewType === 'radio-group'">
<a-row :span="24" style="display: flex;">
<a-col v-for="(item) in items" :key="item.name" :style="colWidth">
<a-tooltip :title="$t(`label.theme.${item.name}`)" placement="top">
<div :class="['img-checkbox', item.disabled ? 'disabled' : '']" v-if="item.type==='image-checkbox'">
<component
:is="item.component"
:style="{
height: '56px',
width: '56px'
}"/>
<div :class="['check-item', item.name === checked ? 'check-item-checked' : '']">
<a-radio :value="item.name" :disabled="item.disabled"></a-radio>
<a-icon :class="['check-icon', item.name]" type="check" />
</div>
</div>
<div class="color-checkbox" v-else>
<div
:class="['check-color', item.color === checked ? 'check-color-checked' : '']"
:style="{ backgroundColor: item.color }">
<a-radio :value="item.color"></a-radio>
<a-icon class="check-icon" type="check" />
</div>
</div>
</a-tooltip>
</a-col>
</a-row>
</div>
</div>
</template>
<script>
import AddNetscalerLoadBalancer from '@/views/infra/network/providers/AddNetscalerLoadBalancer.vue'
export default {
components: { AddNetscalerLoadBalancer },
name: 'SettingItem',
props: {
viewType: {
type: String,
required: true
},
title: {
type: String,
default: ''
},
items: {
type: Array,
default: () => []
},
checked: {
type: String,
default: ''
}
},
computed: {
colWidth () {
if (this.items.length === 2) {
return { width: '70px' }
}
return { width: `${(100 / this.items.length)}%` }
}
}
}
</script>
<style lang="less" scoped>
.setting-item{
margin-bottom: 24px;
padding: 0 24px;
.title {
line-height: 22px;
margin-bottom: 12px;
}
}
.img-checkbox {
margin-right: 16px;
position: relative;
border-radius: 4px;
cursor: pointer;
width: 55px;
height: 50px;
.check-item {
position: absolute;
top: 0;
width: 100%;
padding-top: 25px;
padding-left: 20px;
height: 100%;
font-size: 14px;
font-weight: bold;
.ant-radio-wrapper {
opacity: 0;
position: absolute;
top: 0;
left: 0;
width: 48px;
height: 48px;
}
.check-icon {
display: none;
}
&-checked {
.check-icon {
display: block;
}
}
}
&.disabled {
cursor: not-allowed;
opacity: 0.9;
.ant-radio-wrapper {
cursor: not-allowed;
}
}
}
.color-checkbox {
position: relative;
cursor: pointer;
.check-color {
width: 20px;
height: 20px;
position: absolute;
.ant-radio-wrapper {
opacity: 0;
position: absolute;
top: 0;
left: 0;
margin: 0;
width: 20px;
height: 20px;
}
.check-icon {
display: none;
position: absolute;
top: 3px;
left: 3px;
}
&-checked {
.check-icon {
display: block;
}
}
}
}
</style>

View File

@ -594,8 +594,6 @@ export default {
}
/deep/.ant-tree-icon__customize {
color: rgba(0, 0, 0, 0.45);
background: #fff;
padding-right: 5px;
}

View File

@ -0,0 +1,170 @@
// 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>
<div :class="['mask', visible ? 'open' : 'close']" @click="close"></div>
<div :class="['drawer', placement, visible ? 'open' : 'close']">
<div ref="drawer" class="content">
<slot name="drawer"></slot>
</div>
<div
:class="['handler-container', placement, visible ? 'open' : 'close']"
ref="handler"
@click="toggle">
<slot v-if="$slots.handler" name="handler"></slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Drawer',
data () {
return {
}
},
model: {
prop: 'visible',
event: 'change'
},
props: {
visible: {
type: Boolean,
required: false,
default: false
},
placement: {
type: String,
required: false,
default: 'left'
},
showHandler: {
type: Boolean,
required: false,
default: true
}
},
inject: ['parentToggleSetting'],
methods: {
open () {
this.parentToggleSetting(true)
},
close () {
this.parentToggleSetting(false)
},
toggle () {
this.parentToggleSetting(!this.visible)
}
}
}
</script>
<style lang="less" scoped>
.mask {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
transition: all 0.5s;
z-index: 100;
background-color: #000000;
opacity: 0.2;
&.open{
display: inline-block;
}
&.close{
display: none;
}
}
.drawer{
position: fixed;
transition: all 0.5s;
height: 100vh;
z-index: 100;
&.left{
left: 0;
&.close{
transform: translateX(-100%);
}
}
&.right{
right: 0;
&.close{
transform: translateX(100%);
}
}
}
.content {
display: inline-block;
height: 100vh;
overflow-y: auto;
width: 300px;
background-color: #FFFFFF;
}
.handler-container {
position: absolute;
display: inline-block;
text-align: center;
transition: all 0.5s;
cursor: pointer;
top: calc(50% - 45px);
z-index: 100;
&.left{
right: -40px;
.handler{
border-radius: 0 5px 5px 0;
}
button {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
padding-left: 10px;
padding-right: 12px;
}
}
&.right{
left: -40px;
.handler {
border-radius: 5px 0 0 5px;
}
button {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
padding-left: 12px;
padding-right: 10px;
}
}
}
</style>

View File

@ -20,8 +20,19 @@
<template slot="title">
{{ name }}
</template>
<font-awesome-icon :icon="['fab', logo]" :size="size" style="color: #666;" v-if="logo !== 'debian'" />
<debian-icon v-else-if="logo === 'debian'" :style="{ height: size === '4x' ? '56px' : '16px', width: size === '4x' ? '56px' : '16px', marginBottom: '-4px' }" />
<font-awesome-icon
:icon="['fab', logo]"
:size="size"
:style="[$store.getters.darkMode ? { color: 'rgba(255, 255, 255, 0.65)' } : { color: '#666' }]"
v-if="logo !== 'debian'" />
<debian-icon
v-else-if="logo === 'debian'"
:style="{
height: size === '4x' ? '56px' : '16px',
width: size === '4x' ? '56px' : '16px',
marginBottom: '-4px',
background: $store.getters.darkMode ? 'rgba(255, 255, 255, 0.65)' : ''
}" />
</a-tooltip>
</template>

View File

@ -35,8 +35,10 @@
</template>
<script>
import Vue from 'vue'
import RouteView from '@/layouts/RouteView'
import { mixinDevice } from '@/utils/mixin.js'
import { DARK_MODE } from '@/store/mutation-types'
export default {
name: 'UserLayout',
@ -45,11 +47,25 @@ export default {
data () {
return {}
},
watch: {
'$store.getters.darkMode' (darkMode) {
if (darkMode) {
document.body.classList.add('dark-mode')
} else {
document.body.classList.remove('dark-mode')
}
}
},
mounted () {
document.body.classList.add('userLayout')
const darkMode = Vue.ls.get(DARK_MODE, false)
if (this.$store.getters.darkMode || darkMode) {
document.body.classList.add('dark-mode')
}
},
beforeDestroy () {
document.body.classList.remove('userLayout')
document.body.classList.remove('dark-mode')
}
}
</script>
@ -57,7 +73,6 @@ export default {
<style lang="less" scoped>
.user-layout {
height: 100%;
background: #fff;
&-container {
padding: 3rem 0;

View File

@ -37,7 +37,9 @@ const getters = {
timezoneoffset: state => state.user.timezoneoffset,
usebrowsertimezone: state => state.user.usebrowsertimezone,
server: state => state.app.server,
domainStore: state => state.user.domainStore
domainStore: state => state.user.domainStore,
darkMode: state => state.user.darkMode,
themeSetting: state => state.user.themeSetting
}
export default getters

View File

@ -33,7 +33,9 @@ import {
TIMEZONE_OFFSET,
USE_BROWSER_TIMEZONE,
HEADER_NOTICES,
DOMAIN_STORE
DOMAIN_STORE,
DARK_MODE,
THEME_SETTING
} from '@/store/mutation-types'
const user = {
@ -51,7 +53,9 @@ const user = {
zones: {},
timezoneoffset: 0.0,
usebrowsertimezone: false,
domainStore: {}
domainStore: {},
darkMode: false,
themeSetting: {}
},
mutations: {
@ -106,6 +110,14 @@ const user = {
SET_DOMAIN_STORE (state, domainStore) {
state.domainStore = domainStore
Vue.ls.set(DOMAIN_STORE, domainStore)
},
SET_DARK_MODE (state, darkMode) {
state.darkMode = darkMode
Vue.ls.set(DARK_MODE, darkMode)
},
SET_THEME_SETTING (state, setting) {
state.themeSetting = setting
Vue.ls.set(THEME_SETTING, setting)
}
},
@ -131,6 +143,10 @@ const user = {
const cachedUseBrowserTimezone = Vue.ls.get(USE_BROWSER_TIMEZONE, false)
commit('SET_USE_BROWSER_TIMEZONE', cachedUseBrowserTimezone)
const darkMode = Vue.ls.get(DARK_MODE, false)
commit('SET_DARK_MODE', darkMode)
const themeSetting = Vue.ls.get(THEME_SETTING, {})
commit('SET_THEME_SETTING', themeSetting)
commit('SET_APIS', {})
commit('SET_NAME', '')
@ -159,9 +175,13 @@ const user = {
const cachedTimezoneOffset = Vue.ls.get(TIMEZONE_OFFSET, 0.0)
const cachedUseBrowserTimezone = Vue.ls.get(USE_BROWSER_TIMEZONE, false)
const domainStore = Vue.ls.get(DOMAIN_STORE, {})
const darkMode = Vue.ls.get(DARK_MODE, false)
const themeSetting = Vue.ls.get(THEME_SETTING, {})
const hasAuth = Object.keys(cachedApis).length > 0
commit('SET_DOMAIN_STORE', domainStore)
commit('SET_DARK_MODE', darkMode)
commit('SET_THEME_SETTING', themeSetting)
if (hasAuth) {
console.log('Login detected, using cached APIs')
commit('SET_ZONES', cachedZones)
@ -346,6 +366,12 @@ const user = {
},
SetDomainStore ({ commit }, domainStore) {
commit('SET_DOMAIN_STORE', domainStore)
},
SetDarkMode ({ commit }, darkMode) {
commit('SET_DARK_MODE', darkMode)
},
SetThemeSetting ({ commit }, setting) {
commit('SET_THEME_SETTING', setting)
}
}
}

View File

@ -34,6 +34,8 @@ export const TIMEZONE_OFFSET = 'TIMEZONE_OFFSET'
export const USE_BROWSER_TIMEZONE = 'USE_BROWSER_TIMEZONE'
export const SERVER_MANAGER = 'SERVER_MANAGER'
export const DOMAIN_STORE = 'DOMAIN_STORE'
export const DARK_MODE = 'DARK_MODE'
export const THEME_SETTING = 'THEME_SETTING'
export const CONTENT_WIDTH_TYPE = {
Fluid: 'Fluid',

904
ui/src/style/dark-mode.less Normal file
View File

@ -0,0 +1,904 @@
// 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.
@dark-bgColor: #090c10;
@dark-secondary-bgColor: #141414;
@dark-text-color-1: rgba(255, 255, 255, 0.25);
@dark-text-color-2: rgba(255, 255, 255, 0.45);
@dark-text-color-3: rgba(255, 255, 255, 0.65);
@dark-text-color-4: rgba(255, 255, 255, 0.85);
@box-shadow-1: rgba(0, 0, 0, 0.32);
@box-shadow-2: rgba(0, 0, 0, 0.20);
@box-shadow-3: rgba(0, 0, 0, 0.12);
@light-text-color: rgba(0, 0, 0, 0.65);
@dark-border-color: #434343;
@dropdown-bgColor: #1f1f1f;
@dropdown-hover-bgColor: rgba(255, 255, 255, 0.08);
@table-header-bgColor: #1d1d1d;
@table-header-hover-bgColor: #303030;
@table-body-hover-bgColor: #262626;
@disabled-bgColor: #555;
.dark-mode {
background: @dark-bgColor;
h1, h2, h3, h4, h5, h6 {
color: @dark-text-color-3;
}
.user-layout, .ant-layout {
background: @dark-bgColor;
}
.layout.ant-layout .header {
background: @dark-secondary-bgColor;
box-shadow: 0 1px 4px #090c10;
}
.layout.ant-layout .trigger,
.layout.ant-layout .header .user-menu .action,
.layout.ant-layout .top-nav-header-index .user-menu .action,
.ant-tabs {
color: @dark-text-color-3;
}
.ant-layout-footer {
background: @dark-secondary-bgColor;
color: @dark-text-color-3;
.footer {
.line {
a {
color: @dark-text-color-3;
&:hover {
color: @dark-text-color-4;
}
}
}
.copyright {
color: @dark-text-color-3;
}
}
}
.sider.light {
background: @dark-secondary-bgColor;
.logo {
background-color: @dark-secondary-bgColor;
box-shadow: 1px 1px 0px 0px @dark-border-color;
}
.ant-menu-light,
.ant-menu-submenu > .ant-menu {
background: @dark-secondary-bgColor;
}
}
.ant-menu-submenu-popup.ant-menu-light,
.ant-menu-light > .ant-menu {
background: @dark-secondary-bgColor;
}
.ant-menu {
&-vertical:not(.ant-menu-dark) {
.ant-menu-item,
.ant-menu-submenu-title:not(:hover),
.ant-menu-item:not(.ant-menu-item-selected, :hover) > a {
color: @dark-text-color-3;
}
}
&-inline:not(.ant-menu-dark, .ant-menu-sub) {
.ant-menu-item,
.ant-menu-item:not(.ant-menu-item-selected) > a:not(:hover),
.ant-menu-submenu-title:not(:hover) {
color: @dark-text-color-3;
}
}
&-submenu:not(.ant-menu-dark, .ant-menu-submenu-inline) {
.ant-menu-item:not(.ant-menu-item-selected, :hover) > a {
color: @dark-text-color-3;
}
}
}
.kubernet-icon path
{
color: @dark-text-color-3;
}
.ant-menu-submenu-vertical > .ant-menu-submenu-title .ant-menu-submenu-arrow::before,
.ant-menu-submenu-vertical-left > .ant-menu-submenu-title .ant-menu-submenu-arrow::before,
.ant-menu-submenu-vertical-right > .ant-menu-submenu-title .ant-menu-submenu-arrow::before,
.ant-menu-submenu-inline > .ant-menu-submenu-title .ant-menu-submenu-arrow::before,
.ant-menu-submenu-vertical > .ant-menu-submenu-title .ant-menu-submenu-arrow::after,
.ant-menu-submenu-vertical-left > .ant-menu-submenu-title .ant-menu-submenu-arrow::after,
.ant-menu-submenu-vertical-right > .ant-menu-submenu-title .ant-menu-submenu-arrow::after,
.ant-menu-submenu-inline > .ant-menu-submenu-title .ant-menu-submenu-arrow::after {
background-color: @dark-text-color-3;
}
.ant-card {
background: @dark-secondary-bgColor;
color: @dark-text-color-3;
&-head, &-bottom, &-body {
color: @dark-text-color-3;
border-color: @dark-border-color;
}
.ant-progress-circle {
.ant-progress-text {
color: @dark-text-color-3;
}
}
&-bordered {
border-color: @dark-border-color;
}
}
.chart-card-footer {
border-color: @dark-border-color;
}
.vm-info-card .resource-detail-item__details a,
.vm-info-card .resource-detail-item a {
color: @dark-text-color-3;
}
.ant-breadcrumb {
a:not(:hover), &-separator {
color: @dark-text-color-3;
}
span:last-child, span:last-child a {
color: @dark-text-color-4;
}
}
.ant-btn {
&:not(.ant-btn-primary, .ant-btn-danger, :disabled) {
color: @dark-text-color-3;
background-color: transparent;
border-color: @dark-border-color;
}
&:disabled {
background-color: @disabled-bgColor;
color: @dark-text-color-3;
}
&-primary-disabled,
&-primary.disabled,
&-primary[disabled],
&-primary-disabled:hover,
&-primary.disabled:hover,
&-primary[disabled]:hover,
&-primary-disabled:focus,
&-primary.disabled:focus,
&-primary[disabled]:focus,
&-primary-disabled:active,
&-primary.disabled:active,
&-primary[disabled]:active,
&-primary-disabled.active,
&-primary.disabled.active,
&-primary[disabled].active {
color: @dark-text-color-3;
background-color: @disabled-bgColor;
}
}
.has-error .ant-input-affix-wrapper .ant-input,
.has-error .ant-input-affix-wrapper .ant-input:hover,
.has-error .ant-input,
.has-error .ant-input:hover {
background-color: transparent;
background-image: none;
}
.ant-badge-status-text {
color: @dark-text-color-3;
}
.ant-table {
color: @dark-text-color-3;
&-thead {
background-color: @table-header-bgColor;
tr th {
color: @dark-text-color-4;
background-color: @table-header-bgColor;
border-color: @dark-border-color;
.ant-table-column-has-actions.ant-table-column-has-sorters:hover,
.ant-table-column-has-actions.ant-table-column-has-sorters:hover,
.ant-table-column-has-actions.ant-table-column-has-sorters:hover .ant-table-filter-icon,
.ant-table-column-has-actions.ant-table-column-has-sorters:hover .anticon-filter {
background-color: @table-header-hover-bgColor;
}
}
& > tr > th.ant-table-column-has-actions.ant-table-column-has-sorters:hover {
background-color: @table-header-hover-bgColor;
}
& > tr:hover.ant-table-row-selected > td,
& > tr.ant-table-row-hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td,
& > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td {
background-color: transparent;
}
}
&-tbody {
& > tr > td {
border-color: @dark-border-color;
}
& > tr.ant-table-row-selected td,
& > tr:hover.ant-table-row-selected > td,
& > tr.ant-table-row-hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td,
& > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td {
background-color: @table-body-hover-bgColor;
}
& > tr > th.ant-table-column-sort {
background-color: @dark-bgColor;
}
}
&-footer {
background-color: @dark-secondary-bgColor;
color: @dark-text-color-3;
border-color: @dark-border-color;
&::before {
background-color: @dark-border-color;
}
}
&-header {
background-color: @dark-secondary-bgColor;
}
&-small {
border-color: @dark-border-color;
& > .ant-table-content > .ant-table-body .ant-table-thead {
background-color: transparent;
}
}
tr.ant-table-expanded-row,
tr.ant-table-expanded-row:hover {
background-color: @dark-bgColor;
}
&-placeholder {
border-color: @dark-border-color;
background-color: @dark-secondary-bgColor;
}
&-row-expand-icon {
border-color: @dark-text-color-3;
color: @dark-text-color-3;
background-color: transparent;
}
&-filter-dropdown {
background-color: @dark-secondary-bgColor;
&-btns {
border-color: @dark-border-color;
}
}
}
.light-row, .dark-row {
background-color: @dark-secondary-bgColor;
}
.ant-pagination {
color: @dark-text-color-3;
&-prev, &-next, &-jump-prev, &-jump-next, &-prev a, &-next a {
color: @dark-text-color-3;
}
&-disabled a,
&-disabled:hover a,
&-disabled:focus a,
&-disabled .ant-pagination-item-link,
&-disabled:hover .ant-pagination-item-link,
&-disabled:focus .ant-pagination-item-link {
color: @dark-text-color-1;
}
&-item {
a:not(:hover) {
color: @dark-text-color-3;
}
&-active {
background-color: transparent;
}
}
&-options-quick-jumper input {
background-color: transparent;
background-image: none;
border-color: @dark-border-color;
color: @dark-text-color-3;
}
}
.ant-popover {
&-message {
color: @dark-text-color-3;
}
&-inner-content {
color: @dark-text-color-3;
background-color: @dark-secondary-bgColor;
border: 1px solid @dark-border-color;
box-shadow:
0 3px 6px -4px @box-shadow-1,
0 6px 16px 0 @box-shadow-2,
0 9px 28px 8px @box-shadow-3;
}
&-placement {
&-bottom > .ant-popover-content > .ant-popover-arrow,
&-bottomLeft > .ant-popover-content > .ant-popover-arrow,
&-bottomRight > .ant-popover-content > .ant-popover-arrow {
border-top-color: @dark-border-color;
border-left-color: @dark-border-color;
}
&-top > .ant-popover-content > .ant-popover-arrow,
&-topLeft > .ant-popover-content > .ant-popover-arrow,
&-topRight > .ant-popover-content > .ant-popover-arrow {
border-right-color: @dark-border-color;
border-bottom-color: @dark-border-color;
}
}
}
.ant-list-item {
color: @dark-text-color-3;
border-color: @dark-border-color;
&-meta-title, &-meta-description {
color: @dark-text-color-3;
}
}
.ant-tag {
background-color: transparent;
background-image: none;
border-color: @dark-border-color;
color: @dark-text-color-3;
.anticon-close {
color: @dark-text-color-3;
&:hover {
color: @dark-text-color-4;
}
}
}
.ant-avatar {
background-color: transparent;
background-image: none;
border: 1px solid @dark-border-color;
color: @dark-text-color-3;
}
.ant-form {
color: @dark-text-color-3;
&-item-label > label {
color: @dark-text-color-3;
}
}
.ant-modal {
color: @dark-text-color-3;
&-content {
background-color: @dark-secondary-bgColor;
box-shadow:
0 3px 6px -4px @box-shadow-1,
0 6px 16px 0 @box-shadow-2,
0 9px 28px 8px @box-shadow-3;
}
&-header {
background-color: @dark-secondary-bgColor;
border-color: @dark-border-color;
}
&-footer {
border-color: @dark-border-color;
}
&-confirm-body &-confirm-title,
&-title, &-close-x {
color: @dark-text-color-3;
}
}
.ant-input,
.ant-select-selection,
.ant-input-group-addon,
.ant-checkbox-inner,
.ant-radio-inner,
.ant-radio-button-wrapper,
.ant-input-number,
.ant-time-picker-input {
background-color: transparent;
color: @dark-text-color-3;
&:not(:hover, :focus) {
border-color: @dark-border-color;
}
&:disabled, &-disabled {
background-color: @disabled-bgColor;
}
}
.ant-select-disabled {
background-color: @disabled-bgColor;
}
.ant-checkbox-wrapper,
.ant-select-arrow {
color: @dark-text-color-3;
}
.ant-switch {
color: @light-text-color;
background-color: @dark-text-color-2;
&-checked {
background-color: #1890ff;
}
&-loading-icon, &:after {
background-color: @dark-secondary-bgColor;
}
&:disabled {
background-color: @disabled-bgColor;
}
}
.ant-select-dropdown {
background-color: @dropdown-bgColor;
color: @dark-text-color-3;
box-shadow:
0 3px 6px -4px @box-shadow-1,
0 6px 16px 0 @box-shadow-2,
0 9px 28px 8px @box-shadow-3;
&-menu-item {
color: @dark-text-color-3;
&-selected {
background-color: @dropdown-hover-bgColor;
}
}
&-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled),
&-menu-item-active:not(.ant-select-dropdown-menu-item-disabled) {
background-color: @dropdown-hover-bgColor;
}
}
.ant-calendar {
background-color: @dropdown-bgColor;
border-color: @dark-border-color;
&-last-month-cell .ant-calendar-date,
&-last-month-cell .ant-calendar-date:hover,
&-next-month-btn-day .ant-calendar-date,
&-next-month-btn-day .ant-calendar-date:hover {
color: @dark-text-color-1;
}
&-picker-container, &-date {
color: @dark-text-color-3;
}
&-input-wrap {
border-color: @dark-border-color;
}
&-range {
.ant-calendar-input,
.ant-calendar-time-picker-input,
.ant-calendar-input:placeholder-shown,
.ant-calendar-time-picker-input:placeholder-shown {
background-color: transparent;
color: @dark-text-color-3;
}
&-middle, &-picker-separator {
color: @dark-text-color-3;
}
.ant-calendar-body,
.ant-calendar-decade-panel-body,
.ant-calendar-month-panel-body,
.ant-calendar-year-panel-body {
border-color: @dark-border-color;
}
.ant-calendar-in-range-cell > div {
color: #000;
}
}
&-header {
.ant-calendar-next-century-btn,
.ant-calendar-next-decade-btn,
.ant-calendar-next-month-btn,
.ant-calendar-next-year-btn,
.ant-calendar-prev-century-btn,
.ant-calendar-prev-decade-btn,
.ant-calendar-prev-month-btn,
.ant-calendar-prev-year-btn {
color: @dark-text-color-2;
}
.ant-calendar-prev-month-btn:after,
.ant-calendar-prev-month-btn:before,
.ant-calendar-next-month-btn::before,
.ant-calendar-next-month-btn::after {
border-color: @dark-text-color-2;
}
.ant-calendar-prev-month-btn:hover:after,
.ant-calendar-prev-month-btn:hover:before,
.ant-calendar-next-month-btn:hover::before,
.ant-calendar-next-month-btn:hover::after {
border-color: @dark-text-color-4;
}
.ant-calendar-century-select:not(:hover),
.ant-calendar-decade-select:not(:hover),
.ant-calendar-month-select:not(:hover),
.ant-calendar-year-select:not(:hover) {
color: @dark-text-color-3;
}
.ant-calendar-prev-century-btn::before,
.ant-calendar-prev-decade-btn::before,
.ant-calendar-prev-year-btn::before,
.ant-calendar-prev-century-btn::after,
.ant-calendar-prev-decade-btn::after,
.ant-calendar-prev-year-btn::after,
.ant-calendar-next-century-btn::before,
.ant-calendar-next-decade-btn::before,
.ant-calendar-next-year-btn::before,
.ant-calendar-next-century-btn::after,
.ant-calendar-next-decade-btn::after,
.ant-calendar-next-year-btn::after {
border-color: @dark-text-color-2;
}
.ant-calendar-prev-century-btn:hover::before,
.ant-calendar-prev-decade-btn:hover::before,
.ant-calendar-prev-year-btn:hover::before,
.ant-calendar-prev-century-btn:hover::after,
.ant-calendar-prev-decade-btn:hover::after,
.ant-calendar-prev-year-btn:hover::after {
border-color: @dark-text-color-4;
}
}
&-date:hover {
color: #000;
}
&-picker-clear {
color: @dark-text-color-2;
background: transparent;
&:hover {
color: @dark-text-color-4;
}
}
}
.ant-time {
&-picker-panel {
color: @dark-text-color-3;
&-inner {
background-color: @dropdown-bgColor;
box-shadow:
0 3px 6px -4px @box-shadow-1,
0 6px 16px 0 @box-shadow-2,
0 9px 28px 8px @box-shadow-3;
}
&-input {
background-color: transparent;
&-wrap {
border-color: @dark-border-color;
}
}
&-select {
border-color: @dark-border-color;
li:hover,
li.ant-time-picker-panel-select-option-selected,
li.ant-time-picker-panel-select-option-selected:hover {
background-color: @dropdown-hover-bgColor;
}
}
}
}
.ant-dropdown-menu {
background-color: @dropdown-bgColor;
box-shadow:
0 6px 16px -8px @box-shadow-1,
0 9px 28px 0 @box-shadow-2,
0 12px 48px 16px @box-shadow-3;
&-item:not(.ant-dropdown-menu-item-selected):hover,
&-submenu-title:not(.ant-dropdown-menu-item-selected):hover {
background-color: @dropdown-hover-bgColor;
}
&-item:not(.ant-dropdown-menu-item-selected),
&-submenu-title:not(.ant-dropdown-menu-item-selected),
&-item:not(.ant-dropdown-menu-item-selected) > a,
&-submenu-title:not(.ant-dropdown-menu-item-selected) > a {
color: @dark-text-color-3;
}
}
.user-layout .ant-input-affix-wrapper .ant-input-prefix,
.user-layout .ant-input-affix-wrapper .ant-input-suffix {
color: @dark-text-color-3;
}
.ant-input-affix-wrapper .ant-input-prefix,
.ant-input-affix-wrapper .ant-input-suffix,
.ant-input-password-icon {
color: @dark-text-color-3;
}
.ant-input-number-handler-wrap {
background-color: @dark-secondary-bgColor;
}
.ant-input-number-handler,
.ant-time-picker-icon,
.ant-time-picker-clear,
.ant-time-picker-icon .ant-time-picker-clock-icon,
.ant-time-picker-clear .ant-time-picker-clock-icon {
color: @dark-text-color-3;
}
.ant-steps-item-finish .ant-steps-item-icon {
background-color: transparent;
}
.ant-steps-item-process > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title,
.ant-steps-item-process > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-description {
color: @dark-text-color-3;
}
.ant-steps-item-wait .ant-steps-item-icon {
background-color: transparent;
border-color: @dark-border-color;
}
.ant-steps-item-process > .ant-steps-item-container > .ant-steps-item-tail::after,
.ant-steps-item-wait > .ant-steps-item-container > .ant-steps-item-tail::after {
background-color: @dark-border-color;
}
.ant-steps-item-wait .ant-steps-item-icon > .ant-steps-icon,
.ant-steps-item-wait > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title {
color: @dark-text-color-3;
}
.ant-form-item,
.ant-radio-wrapper {
color: @dark-text-color-3;
}
.ant-table-fixed-left table, .ant-table-fixed-right table,
.ant-table-fixed-header > .ant-table-content > .ant-table-scroll > .ant-table-body {
background-color: @dark-secondary-bgColor;
}
.ant-upload.ant-upload-drag {
background-color: transparent;
border-color: @dark-border-color;
}
.ant-upload.ant-upload-drag p.ant-upload-text {
color: @dark-text-color-3;
}
.ant-tree.ant-tree-show-line li span.ant-tree-switcher {
background-color: transparent;
color: @dark-text-color-3;
}
.ant-tree li .ant-tree-node-content-wrapper {
color: @dark-text-color-3;
}
.ant-tree-icon__customize {
color: @dark-text-color-3;
background-color: transparent;
}
.ant-tree li .ant-tree-node-content-wrapper.ant-tree-node-selected {
.ant-tree-icon__customize {
color: #000;
}
color: #000;
}
.ant-tree li .ant-tree-node-content-wrapper:hover {
.ant-tree-icon__customize {
color: #000;
}
.ant-tree-title {
color: #000;
}
}
.form-content, .zone-support {
background-color: @dark-bgColor;
border-color: @dark-border-color;
}
.ant-steps-item-wait .ant-steps-item-icon > .ant-steps-icon .ant-steps-icon-dot {
background-color: @dark-text-color-3;
}
.ant-steps-item-finish > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title {
color: @dark-text-color-3;
}
.ant-select-selection__clear {
background-color: transparent;
color: @dark-text-color-3;
&:hover {
color: @dark-text-color-2;
}
}
.anticon {
&-info-circle {
color: @dark-text-color-3;
}
}
.ant-message-notice-content {
background-color: @dropdown-bgColor;
color: @dark-text-color-3;
box-shadow:
0 3px 6px -4px @box-shadow-1,
0 6px 16px 0 @box-shadow-2,
0 9px 28px 8px @box-shadow-3;
}
.btn-add-tag {
background-color: transparent;
}
.tag-disabled-input.ant-input-disabled {
background-color: transparent;
}
.tagsTitle {
color: @dark-text-color-3;
}
.ant-notification {
color: @dark-text-color-3;
&-notice {
background-color: @dark-secondary-bgColor;
border: 1px solid @dark-border-color;
box-shadow:
0 3px 6px -4px @box-shadow-1,
0 6px 16px 0 @box-shadow-2,
0 9px 28px 8px @box-shadow-3;
&-message {
color: @dark-text-color-4;
}
&-close {
color: @dark-text-color-3;
&:hover {
color: @dark-text-color-4;
}
}
}
}
.ant-collapse {
background-color: @dark-secondary-bgColor;
&--borderless {
background-color: @dark-secondary-bgColor;
}
& > .ant-collapse-item {
background-color: @dark-bgColor;
& > .ant-collapse-header {
color: @dark-text-color-3;
}
&-disabled > .ant-collapse-header,
&-disabled > .ant-collapse-header > .arrow {
color: @dark-text-color-1;
}
}
}
.drawer {
.content {
background-color: @dark-secondary-bgColor;
box-shadow:
0 3px 6px -4px @box-shadow-1,
0 6px 16px 0 @box-shadow-2,
0 9px 28px 8px @box-shadow-3;
}
}
::placeholder {
color: @dark-text-color-1;
}
.ant-card.usage-dashboard-chart-card.usage-chart-text {
h1, h2, h3, h4, h5, h6 {
color: initial;
}
}
.ant-empty-normal {
color: @dark-text-color-3;
}
}

View File

@ -37,3 +37,4 @@
@import "frame/top-menu";
@import "objects/table";
@import "dark-mode";

View File

@ -90,6 +90,10 @@ a {
box-shadow: 1px 1px 0px 0px #e8e8e8;
}
.sider.dark .logo {
background-color: @project-nav-background-color;
}
.sider.light {
background: @navigation-background-color;
@ -149,10 +153,6 @@ a {
.ant-menu-submenu-title:hover
{
color: @primary-color;
.custom-icon path {
color: @primary-color;
}
}
.ant-menu-submenu-vertical > .ant-menu-submenu-title .ant-menu-submenu-arrow::before,
@ -254,4 +254,93 @@ a {
.ant-pagination-options {
display: inline-block;
}
}
}
.user-layout {
background: #ffffff;
.ant-input-affix-wrapper .ant-input-prefix,
.ant-input-affix-wrapper .ant-input-suffix {
color: rgba(0,0,0,.25);
}
}
.footer {
.line {
a {
color: rgba(0, 0, 0, .45);
&:hover {
color: rgba(0, 0, 0, .65);
}
}
}
.copyright {
color: rgba(0, 0, 0, .45);
}
}
.ant-tree-icon__customize {
color: rgba(0, 0, 0, 0.45);
background: #fff;
}
.form-content {
background-color: #fafafa;
}
.zone-support {
background: #fafafa;
}
.anticon {
&-info-circle {
color: rgba(0,0,0,.45);
}
}
.light-row {
background-color: #fff;
}
.dark-row {
background-color: #f9f9f9;
}
.tag-disabled-input, .btn-add-tag {
background-color: #fff;
}
.tagsTitle {
color: rgba(0, 0, 0, 0.85);
}
.ant-btn.filter-button:hover,
.ant-dropdown-menu-item:hover,
.ant-dropdown-menu-submenu-title:hover,
.ant-dropdown-menu-item > a:hover,
.ant-dropdown-menu-submenu-title > a:hover {
color: @primary-color;
}
.drawer {
.img-checkbox {
.check-icon.light {
color: #000;
}
.check-icon.dark {
color: #ffffff;
}
}
.color-checkbox {
.check-icon {
color: #ffffff;
}
}
.input-group .color-picker {
border-color: @primary-color;
}
}

View File

@ -64,7 +64,7 @@
{rules: [{ required: true, message: $t('message.error.username') }, { validator: handleUsernameOrEmail }], validateTrigger: 'change'}
]"
>
<a-icon slot="prefix" type="user" :style="{ color: 'rgba(0,0,0,.25)' }"/>
<a-icon slot="prefix" type="user" />
</a-input>
</a-form-item>
@ -79,7 +79,7 @@
{rules: [{ required: true, message: $t('message.error.password') }], validateTrigger: 'blur'}
]"
>
<a-icon slot="prefix" type="lock" :style="{ color: 'rgba(0,0,0,.25)' }"/>
<a-icon slot="prefix" type="lock" />
</a-input-password>
</a-form-item>
@ -93,7 +93,7 @@
{rules: [{ required: false, message: $t('message.error.domain') }], validateTrigger: 'change'}
]"
>
<a-icon slot="prefix" type="block" :style="{ color: 'rgba(0,0,0,.25)' }"/>
<a-icon slot="prefix" type="block" />
</a-input>
</a-form-item>

View File

@ -44,7 +44,7 @@
:placeholder="record.cidr"
@change="($event) => updateNetworkData('ipAddress', record.id, $event.target.value)">
<a-tooltip v-if="record.type !== 'L2'" slot="suffix" :title="getIpRangeDescription(record)">
<a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
<a-icon type="info-circle" />
</a-tooltip>
</a-input>
</a-form-item>
@ -61,7 +61,7 @@
}]"
@change="($event) => updateNetworkData('macAddress', record.id, $event.target.value)">
<a-tooltip slot="suffix" :title="$t('label.macaddress.example')">
<a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
<a-icon type="info-circle" />
</a-tooltip>
</a-input>
</a-form-item>

View File

@ -24,7 +24,7 @@
v-for="stat in stats"
:key="stat.type">
<a-card
class="usage-dashboard-chart-card"
:class="['usage-dashboard-chart-card', stat.bgcolor ? 'usage-chart-text' : '']"
:bordered="false"
:loading="loading"
:style="stat.bgcolor ? { 'background-color': stat.bgcolor } : {}">

View File

@ -477,4 +477,12 @@ export default {
background-color: #f9f9f9;
}
.card-footer {
text-align: right;
button + button {
margin-left: 8px;
}
}
</style>

View File

@ -18,7 +18,7 @@
<template>
<a-spin :spinning="fetchLoading">
<a-list size="small">
<a-list-item>
<a-list-item v-if="host.hypervisorversion || (host.details && host.details['Host.OS'])">
<div>
<strong>{{ $t('label.hypervisorversion') }}</strong>
<div>
@ -26,12 +26,9 @@
<span v-if="host.hypervisorversion">
{{ host.hypervisorversion }}
</span>
<span v-else-if="host.details">
<span v-else-if="host.details && host.details['Host.OS']">
{{ host.details['Host.OS'] + ' ' + host.details['Host.OS.Version'] }}
</span>
<span v-else>
{{ host.version }}
</span>
</div>
</div>
</a-list-item>
@ -130,15 +127,16 @@ export default {
},
watch: {
resource (newItem, oldItem) {
if (this.resource && this.resource.id && newItem && newItem.id !== oldItem.id) {
this.fetchData()
if (this.resource) {
this.host = this.resource
if (this.resource.id && newItem && newItem.id !== oldItem.id) {
this.fetchData()
}
}
}
},
methods: {
fetchData () {
this.dataSource = []
this.itemCount = 0
this.fetchLoading = true
api('listHosts', { id: this.resource.id }).then(json => {
this.host = json.listhostsresponse.host[0]

View File

@ -140,7 +140,6 @@ export default {
.form-content {
border: 1px dashed #e9e9e9;
border-radius: 6px;
background-color: #fafafa;
min-height: 200px;
text-align: center;
vertical-align: center;
@ -162,7 +161,6 @@ export default {
.zone-support {
text-align: justify;
background: #fafafa;
}
}
</style>

View File

@ -484,7 +484,6 @@ export default {
.tagsTitle {
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
margin-bottom: 12px;
}
</style>

View File

@ -435,7 +435,6 @@ export default {
.tagsTitle {
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
margin-bottom: 12px;
}
</style>

View File

@ -308,6 +308,12 @@
v-decorator="['routeripv6', {}]"
:placeholder="this.$t('label.routeripv6')"/>
</a-form-item>
<a-form-item>
<tooltip-label slot="label" :title="$t('label.endipv6')" :tooltip="apiParams.endipv6.description"/>
<a-input
v-decorator="['endipv6', {}]"
:placeholder="this.$t('label.endipv6')"/>
</a-form-item>
<a-form-item>
<tooltip-label slot="label" :title="$t('label.networkdomain')" :tooltip="apiParams.networkdomain.description"/>
<a-input
@ -825,7 +831,6 @@ export default {
.tagsTitle {
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
margin-bottom: 12px;
}
</style>

View File

@ -30,7 +30,8 @@
<a-input
placeholder="-"
disabled
style="width: 30px; border-left: 0; border-right: 0; pointer-events: none; backgroundColor: #fff; text-align:
class="tag-disabled-input"
style="width: 30px; border-left: 0; border-right: 0; pointer-events: none; text-align:
center; margin-right: 0;"></a-input>
<a-input
v-model="newRule.privateendport"
@ -48,7 +49,8 @@
<a-input
placeholder="-"
disabled
style="width: 30px; border-left: 0; border-right: 0; pointer-events: none; backgroundColor: #fff;
class="tag-disabled-input"
style="width: 30px; border-left: 0; border-right: 0; pointer-events: none;
text-align: center; margin-right: 0;"></a-input>
<a-input
v-model="newRule.publicendport"

View File

@ -398,7 +398,7 @@ export default {
scopedSlots: { customRender: 'ip' }
}
],
customStyle: 'margin-bottom: -10px; border-bottom-style: none',
customStyle: 'margin-bottom: 0; border: none',
page: 1,
pageSize: 10,
itemCounts: {

View File

@ -149,7 +149,7 @@ export default {
editModalVisible: false,
selectedRole: null,
projectPermisssions: [],
customStyle: 'margin-bottom: -10px; border-bottom-style: none'
customStyle: 'margin-bottom: 0; border: none'
}
},
beforeCreate () {

View File

@ -49,7 +49,7 @@
</a-select>
</a-form-item>
<a-form-item>
<tooltip-label slot="label" :title="$t('label.diskofferingid')" :tooltip="apiParams.diskofferingid.description"/>
<tooltip-label slot="label" :title="$t('label.diskofferingid')" :tooltip="apiParams.diskofferingid.description || 'Disk Offering'"/>
<a-select
v-decorator="['diskofferingid', {
initialValue: selectedDiskOfferingId,

View File

@ -161,13 +161,17 @@
@keyup.enter="handleInputConfirm"
compact>
<a-input ref="input" :value="inputKey" @change="handleKeyChange" style="width: 100px; text-align: center" :placeholder="$t('label.key')" />
<a-input style=" width: 30px; border-left: 0; pointer-events: none; backgroundColor: #fff" placeholder="=" disabled />
<a-input
class="tag-disabled-input"
style=" width: 30px; border-left: 0; pointer-events: none; text-align: center"
placeholder="="
disabled />
<a-input :value="inputValue" @change="handleValueChange" style="width: 100px; text-align: center; border-left: 0" :placeholder="$t('label.value')" />
<tooltip-button :tooltip="$t('label.ok')" icon="check" size="small" @click="handleInputConfirm" />
<tooltip-button :tooltip="$t('label.cancel')" icon="close" size="small" @click="inputVisible=false" />
</a-input-group>
</div>
<a-tag v-else @click="showInput" style="background: #fff; borderStyle: dashed;">
<a-tag v-else @click="showInput" class="btn-add-tag" style="borderStyle: dashed;">
<a-icon type="plus" /> {{ $t('label.new.tag') }}
</a-tag>
</div>
@ -424,7 +428,6 @@ export default {
.tagsTitle {
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
margin-bottom: 12px;
}
</style>

View File

@ -62,13 +62,17 @@
@keyup.enter="handleInputConfirm"
compact>
<a-input ref="input" :value="inputKey" @change="handleKeyChange" style="width: 100px; text-align: center" :placeholder="$t('label.key')" />
<a-input style=" width: 30px; border-left: 0; pointer-events: none; backgroundColor: #fff" placeholder="=" disabled />
<a-input
class="tag-disabled-input"
style=" width: 30px; border-left: 0; pointer-events: none; text-align: center"
placeholder="="
disabled />
<a-input :value="inputValue" @change="handleValueChange" style="width: 100px; text-align: center; border-left: 0" :placeholder="$t('label.value')" />
<tooltip-button :tooltip="$t('label.ok')" icon="check" size="small" @click="handleInputConfirm" />
<tooltip-button :tooltip="$t('label.cancel')" icon="close" size="small" @click="inputVisible=false" />
</a-input-group>
</div>
<a-tag v-else @click="showInput" style="background: #fff; borderStyle: dashed;">
<a-tag v-else @click="showInput" class="btn-add-tag" style="borderStyle: dashed;">
<a-icon type="plus" /> {{ $t('label.new.tag') }}
</a-tag>
</div>
@ -255,7 +259,6 @@ export default {
.tagsTitle {
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
margin-bottom: 12px;
}
</style>