Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions ui/public/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"apiBase": "/client/api",
"servers": [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this feature shouldn't be enabled by default, wouldn't it confuse users/admins? @utchoang @davidjumani @wido @nvazquez @sureshanaparti @weizhouapache @Pearl1594 @shwstppr ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the list only shows one server at the time, what would it confuse them? There is only one option to select

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rhtyd Yes. I will set it to default hidden mode. If the user/admin wants to enable it, the configuration can be changed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good with @utchoang's change, disabled by default. +1 for getting this in asap

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1
thanks @utchoang

{
"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.",
Expand Down Expand Up @@ -48,5 +55,6 @@
},
"plugins": [],
"basicZoneEnabled": true,
"multipleServer": false,
"docHelpMappings": {}
}
17 changes: 17 additions & 0 deletions ui/src/components/header/UserMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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()"/>
Expand Down Expand Up @@ -59,16 +63,23 @@
</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',
components: {
TranslationMenu,
HeaderNotice
},
computed: {
server () {
return Vue.ls.get(SERVER_MANAGER) || this.$config.servers[0]
}
},
methods: {
...mapActions(['Logout']),
...mapGetters(['nickname', 'avatar']),
Expand Down Expand Up @@ -108,5 +119,11 @@ export default {
min-width: 12px;
margin-right: 8px;
}

&-server-info {
.anticon {
margin-right: 5px;
}
}
}
</style>
18 changes: 17 additions & 1 deletion ui/src/components/widgets/Console.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand All @@ -27,6 +27,9 @@
</template>

<script>
import Vue from 'vue'
import { SERVER_MANAGER } from '@/store/mutation-types'

export default {
name: 'Console',
props: {
Expand All @@ -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>
7 changes: 6 additions & 1 deletion ui/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
16 changes: 15 additions & 1 deletion ui/src/permission.js
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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') {
Expand Down
1 change: 1 addition & 0 deletions ui/src/store/getters.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
13 changes: 11 additions & 2 deletions ui/src/store/modules/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -44,7 +45,8 @@ const app = {
color: null,
inverted: true,
multiTab: true,
metrics: false
metrics: false,
server: ''
},
mutations: {
SET_SIDEBAR_TYPE: (state, type) => {
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -147,6 +153,9 @@ const app = {
},
SetUseBrowserTimezone ({ commit }, bool) {
commit('SET_USE_BROWSER_TIMEZONE', bool)
},
SetServer ({ commit }, server) {
commit('SET_SERVER', server)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions ui/src/store/mutation-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const ZONES = 'ZONES'
export const ASYNC_JOB_IDS = 'ASYNC_JOB_IDS'
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 = {
Expand Down
54 changes: 53 additions & 1 deletion ui/src/views/auth/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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">
Expand All @@ -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 {
Expand All @@ -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: {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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] || {}
}
}
}
Expand Down