mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
UI: Add multiple management server support (#4885)
* add multiple management server support * display the server on the user menu * remove primary color in server icon * using `/client` from apiBase * add a setting that allows users to customize whether to use multiple servers or not * set default hidden the multiple server config
This commit is contained in:
parent
1ccb42017f
commit
1182051961
8
ui/public/config.json
vendored
8
ui/public/config.json
vendored
@ -1,5 +1,12 @@
|
||||
{
|
||||
"apiBase": "/client/api",
|
||||
"servers": [
|
||||
{
|
||||
"name": "Local-Server",
|
||||
"apiHost": "",
|
||||
"apiBase": "/client/api"
|
||||
}
|
||||
],
|
||||
"docBase": "http://docs.cloudstack.apache.org/en/latest",
|
||||
"appTitle": "CloudStack",
|
||||
"footer": "Licensed under the <a href='http://www.apache.org/licenses/' target='_blank'>Apache License</a>, Version 2.0.",
|
||||
@ -48,5 +55,6 @@
|
||||
},
|
||||
"plugins": [],
|
||||
"basicZoneEnabled": true,
|
||||
"multipleServer": false,
|
||||
"docHelpMappings": {}
|
||||
}
|
||||
|
||||
@ -20,6 +20,10 @@
|
||||
|
||||
<translation-menu class="action"/>
|
||||
<header-notice class="action"/>
|
||||
<label class="user-menu-server-info action" v-if="$config.multipleServer">
|
||||
<a-icon slot="prefix" type="database" />
|
||||
{{ server.name || server.apiBase || 'Local-Server' }}
|
||||
</label>
|
||||
<a-dropdown>
|
||||
<span class="user-menu-dropdown action">
|
||||
<a-avatar class="user-menu-avatar avatar" size="small" :src="avatar()"/>
|
||||
@ -59,9 +63,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import HeaderNotice from './HeaderNotice'
|
||||
import TranslationMenu from './TranslationMenu'
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import { SERVER_MANAGER } from '@/store/mutation-types'
|
||||
|
||||
export default {
|
||||
name: 'UserMenu',
|
||||
@ -69,6 +75,11 @@ export default {
|
||||
TranslationMenu,
|
||||
HeaderNotice
|
||||
},
|
||||
computed: {
|
||||
server () {
|
||||
return Vue.ls.get(SERVER_MANAGER) || this.$config.servers[0]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['Logout']),
|
||||
...mapGetters(['nickname', 'avatar']),
|
||||
@ -108,5 +119,11 @@ export default {
|
||||
min-width: 12px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&-server-info {
|
||||
.anticon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<template>
|
||||
<a
|
||||
v-if="['vm', 'systemvm', 'router', 'ilbvm'].includes($route.meta.name) && 'updateVirtualMachine' in $store.getters.apis"
|
||||
:href="'/client/console?cmd=access&vm=' + resource.id"
|
||||
:href="server + '/console?cmd=access&vm=' + resource.id"
|
||||
target="_blank">
|
||||
<a-button style="margin-left: 5px" shape="circle" type="dashed" :size="size" :disabled="['Stopped', 'Error', 'Destroyed'].includes(resource.state)" >
|
||||
<a-icon type="code" />
|
||||
@ -27,6 +27,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import { SERVER_MANAGER } from '@/store/mutation-types'
|
||||
|
||||
export default {
|
||||
name: 'Console',
|
||||
props: {
|
||||
@ -38,6 +41,19 @@ export default {
|
||||
type: String,
|
||||
default: 'small'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
server () {
|
||||
if (!this.$config.multipleServer) {
|
||||
return this.$config.apiBase.replace('/api', '')
|
||||
}
|
||||
const serverStorage = Vue.ls.get(SERVER_MANAGER)
|
||||
const apiBase = serverStorage.apiBase.replace('/api', '')
|
||||
if (!serverStorage.apiHost || serverStorage.apiHost === '/') {
|
||||
return [location.origin, apiBase].join('')
|
||||
}
|
||||
return [serverStorage.apiHost, apiBase].join('')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -37,7 +37,12 @@ Vue.use(toLocaleDatePlugin)
|
||||
|
||||
fetch('config.json').then(response => response.json()).then(config => {
|
||||
Vue.prototype.$config = config
|
||||
Vue.axios.defaults.baseURL = config.apiBase
|
||||
let basUrl = config.apiBase
|
||||
if (config.multipleServer) {
|
||||
basUrl = (config.servers[0].apiHost || '') + config.servers[0].apiBase
|
||||
}
|
||||
|
||||
Vue.axios.defaults.baseURL = basUrl
|
||||
|
||||
loadLanguageAsync().then(() => {
|
||||
new Vue({
|
||||
|
||||
@ -26,7 +26,7 @@ import 'nprogress/nprogress.css' // progress bar style
|
||||
import message from 'ant-design-vue/es/message'
|
||||
import notification from 'ant-design-vue/es/notification'
|
||||
import { setDocumentTitle } from '@/utils/domUtil'
|
||||
import { ACCESS_TOKEN, APIS } from '@/store/mutation-types'
|
||||
import { ACCESS_TOKEN, APIS, SERVER_MANAGER } from '@/store/mutation-types'
|
||||
|
||||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||
|
||||
@ -39,6 +39,20 @@ router.beforeEach((to, from, next) => {
|
||||
const title = i18n.t(to.meta.title) + ' - ' + Vue.prototype.$config.appTitle
|
||||
setDocumentTitle(title)
|
||||
}
|
||||
|
||||
if (Vue.prototype.$config.multipleServer) {
|
||||
const servers = Vue.prototype.$config.servers
|
||||
const serverStorage = Vue.ls.get(SERVER_MANAGER)
|
||||
let apiFullPath = ''
|
||||
if (serverStorage) {
|
||||
apiFullPath = (serverStorage.apiHost || '') + serverStorage.apiBase
|
||||
}
|
||||
const serverFilter = servers.filter(ser => (ser.apiHost || '') + ser.apiBase === apiFullPath)
|
||||
const server = serverFilter[0] || servers[0]
|
||||
Vue.axios.defaults.baseURL = (server.apiHost || '') + server.apiBase
|
||||
store.dispatch('SetServer', server)
|
||||
}
|
||||
|
||||
const validLogin = Vue.ls.get(ACCESS_TOKEN) || Cookies.get('userid') || Cookies.get('userid', { path: '/client' })
|
||||
if (validLogin) {
|
||||
if (to.path === '/user/login') {
|
||||
|
||||
@ -36,6 +36,7 @@ const getters = {
|
||||
zones: state => state.user.zones,
|
||||
timezoneoffset: state => state.user.timezoneoffset,
|
||||
usebrowsertimezone: state => state.user.usebrowsertimezone,
|
||||
server: state => state.app.server,
|
||||
domainStore: state => state.user.domainStore
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,8 @@ import {
|
||||
DEFAULT_FIXED_HEADER_HIDDEN,
|
||||
DEFAULT_CONTENT_WIDTH_TYPE,
|
||||
DEFAULT_MULTI_TAB,
|
||||
USE_BROWSER_TIMEZONE
|
||||
USE_BROWSER_TIMEZONE,
|
||||
SERVER_MANAGER
|
||||
} from '@/store/mutation-types'
|
||||
|
||||
const app = {
|
||||
@ -44,7 +45,8 @@ const app = {
|
||||
color: null,
|
||||
inverted: true,
|
||||
multiTab: true,
|
||||
metrics: false
|
||||
metrics: false,
|
||||
server: ''
|
||||
},
|
||||
mutations: {
|
||||
SET_SIDEBAR_TYPE: (state, type) => {
|
||||
@ -100,6 +102,10 @@ const app = {
|
||||
SET_USE_BROWSER_TIMEZONE: (state, bool) => {
|
||||
Vue.ls.set(USE_BROWSER_TIMEZONE, bool)
|
||||
state.usebrowsertimezone = bool
|
||||
},
|
||||
SET_SERVER: (state, server) => {
|
||||
Vue.ls.set(SERVER_MANAGER, server)
|
||||
state.server = server
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@ -147,6 +153,9 @@ const app = {
|
||||
},
|
||||
SetUseBrowserTimezone ({ commit }, bool) {
|
||||
commit('SET_USE_BROWSER_TIMEZONE', bool)
|
||||
},
|
||||
SetServer ({ commit }, server) {
|
||||
commit('SET_SERVER', server)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ export const ZONES = 'ZONES'
|
||||
export const HEADER_NOTICES = 'HEADER_NOTICES'
|
||||
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 CONTENT_WIDTH_TYPE = {
|
||||
|
||||
@ -35,6 +35,23 @@
|
||||
<a-icon type="safety" />
|
||||
{{ $t('label.login.portal') }}
|
||||
</span>
|
||||
<a-form-item v-if="$config.multipleServer">
|
||||
<a-select
|
||||
size="large"
|
||||
:placeholder="$t('server')"
|
||||
v-decorator="[
|
||||
'server',
|
||||
{
|
||||
initialValue: (server.apiHost || '') + server.apiBase
|
||||
}
|
||||
]"
|
||||
@change="onChangeServer">
|
||||
<a-select-option v-for="item in $config.servers" :key="(item.apiHost || '') + item.apiBase">
|
||||
<a-icon slot="prefix" type="database" :style="{ color: 'rgba(0,0,0,.25)' }"></a-icon>
|
||||
{{ item.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-input
|
||||
size="large"
|
||||
@ -85,6 +102,23 @@
|
||||
<a-icon type="audit" />
|
||||
{{ $t('label.login.single.signon') }}
|
||||
</span>
|
||||
<a-form-item v-if="$config.multipleServer">
|
||||
<a-select
|
||||
size="large"
|
||||
:placeholder="$t('server')"
|
||||
v-decorator="[
|
||||
'server',
|
||||
{
|
||||
initialValue: (server.apiHost || '') + server.apiBase
|
||||
}
|
||||
]"
|
||||
@change="onChangeServer">
|
||||
<a-select-option v-for="item in $config.servers" :key="(item.apiHost || '') + item.apiBase">
|
||||
<a-icon slot="prefix" type="database" :style="{ color: 'rgba(0,0,0,.25)' }"></a-icon>
|
||||
{{ item.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-select v-decorator="['idp', { initialValue: selectedIdp } ]">
|
||||
<a-select-option v-for="(idp, idx) in idps" :key="idx" :value="idp.id">
|
||||
@ -110,8 +144,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import { api } from '@/api'
|
||||
import store from '@/store'
|
||||
import { mapActions } from 'vuex'
|
||||
import { SERVER_MANAGER } from '@/store/mutation-types'
|
||||
import TranslationMenu from '@/components/header/TranslationMenu'
|
||||
|
||||
export default {
|
||||
@ -130,10 +167,15 @@ export default {
|
||||
time: 60,
|
||||
loginBtn: false,
|
||||
loginType: 0
|
||||
}
|
||||
},
|
||||
server: ''
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (this.$config.multipleServer) {
|
||||
this.server = Vue.ls.get(SERVER_MANAGER) || this.$config.servers[0]
|
||||
}
|
||||
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
@ -176,6 +218,11 @@ export default {
|
||||
|
||||
validateFields(validateFieldsKey, { force: true }, (err, values) => {
|
||||
if (!err) {
|
||||
if (this.$config.multipleServer) {
|
||||
this.axios.defaults.baseURL = (this.server.apiHost || '') + this.server.apiBase
|
||||
store.dispatch('SetServer', this.server)
|
||||
}
|
||||
|
||||
if (customActiveKey === 'cs') {
|
||||
const loginParams = { ...values }
|
||||
delete loginParams.username
|
||||
@ -216,6 +263,11 @@ export default {
|
||||
} else {
|
||||
this.$message.error(this.$t('message.login.failed'))
|
||||
}
|
||||
},
|
||||
onChangeServer (server) {
|
||||
const servers = this.$config.servers || []
|
||||
const serverFilter = servers.filter(ser => (ser.apiHost || '') + ser.apiBase === server)
|
||||
this.server = serverFilter[0] || {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user