mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 01:32:18 +02:00
UI: Upgrade to Vue3 library (#5151)
* add new vue 3 library & and 2.x (beta) * edit config files, settings, utils, store,... corresponding to Vue 3 * edit layout and config to suit the new library * fix header & side menu * components, autogenview * fix dashboard & compute * compute: fix form errors * storage: fix form & template by vue3 * networks: fix form & template by vue3 * image: fix form & template by vue3 * project: fix by vue3 library * user: fix by vue3 * iam: fix by vue3 * fix zoneWizard & tooltip click event * fix infra > physicalnetwork & visible modal * fix infra by vue3 & antdv 2x * fix offerings by vue3 * fix plugin by vue3 * fix form & action form * update the ant-design latest version * fix icon, style dark mode, menu * fix unittest * fix babel plugins not found * add name,ref missing & callback i18n not found * fix slot & info icon * fix unit test * fix tooltip label of form item * fix lint errors * using global app, globalProperties * add focus directive & edit the position of ctrl+Enter * upgrage Vue 3 version * fix main UT * fix build failed * using `optionFilterProp="label"' & fix build fail * fix UT with new code * fix icons of undefined * fix error run app * fix selectbox options * add vue version for clear storage * fix template * fix template of iprange form * fix warning test UT * fix conflit * fix build failed * fix error run app the first time after upgrade * fix auto-complete & watch object/array * fix error run application * fix error build * fix form, icon, template & locales * fix conflit & form * remove slot errors * fix error build & test UT * fix error template * Add licenses for missing files * add scroll to first errors * add scroll to first errors * fix select filter, tag event * add shallowRef async component are missing * fix css, upgrade vue-cropper version * fix css * fix vue 3 coding for new components * Remove unused components * fixes `this` not found in @/roles * fix redirect after login again when session expired error * fix openKeys menu & watch router * fixes * fix build failed * fixes * fixes ut * fixes * fixes eslint * fixes * fixes * fixes css * fix menu sidebar css * fix some css icon, images * fix build fail * fixes * fixes * fixes * fixes * fix publicip resource * fixes ut * fixes * fixes * fixes layout mode * fixes dropdown filter columns * fixes dashboard & hidden setting for normal user * fixes * fixes layout * fixes avatar * fixes * Add missing else * Fix query in routable paths Co-authored-by: davidjumani <dj.davidjumani1994@gmail.com>
This commit is contained in:
parent
7439581c77
commit
d258da5524
@ -1,4 +1,7 @@
|
||||
{
|
||||
"plugins": [
|
||||
["import", { "libraryName": "ant-design-vue", "libraryDirectory": "lib"}, "ant-design-vue"]
|
||||
],
|
||||
"env": {
|
||||
"test": {
|
||||
"plugins": ["require-context-hook"]
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
// under the License.
|
||||
|
||||
module.exports = {
|
||||
preset: '@vue/cli-plugin-unit-jest',
|
||||
testURL: 'http://localhost/',
|
||||
setupFiles: ['<rootDir>/tests/setup.js'],
|
||||
moduleFileExtensions: [
|
||||
@ -41,7 +42,7 @@ module.exports = {
|
||||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
|
||||
],
|
||||
transformIgnorePatterns: [
|
||||
'<rootDir>/node_modules/(?!ant-design-vue|vue)'
|
||||
'<rootDir>/node_modules/(?!ant-design-vue|vue|@babel/runtime|lodash-es|@ant-design)'
|
||||
],
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: [
|
||||
|
||||
16330
ui/package-lock.json
generated
16330
ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -37,8 +37,8 @@
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.34",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.2",
|
||||
"@fortawesome/vue-fontawesome": "^2.0.2",
|
||||
"ant-design-vue": "~1.7.3",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.0-4",
|
||||
"ant-design-vue": "^2.2.3",
|
||||
"antd-theme-webpack-plugin": "^1.3.9",
|
||||
"axios": "^0.21.1",
|
||||
"babel-plugin-require-context-hook": "^1.0.0",
|
||||
@ -47,48 +47,52 @@
|
||||
"js-cookie": "^2.2.1",
|
||||
"lodash": "^4.17.15",
|
||||
"md5": "^2.2.1",
|
||||
"mitt": "^2.1.0",
|
||||
"moment": "^2.26.0",
|
||||
"npm-check-updates": "^6.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"viser-vue": "^2.4.8",
|
||||
"vue": "^2.6.12",
|
||||
"vue": "^3.2.11",
|
||||
"vue-clipboard2": "^0.3.1",
|
||||
"vue-cropper": "0.5.6",
|
||||
"vue-i18n": "^8.22.4",
|
||||
"vue-cropper": "^1.0.2",
|
||||
"vue-i18n": "^9.1.6",
|
||||
"vue-loader": "^16.2.0",
|
||||
"vue-ls": "^3.2.2",
|
||||
"vue-router": "^3.5.1",
|
||||
"vue-svg-component-runtime": "^1.0.1",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuex": "^3.6.2"
|
||||
"vue-router": "^4.0.0-0",
|
||||
"vue-web-storage": "^6.1.0",
|
||||
"vue3-clipboard": "^1.0.0",
|
||||
"vuedraggable": "^4.0.3",
|
||||
"vuex": "^4.0.0-0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@vue/cli": "^4.4.1",
|
||||
"@vue/cli-plugin-babel": "^4.4.1",
|
||||
"@vue/cli-plugin-eslint": "^4.4.1",
|
||||
"@vue/cli-plugin-unit-jest": "^4.4.1",
|
||||
"@vue/cli-service": "^4.4.1",
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-plugin-unit-jest": "~4.5.0",
|
||||
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
"@vue/test-utils": "^1.0.3",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-jest": "^25.1.0",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-html": "^6.0.2",
|
||||
"@vue/test-utils": "^2.0.0-0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^26.6.3",
|
||||
"babel-plugin-import": "^1.13.3",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"less": "^3.11.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-vue": "^7.0.0",
|
||||
"less": "^3.0.4",
|
||||
"less-loader": "^5.0.0",
|
||||
"node-sass": "^4.13.1",
|
||||
"node-sass": "^4.0.0",
|
||||
"sass": "^1.35.1",
|
||||
"sass-loader": "^8.0.2",
|
||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||
"vue-cli-plugin-i18n": "^1.0.1",
|
||||
"vue-svg-icon-loader": "^2.1.1",
|
||||
"vue-template-compiler": "^2.6.12",
|
||||
"webpack": "^4.43.0"
|
||||
"vue-jest": "^5.0.0-0",
|
||||
"vue-svg-loader": "^0.17.0-beta.2",
|
||||
"webpack": "^4.46.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
@ -96,7 +100,7 @@
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/strongly-recommended",
|
||||
"plugin:vue/vue3-essential",
|
||||
"@vue/standard"
|
||||
],
|
||||
"parserOptions": {
|
||||
@ -149,7 +153,18 @@
|
||||
"ignoreReadBeforeAssign": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"**/__tests__/*.{j,t}s?(x)",
|
||||
"**/tests/unit/**/*.spec.{j,t}s?(x)"
|
||||
],
|
||||
"env": {
|
||||
"jest": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
|
||||
1
ui/public/config.json
vendored
1
ui/public/config.json
vendored
@ -19,6 +19,7 @@
|
||||
"500": "assets/500.png"
|
||||
},
|
||||
"theme": {
|
||||
"@layout-mode": "light",
|
||||
"@logo-background-color": "#ffffff",
|
||||
"@navigation-background-color": "#ffffff",
|
||||
"@project-nav-background-color": "#001529",
|
||||
|
||||
@ -860,6 +860,7 @@
|
||||
"label.download.kubernetes.cluster.config": "Download Kubernetes cluster config",
|
||||
"label.download.percent": "Download Percent",
|
||||
"label.download.progress": "Download Progress",
|
||||
"label.download.setting": "Download setting",
|
||||
"label.download.state": "Download State",
|
||||
"label.dpd": "Dead Peer Detection",
|
||||
"label.drag.new.position": "Drag to new position",
|
||||
@ -1958,7 +1959,6 @@
|
||||
"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.up.policy": "SCALE UP POLICY",
|
||||
"label.scale.vm": "Scale VM",
|
||||
@ -2210,7 +2210,7 @@
|
||||
"label.templatetype": "Template Type",
|
||||
"label.tftp.dir": "TFTP Directory",
|
||||
"label.tftpdir": "Tftp root directory",
|
||||
"label.theme.alert": "Please save for the changes to take effect.",
|
||||
"label.theme.alert": "The setting is only visible to the current browser. To apply the setting, please download the JSON file and replace its content in the `theme` section of the `config.json` file under the path: `/public/config.json`",
|
||||
"label.theme.color": "Theme Color",
|
||||
"label.theme.cyan": "Cyan",
|
||||
"label.theme.dark": "Dark Style",
|
||||
|
||||
@ -36,12 +36,7 @@ export default {
|
||||
}
|
||||
},
|
||||
created () {
|
||||
const userThemeSetting = this.$store.getters.themeSetting || {}
|
||||
if (Object.keys(userThemeSetting).length === 0) {
|
||||
window.less.modifyVars(this.$config.theme)
|
||||
} else {
|
||||
window.less.modifyVars(userThemeSetting)
|
||||
}
|
||||
window.less.modifyVars(this.$config.theme)
|
||||
console.log('config and theme applied')
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,18 +39,6 @@
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg38" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
<![CDATA[
|
||||
.fil0 {fill:#424B53;fill-rule:nonzero}
|
||||
.fil2 {fill:#969C98;fill-rule:nonzero}
|
||||
.fil1 {fill:#BFD43F;fill-rule:nonzero}
|
||||
]]>
|
||||
</style>
|
||||
</defs>
|
||||
<g
|
||||
id="g4573"
|
||||
transform="translate(-686.25631,82.403259)"><polygon
|
||||
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.7 KiB |
@ -13,8 +13,6 @@
|
||||
ns2:viewOrigin="262 450"
|
||||
ns2:rulerOrigin="0 0"
|
||||
ns2:pageBounds="0 792 612 0"
|
||||
width="56"
|
||||
height="56.000069"
|
||||
viewBox="0 0 55.999999 56.000069"
|
||||
overflow="visible"
|
||||
enable-background="new 0 0 87.041 108.445"
|
||||
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@ -41,15 +41,6 @@
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
<![CDATA[
|
||||
.fil0 {fill:#424B53;fill-rule:nonzero}
|
||||
.fil2 {fill:#969C98;fill-rule:nonzero}
|
||||
.fil1 {fill:#BFD43F;fill-rule:nonzero}
|
||||
]]>
|
||||
</style>
|
||||
</defs>
|
||||
|
||||
<g
|
||||
|
||||
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.6 KiB |
@ -20,7 +20,7 @@
|
||||
<a-col>
|
||||
<a-row :md="24" :lg="layout === 'horizontal' ? 12 : 24">
|
||||
<a-checkbox
|
||||
v-decorator="[checkBoxDecorator, {}]"
|
||||
v-model:value="fields[checkBoxDecorator]"
|
||||
:checked="checked"
|
||||
@change="handleCheckChange">
|
||||
{{ checkBoxLabel }}
|
||||
@ -31,9 +31,7 @@
|
||||
:label="inputLabel"
|
||||
v-if="reversed !== checked">
|
||||
<a-input
|
||||
v-decorator="[inputDecorator, {
|
||||
initialValue: defaultInputValue
|
||||
}]"
|
||||
v-model:value="fields[inputDecorator]"
|
||||
@change="val => handleInputChangeTimed(val)" />
|
||||
</a-form-item>
|
||||
</a-row>
|
||||
@ -91,11 +89,14 @@ export default {
|
||||
return {
|
||||
checked: false,
|
||||
inputValue: '',
|
||||
inputUpdateTimer: null
|
||||
inputUpdateTimer: null,
|
||||
fields: {}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.checked = this.defaultCheckBoxValue
|
||||
this.fields[this.checkBoxDecorator] = this.checked
|
||||
this.fields[this.inputDecorator] = this.defaultInputValue
|
||||
},
|
||||
methods: {
|
||||
handleCheckChange (e) {
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<template>
|
||||
<div style="width: 100%">
|
||||
<a-row :gutter="6">
|
||||
<a-col :md="24" :lg="layout === 'horizontal' ? 12 : 24">
|
||||
<a-col :md="24" :lg="layout === 'horizontal' ? 10 : 24">
|
||||
<a-checkbox
|
||||
:checked="checked"
|
||||
@change="handleCheckChange">
|
||||
@ -27,16 +27,16 @@
|
||||
</a-col>
|
||||
<a-col :md="24" :lg="layout === 'horizontal' ? 12 : 24">
|
||||
<a-form-item
|
||||
v-if="reversed != checked"
|
||||
v-if="reversed !== checked"
|
||||
:label="selectLabel">
|
||||
<a-select
|
||||
v-model="selectedOption"
|
||||
v-model:value="selectedOption"
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
@change="val => { this.handleSelectChange(val) }">
|
||||
@change="val => { handleSelectChange(val) }">
|
||||
<a-select-option
|
||||
v-for="(opt) in selectSource"
|
||||
:key="opt.id"
|
||||
@ -138,3 +138,9 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-list-split .ant-list-item div {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -23,22 +23,36 @@
|
||||
:autoAdjustOverflow="true"
|
||||
:arrowPointAtCenter="true"
|
||||
overlayClassName="header-notice-popover">
|
||||
<template slot="content">
|
||||
<template #content>
|
||||
<a-spin :spinning="loading">
|
||||
<a-list style="min-width: 200px; max-width: 300px">
|
||||
<a-list-item>
|
||||
<a-list-item-meta :title="$t('label.notifications')">
|
||||
<a-avatar :style="{backgroundColor: '#6887d0', verticalAlign: 'middle'}" icon="notification" slot="avatar"/>
|
||||
<a-button size="small" slot="description" @click="clearJobs">{{ $t('label.clear.list') }}</a-button>
|
||||
<template #avatar>
|
||||
<a-avatar :style="{ backgroundColor: '#6887d0', verticalAlign: 'middle' }">
|
||||
<template #icon><notification-outlined /></template>
|
||||
</a-avatar>
|
||||
</template>
|
||||
<template #description><a-button size="small" @click="clearJobs">{{ $t('label.clear.list') }}</a-button></template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item v-for="(notice, index) in notices" :key="index">
|
||||
<div slot="title"> {{ notice.path }} </div>
|
||||
<template #title>{{ notice.path }} </template>
|
||||
<a-list-item-meta :title="notice.title">
|
||||
<a-avatar :style="notificationAvatar[notice.status].style" :icon="notificationAvatar[notice.status].icon" slot="avatar"/>
|
||||
<span slot="description" v-if="getResourceName(notice.description, 'name') && notice.path"><router-link :to="{ path: notice.path}"> {{ getResourceName(notice.description, "name") + ' - ' }}</router-link></span>
|
||||
<span slot="description" v-if="getResourceName(notice.description, 'name') && notice.path"> {{ getResourceName(notice.description, "msg") }}</span>
|
||||
<span slot="description" v-else> {{ notice.description }} </span>
|
||||
<template #avatar>
|
||||
<a-avatar :style="notificationAvatar[notice.status].style">
|
||||
<template #icon>
|
||||
<render-icon :icon="notificationAvatar[notice.status].icon" />
|
||||
</template>
|
||||
</a-avatar>
|
||||
</template>
|
||||
<template #description>
|
||||
<span v-if="getResourceName(notice.description, 'name') && notice.path">
|
||||
<router-link :to="{ path: notice.path}"> {{ getResourceName(notice.description, "name") + ' - ' }}</router-link>
|
||||
</span>
|
||||
<span v-if="getResourceName(notice.description, 'name') && notice.path"> {{ getResourceName(notice.description, "msg") }}</span>
|
||||
<span v-else>{{ notice.description }}</span>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
@ -46,7 +60,7 @@
|
||||
</template>
|
||||
<span @click="showNotifications" class="header-notice-opener">
|
||||
<a-badge :count="notices.length">
|
||||
<a-icon class="header-notice-icon" type="bell" />
|
||||
<bell-outlined class="header-notice-icon" />
|
||||
</a-badge>
|
||||
</span>
|
||||
</a-popover>
|
||||
@ -54,9 +68,11 @@
|
||||
|
||||
<script>
|
||||
import store from '@/store'
|
||||
import RenderIcon from '@/utils/renderIcon'
|
||||
|
||||
export default {
|
||||
name: 'HeaderNotice',
|
||||
components: { RenderIcon },
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
@ -64,9 +80,9 @@ export default {
|
||||
notices: [],
|
||||
poller: null,
|
||||
notificationAvatar: {
|
||||
done: { icon: 'check-circle', style: 'backgroundColor:#87d068' },
|
||||
progress: { icon: 'loading', style: 'backgroundColor:#ffbf00' },
|
||||
failed: { icon: 'close-circle', style: 'backgroundColor:#f56a00' }
|
||||
done: { icon: 'check-circle-outlined', style: { backgroundColor: '#87d068' } },
|
||||
progress: { icon: 'loading-outlined', style: { backgroundColor: '#ffbf00' } },
|
||||
failed: { icon: 'close-circle-outlined', style: { backgroundColor: '#f56a00' } }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -28,20 +28,22 @@
|
||||
@focus="fetchData"
|
||||
showSearch>
|
||||
|
||||
<a-tooltip placement="bottom" slot="suffixIcon">
|
||||
<template slot="title">
|
||||
<span>{{ $t('label.projects') }}</span>
|
||||
</template>
|
||||
<span style="font-size: 20px; color: #999; margin-top: -5px">
|
||||
<a-icon v-if="!loading" type="project" />
|
||||
<a-icon v-else type="loading" />
|
||||
</span>
|
||||
</a-tooltip>
|
||||
<template #suffixIcon>
|
||||
<a-tooltip placement="bottom">
|
||||
<template #title>
|
||||
<span>{{ $t('label.projects') }}</span>
|
||||
</template>
|
||||
<span class="custom-suffix-icon">
|
||||
<ProjectOutlined v-if="!loading" />
|
||||
<LoadingOutlined v-else />
|
||||
</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
|
||||
<a-select-option v-for="(project, index) in projects" :key="index" :label="project.displaytext || project.name">
|
||||
<span>
|
||||
<resource-icon v-if="project.icon && project.icon.base64image" :image="project.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||
<a-icon v-else style="margin-right: 5px" type="project" />
|
||||
<project-outlined v-else style="margin-right: 5px" />
|
||||
{{ project.displaytext || project.name }}
|
||||
</span>
|
||||
</a-select-option>
|
||||
@ -108,7 +110,7 @@ export default {
|
||||
}
|
||||
},
|
||||
filterProject (input, option) {
|
||||
return option.componentOptions.propsData.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,4 +129,12 @@ export default {
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-suffix-icon {
|
||||
font-size: 20px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 1px;
|
||||
margin-top: -3px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -23,22 +23,24 @@
|
||||
:defaultValue="currentAccount"
|
||||
:value="currentAccount"
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
@change="changeAccount"
|
||||
@focus="fetchData" >
|
||||
|
||||
<a-tooltip placement="bottom" slot="suffixIcon">
|
||||
<template slot="title">
|
||||
<span>{{ $t('label.domain') }}</span>
|
||||
</template>
|
||||
<span style="font-size: 20px; color: #999; margin-top: -5px">
|
||||
<a-icon v-if="!loading" type="block" />
|
||||
<a-icon v-else type="loading" />
|
||||
</span>
|
||||
</a-tooltip>
|
||||
<template #suffixIcon>
|
||||
<a-tooltip placement="bottom">
|
||||
<template #title>
|
||||
<span>{{ $t('label.domain') }}</span>
|
||||
</template>
|
||||
<span class="custom-suffix-icon">
|
||||
<BlockOutlined v-if="!loading" />
|
||||
<LoadingOutlined v-else />
|
||||
</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
|
||||
<a-select-option v-for="(account, index) in samlAccounts" :key="index">
|
||||
{{ `${account.accountName} (${account.domainName})` }}
|
||||
@ -126,4 +128,12 @@ export default {
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-suffix-icon {
|
||||
font-size: 20px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin-top: -8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -18,36 +18,36 @@
|
||||
<template>
|
||||
<a-dropdown>
|
||||
<span class="action ant-dropdown-link translation-menu">
|
||||
<font-awesome-icon :icon="['fas', 'language']" size="lg" />
|
||||
<TranslationOutlined />
|
||||
</span>
|
||||
<a-menu
|
||||
slot="overlay"
|
||||
:selectedKeys="[language]"
|
||||
@click="onClick">
|
||||
<a-menu-item key="en" value="enUS">English</a-menu-item>
|
||||
<a-menu-item key="hi" value="hi">हिन्दी</a-menu-item>
|
||||
<a-menu-item key="ja_JP" value="jpJP">日本語</a-menu-item>
|
||||
<a-menu-item key="ko_KR" value="koKR">한국어</a-menu-item>
|
||||
<a-menu-item key="zh_CN" value="zhCN">简体中文</a-menu-item>
|
||||
<a-menu-item key="ar" value="arEG">Arabic</a-menu-item>
|
||||
<a-menu-item key="ca" value="caES">Catalan</a-menu-item>
|
||||
<a-menu-item key="de_DE" value="deDE">Deutsch</a-menu-item>
|
||||
<a-menu-item key="es" value="esES">Español</a-menu-item>
|
||||
<a-menu-item key="fr_FR" value="frFR">Français</a-menu-item>
|
||||
<a-menu-item key="it_IT" value="itIT">Italiano</a-menu-item>
|
||||
<a-menu-item key="hu" value="huHU">Magyar</a-menu-item>
|
||||
<a-menu-item key="nl_NL" value="nlNL">Nederlands</a-menu-item>
|
||||
<a-menu-item key="nb_NO" value="nbNO">Norsk</a-menu-item>
|
||||
<a-menu-item key="pl" value="plPL">Polish</a-menu-item>
|
||||
<a-menu-item key="pt_BR" value="ptBR">Português brasileiro</a-menu-item>
|
||||
<a-menu-item key="ru_RU" value="ruRU">Русский</a-menu-item>
|
||||
<a-menu-item key="el_GR" value="elGR">Ελληνικά</a-menu-item>
|
||||
</a-menu>
|
||||
<template #overlay>
|
||||
<a-menu
|
||||
:selectedKeys="[language]"
|
||||
@click="onClick">
|
||||
<a-menu-item key="en" value="enUS">English</a-menu-item>
|
||||
<a-menu-item key="hi" value="hi">हिन्दी</a-menu-item>
|
||||
<a-menu-item key="ja_JP" value="jpJP">日本語</a-menu-item>
|
||||
<a-menu-item key="ko_KR" value="koKR">한국어</a-menu-item>
|
||||
<a-menu-item key="zh_CN" value="zhCN">简体中文</a-menu-item>
|
||||
<a-menu-item key="ar" value="arEG">Arabic</a-menu-item>
|
||||
<a-menu-item key="ca" value="caES">Catalan</a-menu-item>
|
||||
<a-menu-item key="de_DE" value="deDE">Deutsch</a-menu-item>
|
||||
<a-menu-item key="es" value="esES">Español</a-menu-item>
|
||||
<a-menu-item key="fr_FR" value="frFR">Français</a-menu-item>
|
||||
<a-menu-item key="it_IT" value="itIT">Italiano</a-menu-item>
|
||||
<a-menu-item key="hu" value="huHU">Magyar</a-menu-item>
|
||||
<a-menu-item key="nl_NL" value="nlNL">Nederlands</a-menu-item>
|
||||
<a-menu-item key="nb_NO" value="nbNO">Norsk</a-menu-item>
|
||||
<a-menu-item key="pl" value="plPL">Polish</a-menu-item>
|
||||
<a-menu-item key="pt_BR" value="ptBR">Português brasileiro</a-menu-item>
|
||||
<a-menu-item key="ru_RU" value="ruRU">Русский</a-menu-item>
|
||||
<a-menu-item key="el_GR" value="elGR">Ελληνικά</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import moment from 'moment'
|
||||
import 'moment/locale/zh-cn'
|
||||
import { loadLanguageAsync } from '@/locales'
|
||||
@ -62,7 +62,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.language = Vue.ls.get('LOCALE') || 'en'
|
||||
this.language = this.$localStorage.get('LOCALE') || 'en'
|
||||
this.setLocale(this.language)
|
||||
},
|
||||
methods: {
|
||||
@ -75,11 +75,10 @@ export default {
|
||||
this.setLocale(localeValue)
|
||||
},
|
||||
setLocale (localeValue) {
|
||||
this.$locale = localeValue
|
||||
this.$i18n.locale = localeValue
|
||||
this.language = localeValue
|
||||
moment.locale(localeValue)
|
||||
Vue.ls.set('LOCALE', localeValue)
|
||||
this.$localStorage.set('LOCALE', localeValue)
|
||||
loadLanguageAsync(localeValue)
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
<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" />
|
||||
<database-outlined />
|
||||
{{ server.name || server.apiBase || 'Local-Server' }}
|
||||
</label>
|
||||
<a-dropdown>
|
||||
@ -32,44 +32,46 @@
|
||||
<a-avatar v-else-if="userInitials" class="user-menu-avatar avatar" size="small" :style="{ backgroundColor: '#1890ff', color: 'white' }">
|
||||
{{ userInitials }}
|
||||
</a-avatar>
|
||||
<a-avatar v-else class="user-menu-avatar avatar" size="small" icon="user" :style="{ backgroundColor: '#1890ff', color: 'white' }" />
|
||||
<a-avatar v-else class="user-menu-avatar avatar" size="small" :style="{ backgroundColor: '#1890ff', color: 'white' }">
|
||||
<template #icon><user-outlined /></template>
|
||||
</a-avatar>
|
||||
<span>{{ nickname() }}</span>
|
||||
</span>
|
||||
<a-menu slot="overlay" class="user-menu-wrapper">
|
||||
<a-menu-item class="user-menu-item" key="0">
|
||||
<template #overlay>
|
||||
<a-menu class="user-menu-wrapper">
|
||||
<router-link :to="{ path: '/accountuser/' + $store.getters.userInfo.id }">
|
||||
<a-icon class="user-menu-item-icon" type="user"/>
|
||||
<span class="user-menu-item-name">{{ $t('label.profilename') }}</span>
|
||||
<a-menu-item class="user-menu-item" key="0">
|
||||
<UserOutlined class="user-menu-item-icon" />
|
||||
<span class="user-menu-item-name">{{ $t('label.profilename') }}</span>
|
||||
</a-menu-item>
|
||||
</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item class="user-menu-item" key="1">
|
||||
<a @click="toggleUseBrowserTimezone">
|
||||
<a-icon class="user-menu-item-icon" type="clock-circle"/>
|
||||
<span class="user-menu-item-name" style="margin-right: 5px">{{ $t('label.use.local.timezone') }}</span>
|
||||
<a-switch
|
||||
:checked="$store.getters.usebrowsertimezone" />
|
||||
<a-menu-item class="user-menu-item" key="1">
|
||||
<ClockCircleOutlined class="user-menu-item-icon" />
|
||||
<span class="user-menu-item-name" style="margin-right: 5px">{{ $t('label.use.local.timezone') }}</span>
|
||||
<a-switch :checked="$store.getters.usebrowsertimezone" />
|
||||
</a-menu-item>
|
||||
</a>
|
||||
</a-menu-item>
|
||||
<a-menu-item class="user-menu-item" key="2" disabled>
|
||||
<a :href="$config.docBase" target="_blank">
|
||||
<a-icon class="user-menu-item-icon" type="question-circle-o"></a-icon>
|
||||
<span class="user-menu-item-name">{{ $t('label.help') }}</span>
|
||||
<a-menu-item class="user-menu-item" key="2">
|
||||
<QuestionCircleOutlined class="user-menu-item-icon" />
|
||||
<span class="user-menu-item-name">{{ $t('label.help') }}</span>
|
||||
</a-menu-item>
|
||||
</a>
|
||||
</a-menu-item>
|
||||
<a-menu-divider/>
|
||||
<a-menu-item class="user-menu-item" key="3">
|
||||
<a-menu-divider/>
|
||||
<a href="javascript:;" @click="handleLogout">
|
||||
<a-icon class="user-menu-item-icon" type="logout"/>
|
||||
<span class="user-menu-item-name">{{ $t('label.logout') }}</span>
|
||||
<a-menu-item class="user-menu-item" key="3">
|
||||
<LogoutOutlined class="user-menu-item-icon" />
|
||||
<span class="user-menu-item-name">{{ $t('label.logout') }}</span>
|
||||
</a-menu-item>
|
||||
</a>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import { api } from '@/api'
|
||||
import HeaderNotice from './HeaderNotice'
|
||||
import TranslationMenu from './TranslationMenu'
|
||||
@ -96,7 +98,7 @@ export default {
|
||||
this.userInitials = (this.$store.getters.userInfo.firstname.toUpperCase().charAt(0) || '') +
|
||||
(this.$store.getters.userInfo.lastname.toUpperCase().charAt(0) || '')
|
||||
this.getIcon()
|
||||
eventBus.$on('refresh-header', () => {
|
||||
eventBus.on('refresh-header', () => {
|
||||
this.getIcon()
|
||||
})
|
||||
this.$store.watch(
|
||||
@ -113,7 +115,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
server () {
|
||||
return Vue.ls.get(SERVER_MANAGER) || this.$config.servers[0]
|
||||
return this.$localStorage.get(SERVER_MANAGER) || this.$config.servers[0]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
171
ui/src/components/menu/SMenu.vue
Normal file
171
ui/src/components/menu/SMenu.vue
Normal file
@ -0,0 +1,171 @@
|
||||
// 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>
|
||||
<a-menu
|
||||
:mode="mode"
|
||||
:theme="theme"
|
||||
:openKeys="openKeys"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
@click="selectMenu"
|
||||
@openChange="onOpenChange"
|
||||
>
|
||||
<template v-for="(item, index) in menuData" :key="index">
|
||||
<a-sub-menu v-if="item.children && !item.hideChildrenInMenu" :key="item.path">
|
||||
<template #title>
|
||||
<span>
|
||||
<render-icon
|
||||
v-if="item.meta.icon && typeof (item.meta.icon) === 'string'"
|
||||
:icon="item.meta.icon"
|
||||
@click="() => { handleClickParentMenu(item) }" />
|
||||
<span @click="() => { handleClickParentMenu(item) }">{{ $t(item.meta.title) }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<template v-for="children in item.children" :key="children.path">
|
||||
<a-menu-item :key="children.path" v-if="!children.hidden">
|
||||
<router-link :to="{ name: children.name, target: children.meta.target || null }">
|
||||
<render-icon
|
||||
v-if="children.meta.icon && typeof (children.meta.icon) === 'string'"
|
||||
:icon="children.meta.icon" />
|
||||
<render-icon v-else :svgIcon="children.meta.icon" />
|
||||
<span>{{ $t(children.meta.title) }}</span>
|
||||
</router-link>
|
||||
</a-menu-item>
|
||||
</template>
|
||||
</a-sub-menu>
|
||||
<a-menu-item v-else :key="item.path">
|
||||
<router-link :to="{ name: item.name, target: item.meta.target || null }">
|
||||
<render-icon
|
||||
v-if="item.meta.icon && typeof (item.meta.icon) === 'string'"
|
||||
:icon="item.meta.icon"
|
||||
@click="() => { handleClickParentMenu(item) }" />
|
||||
<span>{{ $t(item.meta.title) }}</span>
|
||||
</router-link>
|
||||
</a-menu-item>
|
||||
</template>
|
||||
</a-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RenderIcon from '@/utils/renderIcon'
|
||||
|
||||
export default {
|
||||
name: 'SMenu',
|
||||
components: { RenderIcon },
|
||||
props: {
|
||||
menu: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'dark'
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'inline'
|
||||
},
|
||||
collapsed: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
openKeys: [],
|
||||
selectedKeys: [],
|
||||
cachedOpenKeys: [],
|
||||
cachedPath: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rootSubmenuKeys: vm => {
|
||||
const keys = []
|
||||
vm.menu.forEach(item => keys.push(item.path))
|
||||
return keys
|
||||
},
|
||||
menuData () {
|
||||
return this.menu.filter(item => !item.hidden)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.updateMenu()
|
||||
},
|
||||
watch: {
|
||||
collapsed (val) {
|
||||
this.openKeys = val ? [] : this.cachedOpenKeys
|
||||
},
|
||||
'$route.fullPath': function () {
|
||||
this.updateMenu()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectMenu (obj) {
|
||||
this.selectedKeys = [obj.key]
|
||||
},
|
||||
onOpenChange (openKeys) {
|
||||
const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1)
|
||||
if (this.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
|
||||
this.openKeys = openKeys
|
||||
} else {
|
||||
this.openKeys = latestOpenKey ? [latestOpenKey] : []
|
||||
}
|
||||
},
|
||||
updateMenu () {
|
||||
const routes = this.$route.matched.concat()
|
||||
|
||||
if (routes.length >= 4 && this.$route.meta.hidden) {
|
||||
routes.pop()
|
||||
this.selectedKeys = [routes[2].path]
|
||||
} else {
|
||||
this.selectedKeys = [routes.pop().path]
|
||||
}
|
||||
|
||||
const openKeys = []
|
||||
if (this.mode === 'inline') {
|
||||
routes.forEach(item => {
|
||||
openKeys.push(item.path)
|
||||
})
|
||||
}
|
||||
|
||||
this.cachedPath = this.selectedKeys[0]
|
||||
this.cachedOpenKeys = openKeys
|
||||
if (!this.collapsed) {
|
||||
this.openKeys = openKeys
|
||||
}
|
||||
},
|
||||
handleClickParentMenu (menuItem) {
|
||||
if (this.cachedPath === menuItem.redirect) {
|
||||
return
|
||||
}
|
||||
if (menuItem.redirect) {
|
||||
this.cachedPath = menuItem.redirect
|
||||
setTimeout(() => this.$router.push({ path: menuItem.path }))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.sider .ant-menu-vertical .ant-menu-item {
|
||||
margin-right: 0;
|
||||
}
|
||||
</style>
|
||||
@ -19,12 +19,12 @@
|
||||
<a-layout-sider
|
||||
:class="['sider', isDesktop() ? null : 'shadow', theme, fixSiderbar ? 'ant-fixed-sidemenu' : null ]"
|
||||
width="256px"
|
||||
:collapsible="collapsible"
|
||||
v-model="collapsed"
|
||||
collapsible
|
||||
v-model:collapsed="isCollapsed"
|
||||
:trigger="null">
|
||||
<logo />
|
||||
<s-menu
|
||||
:collapsed="collapsed"
|
||||
:collapsed="isCollapsed"
|
||||
:menu="menus"
|
||||
:theme="theme"
|
||||
:mode="mode"
|
||||
@ -34,14 +34,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ALayoutSider from 'ant-design-vue/es/layout/Sider'
|
||||
import Logo from '../header/Logo'
|
||||
import SMenu from './index'
|
||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||
|
||||
export default {
|
||||
name: 'SideMenu',
|
||||
components: { ALayoutSider, Logo, SMenu },
|
||||
components: { Logo, SMenu },
|
||||
mixins: [mixin, mixinDevice],
|
||||
props: {
|
||||
mode: {
|
||||
@ -69,6 +68,11 @@ export default {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isCollapsed () {
|
||||
return this.collapsed
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSelect (obj) {
|
||||
this.$emit('menuSelect', obj)
|
||||
@ -84,23 +88,23 @@ export default {
|
||||
z-index: 10;
|
||||
height: auto;
|
||||
|
||||
/deep/ .ant-layout-sider-children {
|
||||
:deep(.ant-layout-sider-children) {
|
||||
overflow-y: hidden;
|
||||
&:hover {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .ant-menu-vertical .ant-menu-item {
|
||||
:deep(.ant-menu-vertical) .ant-menu-item {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
/deep/ .ant-menu-inline .ant-menu-item:not(:last-child) {
|
||||
:deep(.ant-menu-inline) .ant-menu-item:not(:last-child) {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
/deep/ .ant-menu-inline .ant-menu-item {
|
||||
:deep(.ant-menu-inline) .ant-menu-item {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
|
||||
@ -15,5 +15,5 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import SMenu from './menu'
|
||||
import SMenu from './SMenu.vue'
|
||||
export default SMenu
|
||||
|
||||
@ -1,207 +0,0 @@
|
||||
// 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.
|
||||
|
||||
import Menu from 'ant-design-vue/es/menu'
|
||||
import Icon from 'ant-design-vue/es/icon'
|
||||
|
||||
const { Item, SubMenu } = Menu
|
||||
|
||||
export default {
|
||||
name: 'SMenu',
|
||||
props: {
|
||||
menu: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'dark'
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'inline'
|
||||
},
|
||||
collapsed: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
openKeys: [],
|
||||
selectedKeys: [],
|
||||
cachedOpenKeys: [],
|
||||
cachedPath: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rootSubmenuKeys: vm => {
|
||||
const keys = []
|
||||
vm.menu.forEach(item => keys.push(item.path))
|
||||
return keys
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.updateMenu()
|
||||
},
|
||||
watch: {
|
||||
collapsed (val) {
|
||||
if (val) {
|
||||
this.cachedOpenKeys = this.openKeys.concat()
|
||||
this.openKeys = []
|
||||
} else {
|
||||
this.openKeys = this.cachedOpenKeys
|
||||
}
|
||||
},
|
||||
$route: function () {
|
||||
this.updateMenu()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// select menu item
|
||||
onOpenChange (openKeys) {
|
||||
if (this.mode === 'horizontal') {
|
||||
this.openKeys = openKeys
|
||||
return
|
||||
}
|
||||
const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key))
|
||||
if (!this.rootSubmenuKeys.includes(latestOpenKey)) {
|
||||
this.openKeys = openKeys
|
||||
} else {
|
||||
this.openKeys = latestOpenKey ? [latestOpenKey] : []
|
||||
}
|
||||
},
|
||||
updateMenu () {
|
||||
const routes = this.$route.matched.concat()
|
||||
|
||||
if (routes.length >= 4 && this.$route.meta.hidden) {
|
||||
routes.pop()
|
||||
this.selectedKeys = [routes[2].path]
|
||||
} else {
|
||||
this.selectedKeys = [routes.pop().path]
|
||||
}
|
||||
|
||||
const openKeys = []
|
||||
if (this.mode === 'inline') {
|
||||
routes.forEach(item => {
|
||||
openKeys.push(item.path)
|
||||
})
|
||||
}
|
||||
|
||||
this.cachedPath = this.selectedKeys[0]
|
||||
this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
|
||||
},
|
||||
|
||||
// render
|
||||
renderItem (menu) {
|
||||
if (!menu.hidden) {
|
||||
return menu.children && !menu.hideChildrenInMenu ? this.renderSubMenu(menu) : this.renderMenuItem(menu)
|
||||
}
|
||||
return null
|
||||
},
|
||||
renderMenuItem (menu) {
|
||||
const target = menu.meta.target || null
|
||||
const props = {
|
||||
to: { name: menu.name },
|
||||
target: target
|
||||
}
|
||||
return (
|
||||
<Item {...{ key: menu.path }}>
|
||||
<router-link {...{ props }}>
|
||||
{this.renderIcon(menu.meta.icon, menu)}
|
||||
<span>{this.$t(menu.meta.title)}</span>
|
||||
</router-link>
|
||||
</Item>
|
||||
)
|
||||
},
|
||||
renderSubMenu (menu) {
|
||||
const itemArr = []
|
||||
const on = {
|
||||
click: () => {
|
||||
this.handleClickParentMenu(menu)
|
||||
}
|
||||
}
|
||||
if (!menu.hideChildrenInMenu) {
|
||||
menu.children.forEach(item => itemArr.push(this.renderItem(item)))
|
||||
}
|
||||
return (
|
||||
<SubMenu {...{ key: menu.path }}>
|
||||
<span slot="title">
|
||||
{this.renderIcon(menu.meta.icon, menu)}
|
||||
<span {...{ on: on }}>{this.$t(menu.meta.title)}</span>
|
||||
</span>
|
||||
{itemArr}
|
||||
</SubMenu>
|
||||
)
|
||||
},
|
||||
renderIcon (icon, menuItem) {
|
||||
if (icon === 'none' || icon === undefined) {
|
||||
return null
|
||||
}
|
||||
const props = {}
|
||||
const on = {
|
||||
click: () => {
|
||||
this.handleClickParentMenu(menuItem)
|
||||
}
|
||||
}
|
||||
typeof (icon) === 'object' ? props.component = icon : props.type = icon
|
||||
return (
|
||||
<Icon {... { props, on } } />
|
||||
)
|
||||
},
|
||||
handleClickParentMenu (menuItem) {
|
||||
if (this.cachedPath === menuItem.redirect) {
|
||||
return
|
||||
}
|
||||
if (menuItem.redirect) {
|
||||
this.cachedPath = menuItem.redirect
|
||||
setTimeout(() => this.$router.push({ path: menuItem.path }))
|
||||
}
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { mode, theme, menu } = this
|
||||
const props = {
|
||||
mode: mode,
|
||||
theme: theme,
|
||||
openKeys: this.openKeys
|
||||
}
|
||||
const on = {
|
||||
select: obj => {
|
||||
this.selectedKeys = obj.selectedKeys
|
||||
this.$emit('select', obj)
|
||||
},
|
||||
openChange: this.onOpenChange
|
||||
}
|
||||
|
||||
const menuTree = menu.map(item => {
|
||||
if (item.hidden) {
|
||||
return null
|
||||
}
|
||||
return this.renderItem(item)
|
||||
})
|
||||
// {...{ props, on: on }}
|
||||
return (
|
||||
<Menu vModel={this.selectedKeys} {...{ props, on: on }}>
|
||||
{menuTree}
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -150,11 +150,11 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route: function (newVal) {
|
||||
this.activeKey = newVal.fullPath
|
||||
if (this.fullPathList.indexOf(newVal.fullPath) < 0) {
|
||||
this.fullPathList.push(newVal.fullPath)
|
||||
this.pages.push(newVal)
|
||||
'$route.fullPath': function (fullPath) {
|
||||
this.activeKey = fullPath
|
||||
if (this.fullPathList.indexOf(fullPath) < 0) {
|
||||
this.fullPathList.push(fullPath)
|
||||
this.pages.push(this.$route)
|
||||
}
|
||||
},
|
||||
activeKey: function (newPathKey) {
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
CloudStack {{ $store.getters.features.cloudstackversion }}
|
||||
<a-divider type="vertical" />
|
||||
<a href="https://github.com/apache/cloudstack/issues/new" target="_blank">
|
||||
<a-icon type="github"/>
|
||||
<github-outlined />
|
||||
{{ $t('label.report.bug') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -18,16 +18,14 @@
|
||||
<template>
|
||||
<a-layout-header v-if="!headerBarFixed" :class="[fixedHeader && 'ant-header-fixedHeader', sidebarOpened ? 'ant-header-side-opened' : 'ant-header-side-closed', theme ]" :style="{ padding: '0' }">
|
||||
<div v-if="mode === 'sidemenu'" class="header">
|
||||
<a-icon
|
||||
v-if="device==='mobile'"
|
||||
class="trigger"
|
||||
:type="collapsed ? 'menu-fold' : 'menu-unfold'"
|
||||
@click="toggle"></a-icon>
|
||||
<a-icon
|
||||
v-else
|
||||
class="trigger"
|
||||
:type="collapsed ? 'menu-unfold' : 'menu-fold'"
|
||||
@click="toggle"/>
|
||||
<template v-if="device==='mobile'">
|
||||
<menu-fold-outlined class="trigger" v-if="collapsed" @click="toggle" />
|
||||
<menu-unfold-outlined class="trigger" v-else @click="toggle" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<menu-unfold-outlined class="trigger" v-if="collapsed" @click="toggle" />
|
||||
<menu-fold-outlined class="trigger" v-else @click="toggle" />
|
||||
</template>
|
||||
<project-menu v-if="device !== 'mobile'" />
|
||||
<saml-domain-switcher style="margin-left: 20px" />
|
||||
<user-menu></user-menu>
|
||||
@ -42,11 +40,10 @@
|
||||
:menu="menus"
|
||||
:theme="theme"
|
||||
></s-menu>
|
||||
<a-icon
|
||||
v-else
|
||||
class="trigger"
|
||||
:type="collapsed ? 'menu-fold' : 'menu-unfold'"
|
||||
@click="toggle"></a-icon>
|
||||
<div v-else>
|
||||
<menu-fold-outlined class="trigger" v-if="collapsed" @click="toggle" />
|
||||
<menu-unfold-outlined class="trigger" v-else @click="toggle" />
|
||||
</div>
|
||||
</div>
|
||||
<project-menu v-if="device !== 'mobile'" />
|
||||
<saml-domain-switcher style="margin-left: 20px" />
|
||||
@ -58,7 +55,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Breadcrumb from '@/components/widgets/Breadcrumb'
|
||||
import Logo from '../header/Logo'
|
||||
import SMenu from '../menu/'
|
||||
import ProjectMenu from '../header/ProjectMenu'
|
||||
@ -70,7 +66,6 @@ import { mixin } from '@/utils/mixin.js'
|
||||
export default {
|
||||
name: 'GlobalHeader',
|
||||
components: {
|
||||
Breadcrumb,
|
||||
Logo,
|
||||
SMenu,
|
||||
ProjectMenu,
|
||||
|
||||
@ -65,16 +65,17 @@
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<template v-if="isDevelopmentMode || allowSettingTheme">
|
||||
<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>
|
||||
<drawer :visible="showSetting" placement="right" v-if="isAdmin && (isDevelopmentMode || allowSettingTheme)">
|
||||
<template #handler>
|
||||
<a-button type="primary" size="large">
|
||||
<close-outlined v-if="showSetting" />
|
||||
<setting-outlined v-else />
|
||||
</a-button>
|
||||
</template>
|
||||
<template #drawer>
|
||||
<setting :visible="showSetting" />
|
||||
</template>
|
||||
</drawer>
|
||||
|
||||
</a-affix>
|
||||
|
||||
@ -118,6 +119,7 @@ import GlobalFooter from '@/components/page/GlobalFooter'
|
||||
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||
import { mapState, mapActions } from 'vuex'
|
||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||
import { isAdmin } from '@/role'
|
||||
import Drawer from '@/components/widgets/Drawer'
|
||||
import Setting from '@/components/view/Setting.vue'
|
||||
|
||||
@ -143,6 +145,9 @@ export default {
|
||||
...mapState({
|
||||
mainMenu: state => state.permission.addRouters
|
||||
}),
|
||||
isAdmin () {
|
||||
return isAdmin()
|
||||
},
|
||||
isDevelopmentMode () {
|
||||
return process.env.NODE_ENV === 'development'
|
||||
},
|
||||
@ -190,7 +195,9 @@ export default {
|
||||
this.collapsed = !this.sidebarOpened
|
||||
},
|
||||
mounted () {
|
||||
if (this.$store.getters.darkMode) {
|
||||
const layoutMode = this.$config.theme['@layout-mode'] || 'light'
|
||||
this.$store.dispatch('SetDarkMode', (layoutMode === 'dark'))
|
||||
if (layoutMode === 'dark') {
|
||||
document.body.classList.add('dark-mode')
|
||||
}
|
||||
const userAgent = navigator.userAgent
|
||||
@ -203,7 +210,7 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
document.body.classList.remove('dark')
|
||||
},
|
||||
methods: {
|
||||
@ -218,7 +225,7 @@ export default {
|
||||
if (this.sidebarOpened) {
|
||||
left = this.isDesktop() ? '256px' : '80px'
|
||||
} else {
|
||||
left = this.isMobile() && '0' || (this.fixSidebar && '80px' || '0')
|
||||
left = this.isMobile() ? '0' : (this.fixSidebar ? '80px' : '0')
|
||||
}
|
||||
return left
|
||||
},
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
v-if="item.name"
|
||||
:to="{ path: item.path === '' ? '/' : item.path }"
|
||||
>
|
||||
<a-icon v-if="index == 0" :type="item.meta.icon" />
|
||||
<render-icon v-if="index == 0" :icon="item.meta.icon" />
|
||||
{{ item.meta.title }}
|
||||
</router-link>
|
||||
<span v-else-if="$route.params.id">{{ $route.params.id }}</span>
|
||||
@ -51,12 +51,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Breadcrumb from '@/components/widgets/Breadcrumb'
|
||||
import RenderIcon from '@/utils/renderIcon'
|
||||
|
||||
export default {
|
||||
name: 'PageHeader',
|
||||
components: {
|
||||
's-breadcrumb': Breadcrumb
|
||||
RenderIcon
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
@ -101,7 +101,7 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route () {
|
||||
'$route.fullPath' () {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,21 +19,21 @@
|
||||
<div :style="!$route.meta.pageHeader ? 'margin: -24px -24px 0px;' : null">
|
||||
<!-- pageHeader , route meta hideHeader:true on hide -->
|
||||
<page-header v-if="!$route.meta.pageHeader" :title="title" :logo="logo" :avatar="avatar">
|
||||
<slot slot="action" name="action"></slot>
|
||||
<slot slot="content" name="headerContent"></slot>
|
||||
<div slot="content" v-if="!this.$slots.headerContent && desc">
|
||||
<template #action><slot name="action"></slot></template>
|
||||
<template #content><slot name="headerContent"></slot></template>
|
||||
<template #slot:content v-if="!this.$slots.headerContent && desc">
|
||||
<p style="font-size: 14px;color: rgba(0,0,0,.65)">{{ desc }}</p>
|
||||
<div class="link">
|
||||
<template v-for="(link, index) in linkList">
|
||||
<a :key="index" :href="link.href">
|
||||
<a-icon :type="link.icon"/>
|
||||
<template v-for="(link, index) in linkList" :key="index">
|
||||
<a :href="link.href">
|
||||
<render-icon v-if="index == 0" :icon="link.icon" />
|
||||
<span>{{ link.title }}</span>
|
||||
</a>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<slot slot="extra" name="extra"></slot>
|
||||
<div slot="pageMenu">
|
||||
</template>
|
||||
<template #extra><slot name="extra"></slot></template>
|
||||
<template #pageMenu>
|
||||
<div class="page-menu-search" v-if="search">
|
||||
<a-input-search style="width: 80%; max-width: 522px;" placeholder="请输入..." size="large" enterButton="搜索" />
|
||||
</div>
|
||||
@ -43,7 +43,7 @@
|
||||
<a-tab-pane v-for="item in tabs.items" :tab="item.title" :key="item.key"></a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</page-header>
|
||||
<div class="content">
|
||||
<div :class="['page-header-index-wide']">
|
||||
@ -54,11 +54,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RenderIcon from '@/utils/renderIcon'
|
||||
|
||||
import PageHeader from './PageHeader'
|
||||
|
||||
export default {
|
||||
name: 'LayoutContent',
|
||||
components: {
|
||||
RenderIcon,
|
||||
PageHeader
|
||||
},
|
||||
// ['desc', 'logo', 'title', 'avatar', 'linkList', 'extraImage']
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
<template>
|
||||
<a-popover trigger="click" placement="bottomRight" :overlayStyle="{ width: '300px' }">
|
||||
<template slot="content">
|
||||
<template #content>
|
||||
<a-spin :spinning="loadding">
|
||||
<a-tabs>
|
||||
<a-tab-pane v-for="(tab, k) in tabs" :tab="tab.title" :key="k">
|
||||
@ -28,7 +28,7 @@
|
||||
</template>
|
||||
<span @click="fetchNotice" class="header-notice">
|
||||
<a-badge count="12">
|
||||
<a-icon style="font-size: 16px; padding: 4px" type="bell" />
|
||||
<bell-outlined style="font-size: 16px; padding: 4px" />
|
||||
</a-badge>
|
||||
</span>
|
||||
</a-popover>
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<template>
|
||||
<span class="row-action-button">
|
||||
<a-tooltip arrowPointAtCenter placement="bottomRight" v-if="resource && resource.id && dataView">
|
||||
<template slot="title">
|
||||
<template #title>
|
||||
{{ $t('label.view.console') }}
|
||||
</template>
|
||||
<console :resource="resource" :size="size" />
|
||||
@ -28,7 +28,7 @@
|
||||
:key="actionIndex"
|
||||
arrowPointAtCenter
|
||||
placement="bottomRight">
|
||||
<template slot="title">
|
||||
<template #title>
|
||||
{{ $t(action.label) }}
|
||||
</template>
|
||||
<a-badge
|
||||
@ -42,15 +42,16 @@
|
||||
)"
|
||||
:disabled="'disabled' in action ? action.disabled(resource, $store.getters) : false" >
|
||||
<a-button
|
||||
:type="action.icon === 'delete' ? 'danger' : (action.icon === 'plus' ? 'primary' : 'default')"
|
||||
:shape="!dataView && action.icon === 'plus' ? 'round' : 'circle'"
|
||||
:type="(['PlusOutlined', 'plus-outlined', 'DeleteOutlined', 'delete-outlined'].includes(action.icon) ? 'primary' : 'default')"
|
||||
:shape="!dataView && ['PlusOutlined', 'plus-outlined'].includes(action.icon) ? 'round' : 'circle'"
|
||||
:danger="['DeleteOutlined', 'delete-outlined'].includes(action.icon)"
|
||||
style="margin-left: 5px"
|
||||
:size="size"
|
||||
@click="execAction(action)">
|
||||
<span v-if="!dataView && action.icon === 'plus'">
|
||||
<span v-if="!dataView && ['PlusOutlined', 'plus-outlined'].includes(action.icon)">
|
||||
{{ $t(action.label) }}
|
||||
</span>
|
||||
<a-icon v-if="(typeof action.icon === 'string')" :type="action.icon" />
|
||||
<render-icon v-if="(typeof action.icon === 'string')" :icon="action.icon" />
|
||||
<font-awesome-icon v-else :icon="action.icon" />
|
||||
</a-button>
|
||||
</a-badge>
|
||||
@ -61,15 +62,16 @@
|
||||
(dataView && action.dataView && ('show' in action ? action.show(resource, $store.getters) : true))
|
||||
)"
|
||||
:disabled="'disabled' in action ? action.disabled(resource, $store.getters) : false"
|
||||
:type="action.icon === 'delete' ? 'danger' : (action.icon === 'plus' ? 'primary' : 'default')"
|
||||
:shape="!dataView && ['plus', 'user-add'].includes(action.icon) ? 'round' : 'circle'"
|
||||
:type="(['PlusOutlined', 'plus-outlined', 'DeleteOutlined', 'delete-outlined'].includes(action.icon) ? 'primary' : 'default')"
|
||||
:danger="['DeleteOutlined', 'delete-outlined'].includes(action.icon)"
|
||||
:shape="!dataView && ['PlusOutlined', 'plus-outlined', 'UserAddOutlined', 'user-add-outlined'].includes(action.icon) ? 'round' : 'circle'"
|
||||
style="margin-left: 5px"
|
||||
:size="size"
|
||||
@click="execAction(action)">
|
||||
<span v-if="!dataView && ['plus', 'user-add'].includes(action.icon)">
|
||||
<span v-if="!dataView && ['PlusOutlined', 'plus-outlined', 'UserAddOutlined', 'user-add-outlined'].includes(action.icon)">
|
||||
{{ $t(action.label) }}
|
||||
</span>
|
||||
<a-icon v-if="(typeof action.icon === 'string')" :type="action.icon" />
|
||||
<render-icon v-if="(typeof action.icon === 'string')" :icon="action.icon" />
|
||||
<font-awesome-icon v-else :icon="action.icon" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
@ -78,11 +80,13 @@
|
||||
|
||||
<script>
|
||||
import { api } from '@/api'
|
||||
import RenderIcon from '@/utils/renderIcon'
|
||||
import Console from '@/components/widgets/Console'
|
||||
|
||||
export default {
|
||||
name: 'ActionButton',
|
||||
components: {
|
||||
RenderIcon,
|
||||
Console
|
||||
},
|
||||
data () {
|
||||
@ -132,11 +136,14 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource (newItem, oldItem) {
|
||||
if (!newItem || !newItem.id) {
|
||||
return
|
||||
resource: {
|
||||
deep: true,
|
||||
handler (newItem, oldItem) {
|
||||
if (!newItem || !newItem.id) {
|
||||
return
|
||||
}
|
||||
this.handleShowBadge()
|
||||
}
|
||||
this.handleShowBadge()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -186,8 +193,8 @@ export default {
|
||||
|
||||
Promise.all(arrAsync).then(response => {
|
||||
for (let j = 0; j < response.length; j++) {
|
||||
this.$set(this.actionBadge, response[j].api, {})
|
||||
this.$set(this.actionBadge[response[j].api], 'badgeNum', response[j].count)
|
||||
this.actionBadge[response[j].api] = {}
|
||||
this.actionBadge[response[j].api].badgeNum = response[j].count
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
@ -201,7 +208,7 @@ export default {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/deep/.button-action-badge .ant-badge-count {
|
||||
:deep(.button-action-badge) .ant-badge-count {
|
||||
right: 10px;
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
<div class="account-center-team" v-if="annotationType && 'listAnnotations' in $store.getters.apis">
|
||||
<a-spin :spinning="loadingAnnotations">
|
||||
<div class="title">
|
||||
{{ $t('label.comments') }} ({{ this.itemCount }})
|
||||
{{ $t('label.comments') }} ({{ itemCount }})
|
||||
</div>
|
||||
<a-divider :dashed="true" />
|
||||
<a-list
|
||||
@ -29,48 +29,47 @@
|
||||
itemLayout="horizontal"
|
||||
:pagination="false"
|
||||
size="small" >
|
||||
<a-list-item slot="renderItem" slot-scope="item">
|
||||
<a-comment
|
||||
class="comment"
|
||||
:content="item.annotation"
|
||||
:datetime="$toLocaleDate(item.created)"
|
||||
:author="item.username" >
|
||||
<a-avatar
|
||||
slot="avatar"
|
||||
icon="message" />
|
||||
<a-popconfirm
|
||||
:title="$t('label.make') + ' ' + (item.adminsonly ? $t('label.annotation.everyone') : $t('label.adminsonly')) + ' ?'"
|
||||
v-if="['Admin'].includes($store.getters.userInfo.roletype)"
|
||||
slot="actions"
|
||||
key="visibility"
|
||||
@confirm="updateVisibility(item)"
|
||||
:okText="$t('label.yes')"
|
||||
:cancelText="$t('label.no')" >
|
||||
<a-icon
|
||||
type="eye"
|
||||
:style="[{
|
||||
color: item.adminsonly ? $config.theme['@primary-color'] : $config.theme['@disabled-color']
|
||||
}]" />
|
||||
<span>
|
||||
{{ item.adminsonly ? $t('label.adminsonly') : $t('label.annotation.everyone') }}
|
||||
</span>
|
||||
</a-popconfirm>
|
||||
</a-comment>
|
||||
<a-popconfirm
|
||||
:title="$t('label.remove.annotation')"
|
||||
v-if="'removeAnnotation' in $store.getters.apis && isAdminOrAnnotationOwner(item)"
|
||||
slot="actions"
|
||||
key="visibility"
|
||||
@confirm="deleteNote(item)"
|
||||
:okText="$t('label.yes')"
|
||||
:cancelText="$t('label.no')" >
|
||||
<a-icon
|
||||
type="delete"
|
||||
shape="circle"
|
||||
theme="twoTone"
|
||||
two-tone-color="#eb2f96" />
|
||||
</a-popconfirm>
|
||||
</a-list-item>
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item>
|
||||
<a-comment
|
||||
class="comment"
|
||||
:content="item.annotation"
|
||||
:datetime="$toLocaleDate(item.created)"
|
||||
:author="item.username" >
|
||||
<template #avatar>
|
||||
<a-avatar><template #icon><message-outlined /></template></a-avatar>
|
||||
</template>
|
||||
<template #actions>
|
||||
<a-popconfirm
|
||||
:title="$t('label.make') + ' ' + (item.adminsonly ? $t('label.annotation.everyone') : $t('label.adminsonly')) + ' ?'"
|
||||
v-if="['Admin'].includes($store.getters.userInfo.roletype)"
|
||||
key="visibility"
|
||||
@confirm="updateVisibility(item)"
|
||||
:okText="$t('label.yes')"
|
||||
:cancelText="$t('label.no')" >
|
||||
<eye-outlined
|
||||
:style="[{
|
||||
color: item.adminsonly ? $config.theme['@primary-color'] : $config.theme['@disabled-color']
|
||||
}]" />
|
||||
<span>
|
||||
{{ item.adminsonly ? $t('label.adminsonly') : $t('label.annotation.everyone') }}
|
||||
</span>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-comment>
|
||||
<template #actions>
|
||||
<a-popconfirm
|
||||
:title="$t('label.remove.annotation')"
|
||||
v-if="'removeAnnotation' in $store.getters.apis && isAdminOrAnnotationOwner(item)"
|
||||
key="visibility"
|
||||
@confirm="deleteNote(item)"
|
||||
:okText="$t('label.yes')"
|
||||
:cancelText="$t('label.no')" >
|
||||
<delete-two-tone shape="circle" two-tone-color="#eb2f96" />
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
<a-pagination
|
||||
class="row-element"
|
||||
@ -82,33 +81,37 @@
|
||||
:pageSizeOptions="['10']"
|
||||
@change="changePage"
|
||||
showQuickJumper>
|
||||
<template slot="buildOptionText" slot-scope="props">
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
|
||||
<a-divider :dashed="true" />
|
||||
<a-comment v-if="'addAnnotation' in $store.getters.apis">
|
||||
<a-avatar
|
||||
slot="avatar"
|
||||
icon="edit"
|
||||
@click="showNotesInput = true" />
|
||||
<div slot="content" v-ctrl-enter="saveNote">
|
||||
<a-textarea
|
||||
rows="4"
|
||||
@change="handleNoteChange"
|
||||
:value="annotation"
|
||||
:placeholder="$t('label.add.note')" />
|
||||
<a-checkbox @change="toggleNoteVisibility" v-if="['Admin'].includes(this.$store.getters.userInfo.roletype)" style="margin-top: 10px">
|
||||
{{ $t('label.adminsonly') }}
|
||||
</a-checkbox>
|
||||
<a-button
|
||||
style="margin-top: 10px; float: right"
|
||||
@click="saveNote"
|
||||
type="primary" >
|
||||
{{ $t('label.submit') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<template #avatar>
|
||||
<a-avatar @click="showNotesInput = true">
|
||||
<template #icon><edit-outlined /></template>
|
||||
</a-avatar>
|
||||
</template>
|
||||
<template #content>
|
||||
<div v-ctrl-enter="saveNote">
|
||||
<a-textarea
|
||||
rows="4"
|
||||
@change="handleNoteChange"
|
||||
v-model:value="annotation"
|
||||
:placeholder="$t('label.add.note')" />
|
||||
<a-checkbox @change="toggleNoteVisibility" v-if="['Admin'].includes($store.getters.userInfo.roletype)" style="margin-top: 10px">
|
||||
{{ $t('label.adminsonly') }}
|
||||
</a-checkbox>
|
||||
<a-button
|
||||
style="margin-top: 10px; float: right"
|
||||
@click="saveNote"
|
||||
type="primary"
|
||||
ref="submit">
|
||||
{{ $t('label.submit') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</a-comment>
|
||||
</a-spin>
|
||||
</div>
|
||||
@ -145,12 +148,14 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource: function (newItem, oldItem) {
|
||||
this.resource = newItem
|
||||
this.resourceType = this.$route.meta.resourceType
|
||||
this.annotationType = this.generateAnnotationType()
|
||||
if (this.annotationType) {
|
||||
this.getAnnotations()
|
||||
resource: {
|
||||
deep: true,
|
||||
handler () {
|
||||
this.resourceType = this.$route.meta.resourceType
|
||||
this.annotationType = this.generateAnnotationType()
|
||||
if (this.annotationType) {
|
||||
this.getAnnotations()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
<template>
|
||||
<a-modal
|
||||
v-if="showGroupActionModal"
|
||||
:visible="showGroupActionModal"
|
||||
:closable="true"
|
||||
:maskClosable="false"
|
||||
@ -26,22 +27,23 @@
|
||||
style="top: 20px;overflow-y: auto"
|
||||
centered
|
||||
>
|
||||
<span slot="title"> {{ $t(message.title) }}
|
||||
<template #title>
|
||||
{{ $t(message.title) }}
|
||||
<a
|
||||
v-if="message.docHelp || $route.meta.docHelp"
|
||||
style="margin-left: 5px"
|
||||
:href="$config.docBase + '/' + (message.docHelp || $route.meta.docHelp)"
|
||||
target="_blank">
|
||||
<a-icon type="question-circle-o"></a-icon>
|
||||
<question-circle-outlined />
|
||||
</a>
|
||||
</span>
|
||||
<template slot="footer">
|
||||
</template>
|
||||
<template #footer>
|
||||
<a-button key="back" @click="handleCancel"> {{ $t('label.close') }} </a-button>
|
||||
</template>
|
||||
<a-card :bordered="false" style="background:#f1f1f1">
|
||||
<div><a-icon type="check-circle-o" style="color: #52c41a; margin-right: 8px"/> {{ $t('label.success') + ': ' + succeededCount }}</div>
|
||||
<div><a-icon type="close-circle-o" style="color: #f5222d; margin-right: 8px"/> {{ $t('state.failed') + ': ' + failedCount }}</div>
|
||||
<div><a-icon type="sync-o" style="color: #1890ff; margin-right: 8px"/> {{ $t('state.inprogress') + ': ' + selectedItems.filter(item => item.status === 'InProgress').length || 0 }}</div>
|
||||
<div><check-circle-outlined style="color: #52c41a; margin-right: 8px"/> {{ $t('label.success') + ': ' + succeededCount }}</div>
|
||||
<div><close-circle-outlined style="color: #f5222d; margin-right: 8px"/> {{ $t('state.failed') + ': ' + failedCount }}</div>
|
||||
<div><sync-outlined style="color: #1890ff; margin-right: 8px"/> {{ $t('state.inprogress') + ': ' + selectedItems.filter(item => item.status === 'InProgress').length || 0 }}</div>
|
||||
</a-card>
|
||||
<a-divider />
|
||||
<div v-if="showGroupActionModal">
|
||||
@ -50,33 +52,33 @@
|
||||
size="middle"
|
||||
:columns="selectedColumns"
|
||||
:dataSource="tableChanged ? filteredItems : selectedItems"
|
||||
:rowKey="(record, idx) => (this.$route.path.includes('/template') || this.$route.path.includes('/iso')) ? record.zoneid: record.id"
|
||||
:rowKey="(record, idx) => ($route.path.includes('/template') || $route.path.includes('/iso')) ? record.zoneid: record.id"
|
||||
:pagination="true"
|
||||
@change="handleTableChange"
|
||||
style="overflow-y: auto">
|
||||
<div slot="status" slot-scope="text">
|
||||
<template #status="{text}">
|
||||
<status :text=" text ? text : $t('state.inprogress') " displayText></status>
|
||||
</div>
|
||||
<template slot="algorithm" slot-scope="record">
|
||||
</template>
|
||||
<template #algorithm="{record}">
|
||||
{{ returnAlgorithmName(record.algorithm) }}
|
||||
</template>
|
||||
<template slot="privateport" slot-scope="record">
|
||||
<template #privateport="{record}">
|
||||
{{ record.privateport }} - {{ record.privateendport }}
|
||||
</template>
|
||||
<template slot="publicport" slot-scope="record">
|
||||
<template #publicport="{record}">
|
||||
{{ record.publicport }} - {{ record.publicendport }}
|
||||
</template>
|
||||
<template slot="protocol" slot-scope="record">
|
||||
{{ record.protocol | capitalise }}
|
||||
<template #protocol="{record}">
|
||||
{{ capitalise(record.protocol) }}
|
||||
</template>
|
||||
<template slot="startport" slot-scope="record">
|
||||
<template #startport="{record}">
|
||||
{{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : $t('label.all') }}
|
||||
</template>
|
||||
<template slot="endport" slot-scope="record">
|
||||
<template #endport="{record}">
|
||||
{{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : $t('label.all') }}
|
||||
</template>
|
||||
<template slot="vm" slot-scope="record">
|
||||
<div><a-icon type="desktop"/> {{ record.virtualmachinename }} ({{ record.vmguestip }})</div>
|
||||
<template #vm="{record}">
|
||||
<div><desktop-outlined /> {{ record.virtualmachinename }} ({{ record.vmguestip }})</div>
|
||||
</template>
|
||||
</a-table>
|
||||
<br/>
|
||||
@ -91,12 +93,6 @@ export default {
|
||||
components: {
|
||||
Status
|
||||
},
|
||||
filters: {
|
||||
capitalise: val => {
|
||||
if (val === 'all') return 'All'
|
||||
return val.toUpperCase()
|
||||
}
|
||||
},
|
||||
props: {
|
||||
showGroupActionModal: {
|
||||
type: Boolean,
|
||||
@ -185,6 +181,10 @@ export default {
|
||||
default :
|
||||
return ''
|
||||
}
|
||||
},
|
||||
capitalise (val) {
|
||||
if (val === 'all') return 'All'
|
||||
return val.toUpperCase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,51 +31,55 @@
|
||||
:ok-button-props="{props: { type: 'default' } }"
|
||||
:cancel-button-props="{props: { type: 'primary' } }"
|
||||
centered>
|
||||
<span slot="title">
|
||||
<template #title>
|
||||
{{ $t(message.title) }}
|
||||
</span>
|
||||
</template>
|
||||
<span>
|
||||
<a-alert
|
||||
v-if="isDestructiveAction()"
|
||||
type="error">
|
||||
<a-icon slot="message" type="exclamation-circle" style="color: red; fontSize: 30px; display: inline-flex" />
|
||||
<span style="padding-left: 5px" slot="message" v-html="`<b>${selectedRowKeys.length} ` + $t('label.items.selected') + `. </b>`" />
|
||||
<span slot="message" v-html="$t(message.confirmMessage)" />
|
||||
<template #message>
|
||||
<exclamation-circle-outlined style="color: red; fontSize: 30px; display: inline-flex" />
|
||||
<span style="padding-left: 5px" v-html="`<b>${selectedRowKeys.length} ` + $t('label.items.selected') + `. </b>`" />
|
||||
<span v-html="$t(message.confirmMessage)" />
|
||||
</template>
|
||||
</a-alert>
|
||||
<a-alert v-else type="warning">
|
||||
<span v-if="selectedRowKeys.length > 0" slot="message" v-html="`<b>${selectedRowKeys.length} ` + $t('label.items.selected') + `. </b>`" />
|
||||
<span slot="message" v-html="$t(message.confirmMessage)" />
|
||||
<template #message>
|
||||
<span v-if="selectedRowKeys.length > 0" v-html="`<b>${selectedRowKeys.length} ` + $t('label.items.selected') + `. </b>`" />
|
||||
<span v-html="$t(message.confirmMessage)" />
|
||||
</template>
|
||||
</a-alert>
|
||||
<a-divider />
|
||||
<a-table
|
||||
size="middle"
|
||||
:columns="selectedColumns"
|
||||
:dataSource="selectedItems"
|
||||
:rowKey="(record, idx) => this.$route.path.includes('/iso/') ? record.zoneid : record.id"
|
||||
:rowKey="(record, idx) => $route.path.includes('/iso/') ? record.zoneid : record.id"
|
||||
:pagination="true"
|
||||
style="overflow-y: auto">
|
||||
<template slot="algorithm" slot-scope="record">
|
||||
<template #algorithm="{record}">
|
||||
{{ returnAlgorithmName(record.algorithm) }}
|
||||
</template>
|
||||
<template v-for="(column, index) in selectedColumns" :slot="column" slot-scope="text" >
|
||||
<span :key="index"> {{ text }} ==== {{ column }} </span>
|
||||
<template #column="{ text }">
|
||||
<span v-for="(column, index) in selectedColumns" :key="index"> {{ text }} ==== {{ column }}</span>
|
||||
</template>
|
||||
<template slot="privateport" slot-scope="record">
|
||||
<template #privateport="{record}">
|
||||
{{ record.privateport }} - {{ record.privateendport }}
|
||||
</template>
|
||||
<template slot="publicport" slot-scope="record">
|
||||
<template #publicport="{record}">
|
||||
{{ record.publicport }} - {{ record.publicendport }}
|
||||
</template>
|
||||
<template slot="protocol" slot-scope="record">
|
||||
{{ record.protocol | capitalise }}
|
||||
<template #protocol="{record}">
|
||||
{{ capitalise(record.protocol) }}
|
||||
</template>
|
||||
<template slot="vm" slot-scope="record">
|
||||
<div><a-icon type="desktop"/> {{ record.virtualmachinename }} ({{ record.vmguestip }})</div>
|
||||
<template #vm="{record}">
|
||||
<div><desktop-outlined /> {{ record.virtualmachinename }} ({{ record.vmguestip }})</div>
|
||||
</template>
|
||||
<template slot="startport" slot-scope="record">
|
||||
<template #startport="{record}">
|
||||
{{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : $t('label.all') }}
|
||||
</template>
|
||||
<template slot="endport" slot-scope="record">
|
||||
<template #endport="{record}">
|
||||
{{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : $t('label.all') }}
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
<strong>{{ $t('label.account') }}</strong><br/>
|
||||
<router-link :to="{ path: '/account/' + dedicatedAccountId }">{{ dedicatedAccountId }}</router-link>
|
||||
</p>
|
||||
<a-button style="margin-top: 10px; margin-bottom: 10px;" type="danger" @click="handleRelease">
|
||||
<a-button style="margin-top: 10px; margin-bottom: 10px;" type="primary" danger @click="handleRelease">
|
||||
{{ releaseButtonLabel }}
|
||||
</a-button>
|
||||
</div>
|
||||
@ -79,9 +79,12 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource (newItem, oldItem) {
|
||||
if (this.resource && this.resource.id && newItem && newItem.id !== oldItem.id) {
|
||||
this.fetchData()
|
||||
resource: {
|
||||
deep: true,
|
||||
handler (newItem, oldItem) {
|
||||
if (this.resource && this.resource.id && newItem && newItem.id !== oldItem.id) {
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -24,12 +24,13 @@
|
||||
<a-select
|
||||
style="width: 100%"
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
@change="handleChangeDomain"
|
||||
v-model="domainId">
|
||||
v-focus="true"
|
||||
v-model:value="domainId">
|
||||
<a-select-option v-for="(domain, index) in domainsList" :value="domain.id" :key="index">
|
||||
{{ domain.path || domain.name || domain.description }}
|
||||
</a-select-option>
|
||||
@ -42,9 +43,9 @@
|
||||
style="width: 100%"
|
||||
@change="handleChangeAccount"
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}" >
|
||||
<a-select-option v-for="(account, index) in accountsList" :value="account.name" :key="index">
|
||||
{{ account.name }}
|
||||
|
||||
@ -17,20 +17,21 @@
|
||||
|
||||
<template>
|
||||
<a-modal
|
||||
v-model="dedicatedDomainModal"
|
||||
v-ctrl-enter="handleDedicateForm"
|
||||
:visible="dedicatedDomainModal"
|
||||
:title="label"
|
||||
:closable="true"
|
||||
:maskClosable="false"
|
||||
:footer="null"
|
||||
@cancel="closeModal">
|
||||
<DedicateDomain
|
||||
@domainChange="id => domainId = id"
|
||||
@accountChange="id => dedicatedAccount = id"
|
||||
:error="domainError" />
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeModal">{{ this.$t('label.cancel') }}</a-button>
|
||||
<a-button type="primary" ref="submit" @click="handleDedicateForm">{{ this.$t('label.ok') }}</a-button>
|
||||
<div v-ctrl-enter="handleDedicateForm">
|
||||
<DedicateDomain
|
||||
@domainChange="id => domainId = id"
|
||||
@accountChange="id => dedicatedAccount = id"
|
||||
:error="domainError" />
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeModal">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button type="primary" ref="submit" @click="handleDedicateForm">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
@ -26,9 +26,9 @@
|
||||
<a-button
|
||||
type="dashed"
|
||||
style="width: 100%"
|
||||
icon="plus"
|
||||
:disabled="!('updateTemplate' in $store.getters.apis && 'updateVirtualMachine' in $store.getters.apis && isAdminOrOwner())"
|
||||
@click="onShowAddDetail">
|
||||
<template #icon><plus-outlined /></template>
|
||||
{{ $t('label.add.setting') }}
|
||||
</a-button>
|
||||
</div>
|
||||
@ -40,8 +40,8 @@
|
||||
class="detail-input"
|
||||
ref="keyElm"
|
||||
:filterOption="filterOption"
|
||||
:value="newKey"
|
||||
:dataSource="Object.keys(detailOptions)"
|
||||
v-model:value="newKey"
|
||||
:options="detailKeys"
|
||||
:placeholder="$t('label.name')"
|
||||
@change="e => onAddInputChange(e, 'newKey')" />
|
||||
<a-input
|
||||
@ -52,12 +52,12 @@
|
||||
<a-auto-complete
|
||||
class="detail-input"
|
||||
:filterOption="filterOption"
|
||||
:value="newValue"
|
||||
:dataSource="detailOptions[newKey]"
|
||||
v-model:value="newValue"
|
||||
:options="detailValues"
|
||||
:placeholder="$t('label.value')"
|
||||
@change="e => onAddInputChange(e, 'newValue')" />
|
||||
<tooltip-button :tooltip="$t('label.add.setting')" icon="check" @click="addDetail" buttonClass="detail-button" />
|
||||
<tooltip-button :tooltip="$t('label.cancel')" icon="close" @click="closeDetail" buttonClass="detail-button" />
|
||||
<tooltip-button :tooltip="$t('label.add.setting')" icon="check-outlined" @onClick="addDetail" buttonClass="detail-button" />
|
||||
<tooltip-button :tooltip="$t('label.cancel')" icon="close-outlined" @onClick="closeDetail" buttonClass="detail-button" />
|
||||
</a-input-group>
|
||||
<p v-if="error" style="color: red"> {{ $t(error) }} </p>
|
||||
</div>
|
||||
@ -65,48 +65,60 @@
|
||||
<a-list size="large">
|
||||
<a-list-item :key="index" v-for="(item, index) in details">
|
||||
<a-list-item-meta>
|
||||
<span slot="title">
|
||||
<template #title>
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<span slot="description" style="word-break: break-all">
|
||||
<span v-if="item.edit" style="display: flex">
|
||||
</template>
|
||||
<template #description>
|
||||
<div v-if="item.edit" style="display: flex">
|
||||
<a-auto-complete
|
||||
style="width: 100%"
|
||||
:value="item.value"
|
||||
:dataSource="detailOptions[item.name]"
|
||||
v-model:value="item.value"
|
||||
:options="detailOptions[item.name]"
|
||||
@change="val => handleInputChange(val, index)"
|
||||
@pressEnter="e => updateDetail(index)" />
|
||||
</span>
|
||||
<span v-else>{{ item.value }}</span>
|
||||
</span>
|
||||
<tooltip-button
|
||||
buttonClass="edit-button"
|
||||
:tooltip="$t('label.cancel')"
|
||||
@onClick="hideEditDetail(index)"
|
||||
v-if="item.edit"
|
||||
iconType="close-circle-two-tone"
|
||||
iconTwoToneColor="#f5222d" />
|
||||
<tooltip-button
|
||||
buttonClass="edit-button"
|
||||
:tooltip="$t('label.ok')"
|
||||
@onClick="updateDetail(index)"
|
||||
v-if="item.edit"
|
||||
iconType="check-circle-two-tone"
|
||||
iconTwoToneColor="#52c41a" />
|
||||
</div>
|
||||
<span v-else style="word-break: break-all">{{ item.value }}</span>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
<div
|
||||
slot="actions"
|
||||
v-if="!disableSettings && 'updateTemplate' in $store.getters.apis &&
|
||||
'updateVirtualMachine' in $store.getters.apis && isAdminOrOwner() && allowEditOfDetail(item.name)">
|
||||
<tooltip-button :tooltip="$t('label.cancel')" @click="hideEditDetail(index)" v-if="item.edit" iconType="close-circle" iconTwoToneColor="#f5222d" />
|
||||
<tooltip-button :tooltip="$t('label.ok')" @click="updateDetail(index)" v-if="item.edit" iconType="check-circle" iconTwoToneColor="#52c41a" />
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.edit')"
|
||||
icon="edit"
|
||||
:disabled="deployasistemplate === true"
|
||||
v-if="!item.edit"
|
||||
@click="showEditDetail(index)" />
|
||||
</div>
|
||||
<div
|
||||
slot="actions"
|
||||
v-if="!disableSettings && 'updateTemplate' in $store.getters.apis &&
|
||||
'updateVirtualMachine' in $store.getters.apis && isAdminOrOwner() && allowEditOfDetail(item.name)">
|
||||
<a-popconfirm
|
||||
:title="`${$t('label.delete.setting')}?`"
|
||||
@confirm="deleteDetail(index)"
|
||||
:okText="$t('label.yes')"
|
||||
:cancelText="$t('label.no')"
|
||||
placement="left"
|
||||
>
|
||||
<tooltip-button :tooltip="$t('label.delete')" :disabled="deployasistemplate === true" type="danger" icon="delete" />
|
||||
</a-popconfirm>
|
||||
</div>
|
||||
<template #actions>
|
||||
<div
|
||||
v-if="!disableSettings && 'updateTemplate' in $store.getters.apis &&
|
||||
'updateVirtualMachine' in $store.getters.apis && isAdminOrOwner() && allowEditOfDetail(item.name)">
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.edit')"
|
||||
icon="edit-outlined"
|
||||
:disabled="deployasistemplate === true"
|
||||
v-if="!item.edit"
|
||||
@onClick="showEditDetail(index)" />
|
||||
</div>
|
||||
<div
|
||||
v-if="!disableSettings && 'updateTemplate' in $store.getters.apis &&
|
||||
'updateVirtualMachine' in $store.getters.apis && isAdminOrOwner() && allowEditOfDetail(item.name)">
|
||||
<a-popconfirm
|
||||
:title="`${$t('label.delete.setting')}?`"
|
||||
@confirm="deleteDetail(index)"
|
||||
:okText="$t('label.yes')"
|
||||
:cancelText="$t('label.no')"
|
||||
placement="left"
|
||||
>
|
||||
<tooltip-button :tooltip="$t('label.delete')" :disabled="deployasistemplate === true" type="primary" :danger="true" icon="delete-outlined" />
|
||||
</a-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</a-spin>
|
||||
@ -140,8 +152,29 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource: function (newItem, oldItem) {
|
||||
this.updateResource(newItem)
|
||||
resource: {
|
||||
deep: true,
|
||||
handler (newItem) {
|
||||
this.updateResource(newItem)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
detailKeys () {
|
||||
return Object.keys(this.detailOptions).map(key => {
|
||||
return { value: key }
|
||||
})
|
||||
},
|
||||
detailValues () {
|
||||
if (!this.newKey) {
|
||||
return []
|
||||
}
|
||||
if (!Array.isArray(this.detailOptions[this.newKey])) {
|
||||
return { value: this.detailOptions[this.newKey] }
|
||||
}
|
||||
return this.detailOptions[this.newKey].map(value => {
|
||||
return { value: value }
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
@ -150,7 +183,7 @@ export default {
|
||||
methods: {
|
||||
filterOption (input, option) {
|
||||
return (
|
||||
option.componentOptions.children[0].text.toUpperCase().indexOf(input.toUpperCase()) >= 0
|
||||
option.value.toUpperCase().indexOf(input.toUpperCase()) >= 0
|
||||
)
|
||||
},
|
||||
updateResource (resource) {
|
||||
@ -158,18 +191,17 @@ export default {
|
||||
if (!resource) {
|
||||
return
|
||||
}
|
||||
this.resource = resource
|
||||
this.resourceType = this.$route.meta.resourceType
|
||||
if (resource.details) {
|
||||
this.details = Object.keys(this.resource.details).map(k => {
|
||||
return { name: k, value: this.resource.details[k], edit: false }
|
||||
this.details = Object.keys(resource.details).map(k => {
|
||||
return { name: k, value: resource.details[k], edit: false }
|
||||
})
|
||||
}
|
||||
api('listDetailOptions', { resourcetype: this.resourceType, resourceid: this.resource.id }).then(json => {
|
||||
api('listDetailOptions', { resourcetype: this.resourceType, resourceid: resource.id }).then(json => {
|
||||
this.detailOptions = json.listdetailoptionsresponse.detailoptions.details
|
||||
})
|
||||
this.disableSettings = (this.$route.meta.name === 'vm' && this.resource.state !== 'Stopped')
|
||||
api('listTemplates', { templatefilter: 'all', id: this.resource.templateid }).then(json => {
|
||||
this.disableSettings = (this.$route.meta.name === 'vm' && resource.state !== 'Stopped')
|
||||
api('listTemplates', { templatefilter: 'all', id: resource.templateid }).then(json => {
|
||||
this.deployasistemplate = json.listtemplatesresponse.template[0].deployasis
|
||||
})
|
||||
},
|
||||
@ -184,16 +216,13 @@ export default {
|
||||
showEditDetail (index) {
|
||||
this.details[index].edit = true
|
||||
this.details[index].originalValue = this.details[index].value
|
||||
this.$set(this.details, index, this.details[index])
|
||||
},
|
||||
hideEditDetail (index) {
|
||||
this.details[index].edit = false
|
||||
this.details[index].value = this.details[index].originalValue
|
||||
this.$set(this.details, index, this.details[index])
|
||||
},
|
||||
handleInputChange (val, index) {
|
||||
this.details[index].value = val
|
||||
this.$set(this.details, index, this.details[index])
|
||||
},
|
||||
onAddInputChange (val, obj) {
|
||||
this.error = false
|
||||
|
||||
@ -19,48 +19,50 @@
|
||||
<a-list
|
||||
size="small"
|
||||
:dataSource="fetchDetails()">
|
||||
<a-list-item slot="renderItem" slot-scope="item" v-if="item in resource">
|
||||
<div>
|
||||
<strong>{{ item === 'service' ? $t('label.supportedservices') : $t('label.' + String(item).toLowerCase()) }}</strong>
|
||||
<br/>
|
||||
<div v-if="Array.isArray(resource[item]) && item === 'service'">
|
||||
<div v-for="(service, idx) in resource[item]" :key="idx">
|
||||
{{ service.name }} : {{ service.provider[0].name }}
|
||||
<template #renderItem="{item}">
|
||||
<a-list-item v-if="item in dataResource">
|
||||
<div>
|
||||
<strong>{{ item === 'service' ? $t('label.supportedservices') : $t('label.' + String(item).toLowerCase()) }}</strong>
|
||||
<br/>
|
||||
<div v-if="Array.isArray(dataResource[item]) && item === 'service'">
|
||||
<div v-for="(service, idx) in dataResource[item]" :key="idx">
|
||||
{{ service.name }} : {{ service.provider[0].name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="$route.meta.name === 'backup' && item === 'volumes'">
|
||||
<div v-for="(volume, idx) in JSON.parse(resource[item])" :key="idx">
|
||||
<router-link :to="{ path: '/volume/' + volume.uuid }">{{ volume.type }} - {{ volume.path }}</router-link> ({{ parseFloat(volume.size / (1024.0 * 1024.0 * 1024.0)).toFixed(1) }} GB)
|
||||
<div v-else-if="$route.meta.name === 'backup' && item === 'volumes'">
|
||||
<div v-for="(volume, idx) in JSON.parse(dataResource[item])" :key="idx">
|
||||
<router-link :to="{ path: '/volume/' + volume.uuid }">{{ volume.type }} - {{ volume.path }}</router-link> ({{ parseFloat(volume.size / (1024.0 * 1024.0 * 1024.0)).toFixed(1) }} GB)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="$route.meta.name === 'computeoffering' && item === 'rootdisksize'">
|
||||
<div>
|
||||
{{ resource.rootdisksize }} GB
|
||||
<div v-else-if="$route.meta.name === 'computeoffering' && item === 'rootdisksize'">
|
||||
<div>
|
||||
{{ dataResource.rootdisksize }} GB
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="['name', 'type'].includes(item)">
|
||||
<span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(dataResource[item])">{{ $t(dataResource[item].toLowerCase()) }}</span>
|
||||
<span v-else>{{ dataResource[item] }}</span>
|
||||
</div>
|
||||
<div v-else-if="['created', 'sent', 'lastannotated'].includes(item)">
|
||||
{{ $toLocaleDate(dataResource[item]) }}
|
||||
</div>
|
||||
<div v-else-if="$route.meta.name === 'guestnetwork' && item === 'egressdefaultpolicy'">
|
||||
{{ dataResource[item]? $t('message.egress.rules.allow') : $t('message.egress.rules.deny') }}
|
||||
</div>
|
||||
<div v-else>{{ dataResource[item] }}</div>
|
||||
</div>
|
||||
<div v-else-if="['name', 'type'].includes(item)">
|
||||
<span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(resource[item])">{{ $t(resource[item].toLowerCase()) }}</span>
|
||||
<span v-else>{{ resource[item] }}</span>
|
||||
</a-list-item>
|
||||
<a-list-item v-else-if="item === 'ip6address' && ipV6Address && ipV6Address.length > 0">
|
||||
<div>
|
||||
<strong>{{ $t('label.' + String(item).toLowerCase()) }}</strong>
|
||||
<br/>
|
||||
<div>{{ ipV6Address }}</div>
|
||||
</div>
|
||||
<div v-else-if="['created', 'sent', 'lastannotated'].includes(item)">
|
||||
{{ $toLocaleDate(resource[item]) }}
|
||||
</div>
|
||||
<div v-else-if="$route.meta.name === 'guestnetwork' && item === 'egressdefaultpolicy'">
|
||||
{{ resource[item]? $t('message.egress.rules.allow') : $t('message.egress.rules.deny') }}
|
||||
</div>
|
||||
<div v-else>{{ resource[item] }}</div>
|
||||
</div>
|
||||
</a-list-item>
|
||||
<a-list-item slot="renderItem" slot-scope="item" v-else-if="item === 'ip6address' && ipV6Address && ipV6Address.length > 0">
|
||||
<div>
|
||||
<strong>{{ $t('label.' + String(item).toLowerCase()) }}</strong>
|
||||
<br/>
|
||||
<div>{{ ipV6Address }}</div>
|
||||
</div>
|
||||
</a-list-item>
|
||||
<HostInfo :resource="resource" v-if="$route.meta.name === 'host' && 'listHosts' in $store.getters.apis" />
|
||||
<DedicateData :resource="resource" v-if="dedicatedSectionActive" />
|
||||
<VmwareData :resource="resource" v-if="$route.meta.name === 'zone' && 'listVmwareDcs' in $store.getters.apis" />
|
||||
</a-list-item>
|
||||
</template>
|
||||
<HostInfo :resource="dataResource" v-if="$route.meta.name === 'host' && 'listHosts' in $store.getters.apis" />
|
||||
<DedicateData :resource="dataResource" v-if="dedicatedSectionActive" />
|
||||
<VmwareData :resource="dataResource" v-if="$route.meta.name === 'zone' && 'listVmwareDcs' in $store.getters.apis" />
|
||||
</a-list>
|
||||
</template>
|
||||
|
||||
@ -90,7 +92,8 @@ export default {
|
||||
return {
|
||||
dedicatedRoutes: ['zone', 'pod', 'cluster', 'host'],
|
||||
dedicatedSectionActive: false,
|
||||
projectname: ''
|
||||
projectname: '',
|
||||
dataResource: {}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
@ -98,22 +101,26 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
ipV6Address () {
|
||||
if (this.resource.nic && this.resource.nic.length > 0) {
|
||||
return this.resource.nic.filter(e => { return e.ip6address }).map(e => { return e.ip6address }).join(', ')
|
||||
if (this.dataResource.nic && this.dataResource.nic.length > 0) {
|
||||
return this.dataResource.nic.filter(e => { return e.ip6address }).map(e => { return e.ip6address }).join(', ')
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.dataResource = this.resource
|
||||
this.dedicatedSectionActive = this.dedicatedRoutes.includes(this.$route.meta.name)
|
||||
},
|
||||
watch: {
|
||||
resource (newItem) {
|
||||
this.resource = newItem
|
||||
if ('account' in this.resource && this.resource.account.startsWith('PrjAcct-')) {
|
||||
this.projectname = this.resource.account.substring(this.resource.account.indexOf('-') + 1, this.resource.account.lastIndexOf('-'))
|
||||
this.resource.projectname = this.projectname
|
||||
resource: {
|
||||
deep: true,
|
||||
handler () {
|
||||
this.dataResource = this.resource
|
||||
if ('account' in this.dataResource && this.dataResource.account.startsWith('PrjAcct-')) {
|
||||
this.projectname = this.dataResource.account.substring(this.dataResource.account.indexOf('-') + 1, this.dataResource.account.lastIndexOf('-'))
|
||||
this.dataResource.projectname = this.projectname
|
||||
}
|
||||
}
|
||||
},
|
||||
$route () {
|
||||
@ -123,15 +130,15 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
fetchProjectAdmins () {
|
||||
if (!this.resource.owner) {
|
||||
if (!this.dataResource.owner) {
|
||||
return false
|
||||
}
|
||||
var owners = this.resource.owner
|
||||
var owners = this.dataResource.owner
|
||||
var projectAdmins = []
|
||||
for (var owner of owners) {
|
||||
projectAdmins.push(Object.keys(owner).includes('user') ? owner.account + '(' + owner.user + ')' : owner.account)
|
||||
}
|
||||
this.resource.account = projectAdmins.join()
|
||||
this.dataResource.account = projectAdmins.join()
|
||||
},
|
||||
fetchDetails () {
|
||||
var details = this.$route.meta.details
|
||||
|
||||
@ -1,131 +0,0 @@
|
||||
// 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>
|
||||
<a-modal
|
||||
:title="$t(currentAction.label)"
|
||||
:visible="showForm"
|
||||
:closable="true"
|
||||
:confirmLoading="currentAction.loading"
|
||||
style="top: 20px;"
|
||||
@cancel="close"
|
||||
centered
|
||||
>
|
||||
<a-spin :spinning="currentAction.loading">
|
||||
<a-form
|
||||
:form="form"
|
||||
@submit="handleSubmit"
|
||||
layout="vertical" >
|
||||
<a-form-item
|
||||
v-for="(field, fieldIndex) in currentAction.params"
|
||||
:key="fieldIndex"
|
||||
:label="$t(field.name)"
|
||||
:v-bind="field.name"
|
||||
v-if="field.name !== 'id'"
|
||||
>
|
||||
<span v-if="field.type==='boolean'">
|
||||
<a-switch
|
||||
v-decorator="[field.name, {
|
||||
rules: [{ required: field.required, message: `${this.$t('message.error.required.input')}` }]
|
||||
}]"
|
||||
:placeholder="field.description"
|
||||
/>
|
||||
</span>
|
||||
<span v-else-if="field.type==='uuid' || field.name==='account'">
|
||||
<a-select
|
||||
:loading="field.loading"
|
||||
v-decorator="[field.name, {
|
||||
rules: [{ required: field.required, message: `${this.$t('message.error.select')}` }]
|
||||
}]"
|
||||
:placeholder="field.description"
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}" >
|
||||
<a-select-option v-for="(opt, optIndex) in field.opts" :key="optIndex">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</span>
|
||||
<span v-else-if="field.type==='long'">
|
||||
<a-input-number
|
||||
v-decorator="[field.name, {
|
||||
rules: [{ required: field.required, message: `${this.$t('message.validate.number')}` }]
|
||||
}]"
|
||||
:placeholder="field.description"
|
||||
/>
|
||||
</span>
|
||||
<span v-else-if="field.name==='password'">
|
||||
<a-input-password
|
||||
v-decorator="[field.name, {
|
||||
rules: [{ required: field.required, message: `${this.$t('message.error.required.input')}` }]
|
||||
}]"
|
||||
:placeholder="field.description"
|
||||
/>
|
||||
</span>
|
||||
<span v-else>
|
||||
<a-input
|
||||
v-decorator="[field.name, {
|
||||
rules: [{ required: field.required, message: `${this.$t('message.error.required.input')}` }]
|
||||
}]"
|
||||
:placeholder="field.description"
|
||||
/>
|
||||
</span>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import ChartCard from '@/components/widgets/ChartCard'
|
||||
|
||||
export default {
|
||||
name: 'FormView',
|
||||
components: {
|
||||
ChartCard
|
||||
},
|
||||
props: {
|
||||
currentAction: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
showForm: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
handleSubmit: {
|
||||
type: Function,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.currentAction.loading = false
|
||||
this.showForm = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@ -27,16 +27,16 @@
|
||||
v-clipboard:copy="name" >
|
||||
<upload-resource-icon v-if="'uploadResourceIcon' in $store.getters.apis" :visible="showUpload" :resource="resource" @handle-close="showUpload(false)"/>
|
||||
<div class="ant-upload-preview" v-if="$showIcon()">
|
||||
<a-icon type="camera" class="upload-icon"/>
|
||||
<camera-outlined class="upload-icon"/>
|
||||
</div>
|
||||
<slot name="avatar">
|
||||
<span v-if="(resource.icon && resource.icon.base64image || images.template || images.iso || resourceIcon) && !['router', 'systemvm', 'volume'].includes($route.path.split('/')[1])">
|
||||
<resource-icon :image="getImage(resource.icon && resource.icon.base64image || images.template || images.iso || resourceIcon)" size="4x" style="margin-right: 5px"/>
|
||||
</span>
|
||||
<span v-else>
|
||||
<os-logo v-if="resource.ostypeid || resource.ostypename" :osId="resource.ostypeid" :osName="resource.ostypename" size="4x" @update-osname="(name) => resource.ostypename = name"/>
|
||||
<a-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 36px" :type="$route.meta.icon"/>
|
||||
<a-icon v-else style="font-size: 36px" :component="$route.meta.icon" />
|
||||
<os-logo v-if="resource.ostypeid || resource.ostypename" :osId="resource.ostypeid" :osName="resource.ostypename" size="4x" @update-osname="setResourceOsType"/>
|
||||
<render-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 36px" :icon="$route.meta.icon" />
|
||||
<render-icon v-else style="font-size: 36px" :svgIcon="$route.meta.icon" />
|
||||
</span>
|
||||
</slot>
|
||||
</div>
|
||||
@ -82,7 +82,7 @@
|
||||
{{ resource.version }}
|
||||
</a-tag>
|
||||
<a-tooltip placement="right" >
|
||||
<template slot="title">
|
||||
<template #title>
|
||||
<span>{{ $t('label.view.console') }}</span>
|
||||
</template>
|
||||
<console style="margin-top: -5px;" :resource="resource" size="default" v-if="resource.id" />
|
||||
@ -118,12 +118,11 @@
|
||||
<tooltip-button
|
||||
tooltipPlacement="right"
|
||||
:tooltip="$t('label.copyid')"
|
||||
style="margin-left: -5px"
|
||||
icon="barcode"
|
||||
icon="barcode-outlined"
|
||||
type="dashed"
|
||||
size="small"
|
||||
@click="$message.success($t('label.copied.clipboard'))"
|
||||
v-clipboard:copy="resource.id" />
|
||||
:copyResource="resource.id"
|
||||
@onClick="$message.success($t('label.copied.clipboard'))" />
|
||||
<span style="margin-left: 10px;">{{ resource.id }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -140,7 +139,7 @@
|
||||
<div class="resource-detail-item" v-if="('cpunumber' in resource && 'cpuspeed' in resource) || resource.cputotal">
|
||||
<div class="resource-detail-item__label">{{ $t('label.cpu') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="appstore" />
|
||||
<appstore-outlined />
|
||||
<span v-if="resource.cputotal">{{ resource.cputotal }}</span>
|
||||
<span v-else>{{ resource.cpunumber }} CPU x {{ parseFloat(resource.cpuspeed / 1000.0).toFixed(2) }} Ghz</span>
|
||||
</div>
|
||||
@ -168,7 +167,7 @@
|
||||
<div class="resource-detail-item" v-if="'memory' in resource">
|
||||
<div class="resource-detail-item__label">{{ $t('label.memory') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="bulb" />{{ resource.memory + ' ' + $t('label.mb.memory') }}
|
||||
<bulb-outlined />{{ resource.memory + ' ' + $t('label.mb.memory') }}
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="resource.memorykbs && resource.memoryintfreekbs">
|
||||
@ -185,7 +184,7 @@
|
||||
<div class="resource-detail-item" v-else-if="resource.memorytotalgb">
|
||||
<div class="resource-detail-item__label">{{ $t('label.memory') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="bulb" />{{ resource.memorytotalgb + ' ' + $t('label.memory') }}
|
||||
<bulb-outlined />{{ resource.memorytotalgb + ' ' + $t('label.memory') }}
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="resource.memoryusedgb">
|
||||
@ -213,7 +212,7 @@
|
||||
|
||||
<div style="display: flex; flex-direction: column; width: 100%;">
|
||||
<div>
|
||||
<a-icon type="bulb" />{{ resource.memorytotal + ' ' + $t('label.memory') }}
|
||||
<bulb-outlined />{{ resource.memorytotal + ' ' + $t('label.memory') }}
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
@ -241,7 +240,7 @@
|
||||
<div class="resource-detail-item" v-if="resource.volumes || resource.sizegb">
|
||||
<div class="resource-detail-item__label">{{ $t('label.disksize') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="hdd" />
|
||||
<hdd-outlined />
|
||||
<span style="width: 100%;" v-if="$route.meta.name === 'vm' && resource.volumes">{{ (resource.volumes.reduce((total, item) => total += item.size, 0) / (1024 * 1024 * 1024.0)).toFixed(2) }} GB Storage</span>
|
||||
<span style="width: 100%;" v-else-if="resource.sizegb || resource.size">{{ resource.sizegb || (resource.size/1024.0) }}</span>
|
||||
</div>
|
||||
@ -255,7 +254,7 @@
|
||||
<div class="resource-detail-item" v-else-if="resource.disksizetotalgb">
|
||||
<div class="resource-detail-item__label">{{ $t('label.disksize') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="database" />{{ resource.disksizetotalgb }}
|
||||
<database-outlined />{{ resource.disksizetotalgb }}
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="resource.disksizeusedgb">
|
||||
@ -279,19 +278,18 @@
|
||||
<div class="resource-detail-item" v-if="resource.nic || ('networkkbsread' in resource && 'networkkbswrite' in resource)">
|
||||
<div class="resource-detail-item__label">{{ $t('label.network') }}</div>
|
||||
<div class="resource-detail-item__details resource-detail-item__details--start">
|
||||
<a-icon type="wifi" />
|
||||
<wifi-outlined />
|
||||
<div>
|
||||
<div v-if="'networkkbsread' in resource && 'networkkbswrite' in resource">
|
||||
<a-tag><a-icon type="arrow-down" />RX {{ toSize(resource.networkkbsread) }}</a-tag>
|
||||
<a-tag><a-icon type="arrow-up" />TX {{ toSize(resource.networkkbswrite) }}</a-tag>
|
||||
<a-tag><ArrowDownOutlined />RX {{ toSize(resource.networkkbsread) }}</a-tag>
|
||||
<a-tag><ArrowUpOutlined />TX {{ toSize(resource.networkkbswrite) }}</a-tag>
|
||||
</div>
|
||||
<div v-else>{{ resource.nic.length }} NIC(s)</div>
|
||||
<div
|
||||
v-if="resource.nic"
|
||||
v-for="(eth, index) in resource.nic"
|
||||
:key="eth.id"
|
||||
style="margin-left: -24px; margin-top: 5px;">
|
||||
<a-icon type="api" />eth{{ index }} {{ eth.ipaddress }}
|
||||
<api-outlined />eth{{ index }} {{ eth.ipaddress }}
|
||||
<router-link v-if="!isStatic && eth.networkname && eth.networkid" :to="{ path: '/guestnetwork/' + eth.networkid }">({{ eth.networkname }})</router-link>
|
||||
<a-tag v-if="eth.isdefault">
|
||||
{{ $t('label.default') }}
|
||||
@ -308,7 +306,7 @@
|
||||
v-for="network in resource.networks"
|
||||
:key="network.id"
|
||||
style="margin-top: 5px;">
|
||||
<a-icon type="api" />{{ network.name }}
|
||||
<api-outlined />{{ network.name }}
|
||||
<span v-if="resource.defaultnetworkid === network.id">
|
||||
({{ $t('label.default') }})
|
||||
</span>
|
||||
@ -319,8 +317,7 @@
|
||||
<div class="resource-detail-item" v-if="resource.ipaddress">
|
||||
<div class="resource-detail-item__label">{{ $t('label.ip') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon
|
||||
type="environment"
|
||||
<environment-outlined
|
||||
@click="$message.success(`${$t('label.copied.clipboard')} : ${ ipaddress }`)"
|
||||
v-clipboard:copy="ipaddress" />
|
||||
<router-link v-if="!isStatic && resource.ipaddressid" :to="{ path: '/publicip/' + resource.ipaddressid }">{{ ipaddress }}</router-link>
|
||||
@ -330,8 +327,7 @@
|
||||
<div class="resource-detail-item" v-if="ipV6Address && ipV6Address !== null">
|
||||
<div class="resource-detail-item__label">{{ $t('label.ip6address') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon
|
||||
type="environment"
|
||||
<environment-outlined
|
||||
@click="$message.success(`${$t('label.copied.clipboard')} : ${ ipV6Address }`)"
|
||||
v-clipboard:copy="ipV6Address" />
|
||||
{{ ipV6Address }}
|
||||
@ -343,7 +339,7 @@
|
||||
<span v-if="images.project">
|
||||
<resource-icon :image="getImage(images.project)" size="1x" style="margin-right: 5px"/>
|
||||
</span>
|
||||
<a-icon v-else type="project" />
|
||||
<project-outlined v-else />
|
||||
<router-link v-if="!isStatic && resource.projectid" :to="{ path: '/project/' + resource.projectid }">{{ resource.project || resource.projectname || resource.projectid }}</router-link>
|
||||
<router-link v-else :to="{ path: '/project', query: { name: resource.projectname }}">{{ resource.projectname }}</router-link>
|
||||
</div>
|
||||
@ -357,14 +353,14 @@
|
||||
<div class="resource-detail-item" v-if="resource.groupid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.group') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="gold" />
|
||||
<gold-outlined />
|
||||
<router-link :to="{ path: '/vmgroup/' + resource.groupid }">{{ resource.group || resource.groupid }}</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.keypairs">
|
||||
<div class="resource-detail-item" v-if="resource.keypairs && resource.keypairs.length > 0">
|
||||
<div class="resource-detail-item__label">{{ $t('label.keypairs') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="key" />
|
||||
<key-outlined />
|
||||
<li v-for="keypair in keypairs" :key="keypair">
|
||||
<router-link :to="{ path: '/ssh/' + keypair }" style="margin-right: 5px">{{ keypair }}</router-link>
|
||||
</li>
|
||||
@ -373,7 +369,7 @@
|
||||
<div class="resource-detail-item" v-if="resource.virtualmachineid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.vmname') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="desktop" />
|
||||
<desktop-outlined />
|
||||
<router-link :to="{ path: '/vm/' + resource.virtualmachineid }">{{ resource.vmname || resource.vm || resource.virtualmachinename || resource.virtualmachineid }} </router-link>
|
||||
<status class="status status--end" :text="resource.vmstate" v-if="resource.vmstate"/>
|
||||
</div>
|
||||
@ -381,28 +377,28 @@
|
||||
<div class="resource-detail-item" v-if="resource.volumeid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.volume') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="hdd" />
|
||||
<hdd-outlined />
|
||||
<router-link :to="{ path: '/volume/' + resource.volumeid }">{{ resource.volumename || resource.volume || resource.volumeid }} </router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.associatednetworkid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.associatednetwork') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="wifi" />
|
||||
<wifi-outlined />
|
||||
<router-link :to="{ path: '/guestnetwork/' + resource.associatednetworkid }">{{ resource.associatednetworkname || resource.associatednetworkid }} </router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.sourceipaddressnetworkid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.network') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="wifi" />
|
||||
<wifi-outlined />
|
||||
<router-link :to="{ path: '/guestnetwork/' + resource.sourceipaddressnetworkid }">{{ resource.sourceipaddressnetworkname || resource.sourceipaddressnetworkid }} </router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.guestnetworkid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.guestnetwork') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="gateway" />
|
||||
<gateway-outlined />
|
||||
<router-link :to="{ path: '/guestnetwork/' + resource.guestnetworkid }">{{ resource.guestnetworkname || resource.guestnetworkid }} </router-link>
|
||||
</div>
|
||||
</div>
|
||||
@ -412,7 +408,7 @@
|
||||
<span v-if="images.vpc">
|
||||
<resource-icon :image="getImage(images.vpc)" size="1x" style="margin-right: 5px"/>
|
||||
</span>
|
||||
<a-icon v-else type="deployment-unit" />
|
||||
<deployment-unit-outlined v-else />
|
||||
<router-link :to="{ path: '/vpc/' + resource.vpcid }">{{ resource.vpcname || resource.vpcid }}</router-link>
|
||||
</div>
|
||||
</div>
|
||||
@ -423,14 +419,14 @@
|
||||
<span v-if="images.acl">
|
||||
<resource-icon :image="getImage(images.acl)" size="1x" style="margin-right: 5px"/>
|
||||
</span>
|
||||
<a-icon v-else type="deployment-unit" />
|
||||
<deployment-unit-outlined v-else />
|
||||
<router-link :to="{ path: '/acllist/' + resource.aclid }">{{ resource.aclname || resource.aclid }}</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resource-detail-item" v-if="resource.affinitygroup && resource.affinitygroup.length > 0">
|
||||
<div class="resource-detail-item__label">{{ $t('label.affinitygroup') }}</div>
|
||||
<a-icon type="swap" />
|
||||
<SwapOutlined />
|
||||
<span
|
||||
v-for="(group, index) in resource.affinitygroup"
|
||||
:key="group.id"
|
||||
@ -443,7 +439,7 @@
|
||||
<div class="resource-detail-item__label">{{ resource.isoid ? $t('label.iso') : $t('label.templatename') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<resource-icon v-if="resource.icon" :image="getImage(resource.icon.base64image)" size="1x" style="margin-right: 5px"/>
|
||||
<a-icon v-else type="picture" />
|
||||
<PictureOutlined v-else />
|
||||
<div v-if="resource.isoid">
|
||||
<router-link :to="{ path: '/iso/' + resource.isoid }">{{ resource.isodisplaytext || resource.isoname || resource.isoid }} </router-link>
|
||||
</div>
|
||||
@ -455,47 +451,47 @@
|
||||
<div class="resource-detail-item" v-if="resource.serviceofferingname && resource.serviceofferingid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.serviceofferingname') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="cloud" />
|
||||
<cloud-outlined />
|
||||
<router-link v-if="!isStatic && $route.meta.name === 'router'" :to="{ path: '/computeoffering/' + resource.serviceofferingid, query: { issystem: true } }">{{ resource.serviceofferingname || resource.serviceofferingid }} </router-link>
|
||||
<router-link v-else-if="$router.resolve('/computeoffering/' + resource.serviceofferingid).route.name !== '404'" :to="{ path: '/computeoffering/' + resource.serviceofferingid }">{{ resource.serviceofferingname || resource.serviceofferingid }} </router-link>
|
||||
<router-link v-else-if="$router.resolve('/computeoffering/' + resource.serviceofferingid).name !== '404'" :to="{ path: '/computeoffering/' + resource.serviceofferingid }">{{ resource.serviceofferingname || resource.serviceofferingid }} </router-link>
|
||||
<span v-else>{{ resource.serviceofferingname || resource.serviceofferingid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.diskofferingname && resource.diskofferingid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.diskoffering') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="hdd" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/diskoffering/' + resource.diskofferingid).route.name !== '404'" :to="{ path: '/diskoffering/' + resource.diskofferingid }">{{ resource.diskofferingname || resource.diskofferingid }} </router-link>
|
||||
<hdd-outlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/diskoffering/' + resource.diskofferingid).name !== '404'" :to="{ path: '/diskoffering/' + resource.diskofferingid }">{{ resource.diskofferingname || resource.diskofferingid }} </router-link>
|
||||
<span v-else>{{ resource.diskofferingname || resource.diskofferingid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.backupofferingid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.backupofferingid') }}</div>
|
||||
<a-icon type="cloud-upload" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/backupoffering/' + resource.backupofferingid).route.name !== '404'" :to="{ path: '/backupoffering/' + resource.backupofferingid }">{{ resource.backupofferingname || resource.backupofferingid }} </router-link>
|
||||
<cloud-upload-outlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/backupoffering/' + resource.backupofferingid).name !== '404'" :to="{ path: '/backupoffering/' + resource.backupofferingid }">{{ resource.backupofferingname || resource.backupofferingid }} </router-link>
|
||||
<span v-else>{{ resource.backupofferingname || resource.backupofferingid }}</span>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.networkofferingid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.networkofferingid') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="wifi" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/networkoffering/' + resource.networkofferingid).route.name !== '404'" :to="{ path: '/networkoffering/' + resource.networkofferingid }">{{ resource.networkofferingname || resource.networkofferingid }} </router-link>
|
||||
<wifi-outlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/networkoffering/' + resource.networkofferingid).name !== '404'" :to="{ path: '/networkoffering/' + resource.networkofferingid }">{{ resource.networkofferingname || resource.networkofferingid }} </router-link>
|
||||
<span v-else>{{ resource.networkofferingname || resource.networkofferingid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.vpcofferingid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.vpcoffering') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="deployment-unit" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/vpcoffering/' + resource.vpcofferingid).route.name !== '404'" :to="{ path: '/vpcoffering/' + resource.vpcofferingid }">{{ resource.vpcofferingname || resource.vpcofferingid }} </router-link>
|
||||
<DeploymentUnitOutlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/vpcoffering/' + resource.vpcofferingid).name !== '404'" :to="{ path: '/vpcoffering/' + resource.vpcofferingid }">{{ resource.vpcofferingname || resource.vpcofferingid }} </router-link>
|
||||
<span v-else>{{ resource.vpcofferingname || resource.vpcofferingid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.storageid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.storagepool') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="database" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/storagepool/' + resource.storageid).route.name !== '404'" :to="{ path: '/storagepool/' + resource.storageid }">{{ resource.storage || resource.storageid }} </router-link>
|
||||
<database-outlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/storagepool/' + resource.storageid).name !== '404'" :to="{ path: '/storagepool/' + resource.storageid }">{{ resource.storage || resource.storageid }} </router-link>
|
||||
<span v-else>{{ resource.storage || resource.storageid }}</span>
|
||||
<a-tag style="margin-left: 5px;" v-if="resource.storagetype">
|
||||
{{ resource.storagetype }}
|
||||
@ -505,24 +501,24 @@
|
||||
<div class="resource-detail-item" v-if="resource.hostid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.hostname') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="desktop" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/host/' + resource.hostid).route.name !== '404'" :to="{ path: '/host/' + resource.hostid }">{{ resource.hostname || resource.hostid }} </router-link>
|
||||
<desktop-outlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/host/' + resource.hostid).name !== '404'" :to="{ path: '/host/' + resource.hostid }">{{ resource.hostname || resource.hostid }} </router-link>
|
||||
<span v-else>{{ resource.hostname || resource.hostid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.clusterid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.clusterid') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="cluster" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/cluster/' + resource.clusterid).route.name !== '404'" :to="{ path: '/cluster/' + resource.clusterid }">{{ resource.clustername || resource.cluster || resource.clusterid }}</router-link>
|
||||
<cluster-outlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/cluster/' + resource.clusterid).name !== '404'" :to="{ path: '/cluster/' + resource.clusterid }">{{ resource.clustername || resource.cluster || resource.clusterid }}</router-link>
|
||||
<span v-else>{{ resource.clustername || resource.cluster || resource.clusterid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.podid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.podid') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="appstore" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/pod/' + resource.podid).route.name !== '404'" :to="{ path: '/pod/' + resource.podid }">{{ resource.podname || resource.pod || resource.podid }}</router-link>
|
||||
<appstore-outlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/pod/' + resource.podid).name !== '404'" :to="{ path: '/pod/' + resource.podid }">{{ resource.podname || resource.pod || resource.podid }}</router-link>
|
||||
<span v-else>{{ resource.podname || resource.pod || resource.podid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -532,17 +528,17 @@
|
||||
<span v-if="images.zone">
|
||||
<resource-icon :image="getImage(images.zone)" size="1x" style="margin-right: 5px"/>
|
||||
</span>
|
||||
<a-icon v-else type="global" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/zone/' + resource.zoneid).route.name !== '404'" :to="{ path: '/zone/' + resource.zoneid }">{{ resource.zone || resource.zonename || resource.zoneid }}</router-link>
|
||||
<global-outlined v-else />
|
||||
<router-link v-if="!isStatic && $router.resolve('/zone/' + resource.zoneid).name !== '404'" :to="{ path: '/zone/' + resource.zoneid }">{{ resource.zone || resource.zonename || resource.zoneid }}</router-link>
|
||||
<span v-else>{{ resource.zone || resource.zonename || resource.zoneid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.owner">
|
||||
<div class="resource-detail-item__label">{{ $t('label.owners') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="user" />
|
||||
<template v-for="(item,idx) in resource.owner">
|
||||
<span style="margin-right:5px" :key="idx">
|
||||
<user-outlined />
|
||||
<template v-for="(item, idx) in resource.owner" :key="idx">
|
||||
<span style="margin-right:5px">
|
||||
<span v-if="$store.getters.userInfo.roletype !== 'User'">
|
||||
<router-link v-if="!isStatic && 'user' in item" :to="{ path: '/accountuser', query: { username: item.user, domainid: resource.domainid }}">{{ item.account + '(' + item.user + ')' }}</router-link>
|
||||
<router-link v-else :to="{ path: '/account', query: { name: item.account, domainid: resource.domainid } }">{{ item.account }}</router-link>
|
||||
@ -558,7 +554,7 @@
|
||||
<span v-if="images.account">
|
||||
<resource-icon :image="getImage(images.account)" size="1x" style="margin-right: 5px"/>
|
||||
</span>
|
||||
<a-icon v-else type="user" />
|
||||
<user-outlined v-else />
|
||||
<router-link v-if="!isStatic && $store.getters.userInfo.roletype !== 'User'" :to="{ path: '/account', query: { name: resource.account, domainid: resource.domainid } }">{{ resource.account }}</router-link>
|
||||
<span v-else>{{ resource.account }}</span>
|
||||
</div>
|
||||
@ -566,8 +562,8 @@
|
||||
<div class="resource-detail-item" v-if="resource.roleid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.role') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="idcard" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/role/' + resource.roleid).route.name !== '404'" :to="{ path: '/role/' + resource.roleid }">{{ resource.rolename || resource.role || resource.roleid }}</router-link>
|
||||
<idcard-outlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/role/' + resource.roleid).name !== '404'" :to="{ path: '/role/' + resource.roleid }">{{ resource.rolename || resource.role || resource.roleid }}</router-link>
|
||||
<span v-else>{{ resource.rolename || resource.role || resource.roleid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -575,7 +571,7 @@
|
||||
<div class="resource-detail-item__label">{{ $t('label.domain') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<resource-icon v-if="images.domain" :image="getImage(images.domain)" size="1x" style="margin-right: 5px"/>
|
||||
<a-icon v-else type="block" />
|
||||
<block-outlined v-else />
|
||||
<router-link v-if="!isStatic && $store.getters.userInfo.roletype !== 'User'" :to="{ path: '/domain/' + resource.domainid + '?tab=details' }">{{ resource.domain || resource.domainid }}</router-link>
|
||||
<span v-else>{{ resource.domain || resource.domainid }}</span>
|
||||
</div>
|
||||
@ -583,21 +579,21 @@
|
||||
<div class="resource-detail-item" v-if="resource.managementserverid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.management.servers') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="rocket" />
|
||||
<router-link v-if="!isStatic && $router.resolve('/managementserver/' + resource.managementserverid).route.name !== '404'" :to="{ path: '/managementserver/' + resource.managementserverid }">{{ resource.managementserver || resource.managementserverid }}</router-link>
|
||||
<rocket-outlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/managementserver/' + resource.managementserverid).name !== '404'" :to="{ path: '/managementserver/' + resource.managementserverid }">{{ resource.managementserver || resource.managementserverid }}</router-link>
|
||||
<span v-else>{{ resource.managementserver || resource.managementserverid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.created">
|
||||
<div class="resource-detail-item__label">{{ $t('label.created') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="calendar" />{{ $toLocaleDate(resource.created) }}
|
||||
<calendar-outlined />{{ $toLocaleDate(resource.created) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.lastupdated">
|
||||
<div class="resource-detail-item__label">{{ $t('label.last.updated') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<a-icon type="calendar" />{{ $toLocaleDate(resource.lastupdated) }}
|
||||
<calendar-outlined />{{ $toLocaleDate(resource.lastupdated) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -606,9 +602,12 @@
|
||||
<a-divider/>
|
||||
<div v-for="item in $route.meta.related" :key="item.path">
|
||||
<router-link
|
||||
v-if="$router.resolve('/' + item.name).route.name !== '404'"
|
||||
:to="{ path: '/' + item.name + '?' + item.param + '=' + (item.value ? resource[item.value] : item.param === 'account' ? resource.name + '&domainid=' + resource.domainid : item.param === 'keypair' ? resource.name : resource.id) }">
|
||||
<a-button style="margin-right: 10px" :icon="$router.resolve('/' + item.name).route.meta.icon" >
|
||||
v-if="$router.resolve('/' + item.name).name !== '404'"
|
||||
:to="{ name: item.name, query: getRouterQuery(item) }">
|
||||
<a-button style="margin-right: 10px">
|
||||
<template #icon>
|
||||
<render-icon :icon="$router.resolve('/' + item.name).meta.icon" />
|
||||
</template>
|
||||
{{ $t('label.view') + ' ' + $t(item.title) }}
|
||||
</a-button>
|
||||
</router-link>
|
||||
@ -618,34 +617,34 @@
|
||||
<div class="account-center-tags" v-if="showKeys">
|
||||
<a-divider/>
|
||||
<div class="user-keys">
|
||||
<a-icon type="key" />
|
||||
<key-outlined />
|
||||
<strong>
|
||||
{{ $t('label.apikey') }}
|
||||
<tooltip-button
|
||||
tooltipPlacement="right"
|
||||
:tooltip="$t('label.copy') + ' ' + $t('label.apikey')"
|
||||
icon="copy"
|
||||
icon="CopyOutlined"
|
||||
type="dashed"
|
||||
size="small"
|
||||
@click="$message.success($t('label.copied.clipboard'))"
|
||||
v-clipboard:copy="resource.apikey" />
|
||||
@onClick="$message.success($t('label.copied.clipboard'))"
|
||||
:copyResource="resource.apikey" />
|
||||
</strong>
|
||||
<div>
|
||||
{{ resource.apikey.substring(0, 20) }}...
|
||||
</div>
|
||||
</div> <br/>
|
||||
<div class="user-keys">
|
||||
<a-icon type="lock" />
|
||||
<lock-outlined />
|
||||
<strong>
|
||||
{{ $t('label.secretkey') }}
|
||||
<tooltip-button
|
||||
tooltipPlacement="right"
|
||||
:tooltip="$t('label.copy') + ' ' + $t('label.secretkey')"
|
||||
icon="copy"
|
||||
icon="CopyOutlined"
|
||||
type="dashed"
|
||||
size="small"
|
||||
@click="$message.success($t('label.copied.clipboard'))"
|
||||
v-clipboard:copy="resource.secretkey" />
|
||||
@onClick="$message.success($t('label.copied.clipboard'))"
|
||||
:copyResource="resource.secretkey" />
|
||||
</strong>
|
||||
<div>
|
||||
{{ resource.secretkey.substring(0, 20) }}...
|
||||
@ -658,8 +657,8 @@
|
||||
<a-spin :spinning="loadingTags">
|
||||
<div class="title">{{ $t('label.tags') }}</div>
|
||||
<div>
|
||||
<template v-for="(tag, index) in tags">
|
||||
<a-tag :key="index" :closable="isAdminOrOwner() && 'deleteTags' in $store.getters.apis" :afterClose="() => handleDeleteTag(tag)">
|
||||
<template v-for="(tag, index) in tags" :key="index">
|
||||
<a-tag :closable="isAdminOrOwner() && 'deleteTags' in $store.getters.apis" @close="() => handleDeleteTag(tag)">
|
||||
{{ tag.key }} = {{ tag.value }}
|
||||
</a-tag>
|
||||
</template>
|
||||
@ -678,8 +677,8 @@
|
||||
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" />
|
||||
<tooltip-button :tooltip="$t('label.ok')" icon="CheckOutlined" size="small" @onClick="handleInputConfirm" />
|
||||
<tooltip-button :tooltip="$t('label.cancel')" icon="CloseOutlined" size="small" @onClick="inputVisible=false" />
|
||||
</a-input-group>
|
||||
</div>
|
||||
<a-tag
|
||||
@ -687,7 +686,7 @@
|
||||
class="btn-add-tag"
|
||||
style="borderStyle: dashed;"
|
||||
v-else-if="isAdminOrOwner() && 'createTags' in $store.getters.apis">
|
||||
<a-icon type="plus" /> {{ $t('label.new.tag') }}
|
||||
<plus-outlined /> {{ $t('label.new.tag') }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</a-spin>
|
||||
@ -697,8 +696,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { api } from '@/api'
|
||||
import RenderIcon from '@/utils/renderIcon'
|
||||
import Console from '@/components/widgets/Console'
|
||||
import OsLogo from '@/components/widgets/OsLogo'
|
||||
import Status from '@/components/widgets/Status'
|
||||
@ -715,7 +714,8 @@ export default {
|
||||
Status,
|
||||
TooltipButton,
|
||||
UploadResourceIcon,
|
||||
ResourceIcon
|
||||
ResourceIcon,
|
||||
RenderIcon
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
@ -748,9 +748,7 @@ export default {
|
||||
inputValue: '',
|
||||
tags: [],
|
||||
showKeys: false,
|
||||
showNotesInput: false,
|
||||
loadingTags: false,
|
||||
loadingAnnotations: false,
|
||||
showUpload: false,
|
||||
images: {
|
||||
zone: '',
|
||||
@ -761,41 +759,46 @@ export default {
|
||||
project: '',
|
||||
vpc: '',
|
||||
network: ''
|
||||
}
|
||||
},
|
||||
newResource: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route: function () {
|
||||
'$route.fullPath': function () {
|
||||
this.getIcons()
|
||||
},
|
||||
resource: function (newItem, oldItem) {
|
||||
this.resource = newItem
|
||||
this.resourceType = this.$route.meta.resourceType
|
||||
this.showKeys = false
|
||||
this.setData()
|
||||
resource: {
|
||||
deep: true,
|
||||
handler (newData, oldData) {
|
||||
if (newData === oldData) return
|
||||
this.newResource = newData
|
||||
this.resourceType = this.$route.meta.resourceType
|
||||
this.showKeys = false
|
||||
this.setData()
|
||||
|
||||
if (this.tagsSupportingResourceTypes.includes(this.resourceType)) {
|
||||
if ('tags' in this.resource) {
|
||||
this.tags = this.resource.tags
|
||||
} else if (this.resourceType) {
|
||||
this.getTags()
|
||||
if (this.tagsSupportingResourceTypes.includes(this.resourceType)) {
|
||||
if ('tags' in this.resource) {
|
||||
this.tags = this.resource.tags
|
||||
} else if (this.resourceType) {
|
||||
this.getTags()
|
||||
}
|
||||
}
|
||||
if ('apikey' in this.resource) {
|
||||
this.getUserKeys()
|
||||
}
|
||||
this.getIcons()
|
||||
}
|
||||
if ('apikey' in this.resource) {
|
||||
this.getUserKeys()
|
||||
}
|
||||
this.getIcons()
|
||||
},
|
||||
async templateIcon () {
|
||||
this.getIcons()
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
created () {
|
||||
this.setData()
|
||||
eventBus.$on('handle-close', (showModal) => {
|
||||
eventBus.on('handle-close', (showModal) => {
|
||||
this.showUploadModal(showModal)
|
||||
})
|
||||
await this.getIcons()
|
||||
this.getIcons()
|
||||
},
|
||||
computed: {
|
||||
tagsSupportingResourceTypes () {
|
||||
@ -834,9 +837,6 @@ export default {
|
||||
return null
|
||||
}
|
||||
},
|
||||
async mounted () {
|
||||
this.getIcons()
|
||||
},
|
||||
methods: {
|
||||
showUploadModal (show) {
|
||||
if (show) {
|
||||
@ -948,7 +948,8 @@ export default {
|
||||
}
|
||||
api('getUserKeys', { id: this.resource.id }).then(json => {
|
||||
this.showKeys = true
|
||||
this.resource.secretkey = json.getuserkeysresponse.userkeys.secretkey
|
||||
this.newResource.secretkey = json.getuserkeysresponse.userkeys.secretkey
|
||||
this.$emit('change-resource', this.newResource)
|
||||
})
|
||||
},
|
||||
getTags () {
|
||||
@ -976,7 +977,7 @@ export default {
|
||||
isAdminOrOwner () {
|
||||
return ['Admin'].includes(this.$store.getters.userInfo.roletype) ||
|
||||
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account) ||
|
||||
this.resource.project && this.resource.projectid === this.$store.getters.project.id
|
||||
(this.resource.project && this.resource.projectid === this.$store.getters.project.id)
|
||||
},
|
||||
showInput () {
|
||||
this.inputVisible = true
|
||||
@ -1017,14 +1018,34 @@ export default {
|
||||
}).finally(e => {
|
||||
this.getTags()
|
||||
})
|
||||
},
|
||||
setResourceOsType (name) {
|
||||
this.newResource.ostypename = name
|
||||
this.$emit('change-resource', this.newResource)
|
||||
},
|
||||
getRouterQuery (item) {
|
||||
const query = {}
|
||||
if (item.value) {
|
||||
query[item.param] = this.resource[item.value]
|
||||
} else {
|
||||
if (item.param === 'account') {
|
||||
query[item.param] = this.resource.name
|
||||
query.domainid = this.resource.domainid
|
||||
} else if (item.param === 'keypair') {
|
||||
query[item.param] = this.resource.name
|
||||
} else {
|
||||
query[item.param] = this.resource.id
|
||||
}
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
/deep/ .ant-card-body {
|
||||
:deep(.ant-card-body) {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
@ -1125,15 +1146,6 @@ export default {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-top: -5px;
|
||||
|
||||
&--end {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.upload-icon {
|
||||
position: absolute;
|
||||
top: 70px;
|
||||
|
||||
@ -25,22 +25,22 @@
|
||||
:dataSource="nics"
|
||||
:pagination="false"
|
||||
:rowKey="record => record.InstanceID">
|
||||
<template slot="displaytext" slot-scope="record">
|
||||
<template #displaytext="{record}">
|
||||
<span>{{ record.elementName + ' - ' + record.name }}
|
||||
<a-tooltip :title="record.nicDescription" placement="top">
|
||||
<a-icon type="info-circle" class="table-tooltip-icon" />
|
||||
<info-circle-outlined class="table-tooltip-icon" />
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<div slot="size" slot-scope="record">
|
||||
<template #size="{record}">
|
||||
<span v-if="record.size">
|
||||
{{ $bytesToHumanReadableSize(record.size) }}
|
||||
</span>
|
||||
</div>
|
||||
<template slot="selectednetwork" slot-scope="record">
|
||||
</template>
|
||||
<template #selectednetwork="{record}">
|
||||
<span>{{ record.selectednetworkname || '' }}</span>
|
||||
</template>
|
||||
<template slot="select" slot-scope="record">
|
||||
<template #select="{record}">
|
||||
<div style="display: flex; justify-content: flex-end;"><a-button @click="openNicNetworkSelector(record)">{{ record.selectednetworkid ? $t('label.change') : $t('label.select') }}</a-button></div>
|
||||
</template>
|
||||
</a-table>
|
||||
@ -88,31 +88,21 @@ export default {
|
||||
nicColumns: [
|
||||
{
|
||||
title: this.$t('label.nic'),
|
||||
scopedSlots: { customRender: 'displaytext' }
|
||||
slots: { customRender: 'displaytext' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.network'),
|
||||
scopedSlots: { customRender: 'selectednetwork' }
|
||||
slots: { customRender: 'selectednetwork' }
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
scopedSlots: { customRender: 'select' }
|
||||
slots: { customRender: 'select' }
|
||||
}
|
||||
],
|
||||
selectedNicForNetworkSelection: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resetSelection () {
|
||||
var nics = this.nics
|
||||
this.nics = []
|
||||
for (var nic of nics) {
|
||||
nic.selectednetworkid = null
|
||||
nic.selectednetworkname = ''
|
||||
}
|
||||
this.nics = nics
|
||||
this.updateNicToNetworkSelection()
|
||||
},
|
||||
openNicNetworkSelector (nic) {
|
||||
this.selectedNicForNetworkSelection = nic
|
||||
},
|
||||
|
||||
@ -26,15 +26,15 @@
|
||||
:dataSource="volumes"
|
||||
:pagination="false"
|
||||
:rowKey="record => record.id">
|
||||
<div slot="size" slot-scope="record">
|
||||
<template #size="{ record }">
|
||||
<span v-if="record.size">
|
||||
{{ $bytesToHumanReadableSize(record.size) }}
|
||||
</span>
|
||||
</div>
|
||||
<template slot="selectedstorage" slot-scope="record">
|
||||
</template>
|
||||
<template #selectedstorage="{ record }">
|
||||
<span>{{ record.selectedstoragename || '' }}</span>
|
||||
</template>
|
||||
<template slot="select" slot-scope="record">
|
||||
<template #select="{ record }">
|
||||
<div style="display: flex; justify-content: flex-end;"><a-button @click="openVolumeStoragePoolSelector(record)">{{ record.selectedstorageid ? $t('label.change') : $t('label.select') }}</a-button></div>
|
||||
</template>
|
||||
</a-table>
|
||||
@ -95,15 +95,15 @@ export default {
|
||||
},
|
||||
{
|
||||
title: this.$t('label.size'),
|
||||
scopedSlots: { customRender: 'size' }
|
||||
slots: { customRender: 'size' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.storage'),
|
||||
scopedSlots: { customRender: 'selectedstorage' }
|
||||
slots: { customRender: 'selectedstorage' }
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
scopedSlots: { customRender: 'select' }
|
||||
slots: { customRender: 'select' }
|
||||
}
|
||||
],
|
||||
selectedVolumeForStoragePoolSelection: {},
|
||||
@ -112,7 +112,6 @@ export default {
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
this.apiParams = {}
|
||||
if (this.$route.meta.name === 'vm') {
|
||||
this.apiConfig = this.$store.getters.apis.migrateVirtualMachineWithVolume || {}
|
||||
|
||||
@ -21,9 +21,9 @@
|
||||
v-if="showSearch"
|
||||
style="width: 25vw;float: right;margin-bottom: 10px; z-index: 8"
|
||||
:placeholder="$t('label.search')"
|
||||
v-model="filter"
|
||||
v-model:value="filter"
|
||||
@search="handleSearch"
|
||||
autoFocus />
|
||||
v-focus="true" />
|
||||
|
||||
<a-table
|
||||
size="small"
|
||||
@ -35,17 +35,18 @@
|
||||
@change="handleTableChange"
|
||||
@handle-search-filter="handleTableChange" >
|
||||
|
||||
<template v-for="(column, index) in Object.keys(routerlinks({}))" :slot="column" slot-scope="text, item" >
|
||||
<span :key="index">
|
||||
<router-link :set="routerlink = routerlinks(item)" :to="{ path: routerlink[column] }" >{{ text }}</router-link>
|
||||
</span>
|
||||
<template
|
||||
v-for="(column, index) in Object.keys(routerlinks({}))"
|
||||
:key="index"
|
||||
#[column]="{ text, record }" >
|
||||
<router-link :set="routerlink = routerlinks(record)" :to="{ path: routerlink[column] }" >{{ text }}</router-link>
|
||||
</template>
|
||||
|
||||
<template slot="state" slot-scope="text">
|
||||
<template #state="{text}">
|
||||
<status :text="text ? text : ''" />{{ text }}
|
||||
</template>
|
||||
|
||||
<template slot="status" slot-scope="text">
|
||||
<template #status="{text}">
|
||||
<status :text="text ? text : ''" />{{ text }}
|
||||
</template>
|
||||
|
||||
@ -62,7 +63,7 @@
|
||||
@change="handleTableChange"
|
||||
@showSizeChange="handlePageSizeChange"
|
||||
showSizeChanger>
|
||||
<template slot="buildOptionText" slot-scope="props">
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
@ -127,17 +128,23 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource (newItem, oldItem) {
|
||||
if (newItem !== oldItem) {
|
||||
this.fetchData()
|
||||
resource: {
|
||||
deep: true,
|
||||
handler (newItem, oldItem) {
|
||||
if (newItem !== oldItem) {
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
},
|
||||
items (newItem, oldItem) {
|
||||
if (newItem) {
|
||||
this.dataSource = newItem
|
||||
items: {
|
||||
deep: true,
|
||||
handler (newItem) {
|
||||
if (newItem) {
|
||||
this.dataSource = newItem
|
||||
}
|
||||
}
|
||||
},
|
||||
'$i18n.locale' (to, from) {
|
||||
'$i18n.global.locale' (to, from) {
|
||||
if (to !== from) {
|
||||
this.fetchData()
|
||||
}
|
||||
@ -192,7 +199,7 @@ export default {
|
||||
columns.push({
|
||||
dataIndex: col,
|
||||
title: this.$t('label.' + col),
|
||||
scopedSlots: { customRender: col }
|
||||
slots: { customRender: col }
|
||||
})
|
||||
}
|
||||
return columns
|
||||
|
||||
@ -27,21 +27,31 @@
|
||||
:rowClassName="getRowClassName"
|
||||
style="overflow-y: auto"
|
||||
>
|
||||
<template slot="footer">
|
||||
<template #filterDropdown>
|
||||
<div style="padding: 8px" class="filter-dropdown">
|
||||
<a-menu>
|
||||
<a-menu-item v-for="(column, idx) in columnKeys" :key="idx" @click="updateSelectedColumns(column)">
|
||||
<a-checkbox :id="idx.toString()" :checked="selectedColumns.includes(getColumnKey(column))"/>
|
||||
{{ $t('label.' + String(getColumnKey(column)).toLowerCase()) }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<span v-if="hasSelected">
|
||||
{{ `Selected ${selectedRowKeys.length} items` }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<!--
|
||||
<div slot="expandedRowRender" slot-scope="resource">
|
||||
<info-card :resource="resource" style="margin-left: 0px; width: 50%">
|
||||
<div slot="actions" style="padding-top: 12px">
|
||||
<div #expandedRowRender="{ resource }">
|
||||
<info-card :resource="resource style="margin-left: 0px; width: 50%">
|
||||
<div #actions style="padding-top: 12px">
|
||||
<a-tooltip
|
||||
v-for="(action, actionIndex) in $route.meta.actions"
|
||||
:key="actionIndex"
|
||||
placement="bottom">
|
||||
<template slot="title">
|
||||
<template #title>
|
||||
{{ $t(action.label) }}
|
||||
</template>
|
||||
<a-button
|
||||
@ -60,12 +70,12 @@
|
||||
</div>
|
||||
-->
|
||||
|
||||
<span slot="name" slot-scope="text, record">
|
||||
<span v-if="['vm'].includes($route.path.split('/')[1])">
|
||||
<template #name="{text, record}">
|
||||
<span v-if="['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
||||
<span v-if="record.icon && record.icon.base64image">
|
||||
<resource-icon :image="record.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||
<resource-icon :image="record.icon.base64image" size="1x"/>
|
||||
</span>
|
||||
<os-logo v-else :osId="record.ostypeid" :osName="record.osdisplayname" size="lg" style="margin-right: 5px" />
|
||||
<os-logo v-else :osId="record.ostypeid" :osName="record.osdisplayname" size="lg" />
|
||||
</span>
|
||||
<span style="min-width: 120px" >
|
||||
<QuickView
|
||||
@ -75,22 +85,22 @@
|
||||
:enabled="quickViewEnabled() && actions.length > 0 && columns && columns[0].dataIndex === 'name' "
|
||||
@exec-action="$parent.execAction"/>
|
||||
<span v-if="$route.path.startsWith('/project')" style="margin-right: 5px">
|
||||
<tooltip-button type="dashed" size="small" icon="login" @click="changeProject(record)" />
|
||||
<tooltip-button type="dashed" size="small" icon="LoginOutlined" @onClick="changeProject(record)" />
|
||||
</span>
|
||||
<span v-if="$showIcon() && !['vm'].includes($route.path.split('/')[1])">
|
||||
<resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||
<os-logo v-else-if="record.ostypename" :osName="record.ostypename" size="1x" style="margin-right: 5px" />
|
||||
<a-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 16px; margin-right: 5px" :type="$route.meta.icon"/>
|
||||
<a-icon v-else style="font-size: 16px; margin-right: 5px" :component="$route.meta.icon" />
|
||||
<span v-if="$showIcon() && !['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
||||
<resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="1x"/>
|
||||
<os-logo v-else-if="record.ostypename" :osName="record.ostypename" size="1x" />
|
||||
<render-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 16px;" :icon="$route.meta.icon"/>
|
||||
<render-icon v-else style="font-size: 16px;" :svgIcon="$route.meta.icon" />
|
||||
</span>
|
||||
<span v-else>
|
||||
<os-logo v-if="record.ostypename" :osName="record.ostypename" size="1x" style="margin-right: 5px" />
|
||||
<span v-else :style="{ 'margin-right': record.ostypename ? '5px' : '0' }">
|
||||
<os-logo v-if="record.ostypename" :osName="record.ostypename" size="1x" />
|
||||
</span>
|
||||
|
||||
<span v-if="record.hasannotations">
|
||||
<span v-if="record.id">
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||
<router-link :to="{ path: $route.path + '/' + record.id + '?tab=comments' }"><a-icon style="padding-left: 10px" size="small" type="message" theme="filled"/></router-link>
|
||||
<router-link :to="{ path: $route.path + '/' + record.id, query: { tab: 'comments' } }"><message-filled style="padding-left: 10px" size="small"/></router-link>
|
||||
</span>
|
||||
<router-link v-else :to="{ path: $route.path + '/' + record.name }" >{{ text }}</router-link>
|
||||
</span>
|
||||
@ -104,108 +114,134 @@
|
||||
<router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ text }}</router-link>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<a slot="templatetype" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: $route.path + '/' + record.templatetype }">{{ text }}</router-link>
|
||||
</a>
|
||||
<template slot="type" slot-scope="text">
|
||||
</template>
|
||||
<template #templatetype="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link :to="{ path: $route.path + '/' + record.templatetype }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
<template #type="{ text }">
|
||||
<span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(text)">{{ $t(text.toLowerCase()) }}</span>
|
||||
<span v-else>{{ text }}</span>
|
||||
</template>
|
||||
<a slot="displayname" slot-scope="text, record" href="javascript:;">
|
||||
<QuickView
|
||||
style="margin-left: 5px"
|
||||
:actions="actions"
|
||||
:resource="record"
|
||||
:enabled="quickViewEnabled() && actions.length > 0 && columns && columns[0].dataIndex === 'displayname' "
|
||||
@exec-action="$parent.execAction"/>
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||
</a>
|
||||
<span slot="username" slot-scope="text, record" href="javascript:;">
|
||||
<span v-if="$showIcon() && !['vm'].includes($route.path.split('/')[1])">
|
||||
<resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||
<a-icon v-else style="font-size: 16px; margin-right: 5px" type="user" />
|
||||
</span>
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }" v-if="['/accountuser', '/vpnuser'].includes($route.path)">{{ text }}</router-link>
|
||||
<router-link :to="{ path: '/accountuser', query: { username: record.username, domainid: record.domainid } }" v-else-if="$store.getters.userInfo.roletype !== 'User'">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</span>
|
||||
<span slot="entityid" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: generateCommentsPath(record) }">{{ record.entityname }}</router-link>
|
||||
</span>
|
||||
<span slot="entitytype" slot-scope="text, record" href="javascript:;">
|
||||
<template #displayname="{text, record}">
|
||||
<a href="javascript:;">
|
||||
<QuickView
|
||||
style="margin-left: 5px"
|
||||
:actions="actions"
|
||||
:resource="record"
|
||||
:enabled="quickViewEnabled() && actions.length > 0 && columns && columns[0].dataIndex === 'displayname' "
|
||||
@exec-action="$parent.execAction"/>
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
<template #username="{text, record}">
|
||||
<a href="javascript:;">
|
||||
<span v-if="$showIcon() && !['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
||||
<resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="1x"/>
|
||||
<user-outlined v-else style="font-size: 16px;" />
|
||||
</span>
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }" v-if="['/accountuser', '/vpnuser'].includes($route.path)">{{ text }}</router-link>
|
||||
<router-link :to="{ path: '/accountuser', query: { username: record.username, domainid: record.domainid } }" v-else-if="$store.getters.userInfo.roletype !== 'User'">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</a>
|
||||
</template>
|
||||
<template #entityid="{ record }" href="javascript:;">
|
||||
<router-link :to="{ path: generateCommentsPath(record), query: { tab: 'comments' } }">{{ record.entityname }}</router-link>
|
||||
</template>
|
||||
<template #entitytype="{ record }" href="javascript:;">
|
||||
{{ generateHumanReadableEntityType(record) }}
|
||||
</span>
|
||||
<span slot="adminsonly" v-if="['Admin'].includes($store.getters.userInfo.roletype)" slot-scope="text, record" href="javascript:;">
|
||||
</template>
|
||||
<template #adminsonly="{ record }" v-if="['Admin'].includes($store.getters.userInfo.roletype)" href="javascript:;">
|
||||
<a-checkbox :checked="record.adminsonly" :value="record.id" v-if="record.userid === $store.getters.userInfo.id" @change="e => updateAdminsOnly(e)" />
|
||||
<a-checkbox :checked="record.adminsonly" disabled v-else />
|
||||
</span>
|
||||
<span slot="ipaddress" slot-scope="text, record" href="javascript:;">
|
||||
</template>
|
||||
<template #ipaddress="{ text, record }" href="javascript:;">
|
||||
<router-link v-if="['/publicip', '/privategw'].includes($route.path)" :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
<span v-if="record.issourcenat">
|
||||
|
||||
<a-tag>source-nat</a-tag>
|
||||
</span>
|
||||
</span>
|
||||
<span slot="ip6address" slot-scope="text, record" href="javascript:;">
|
||||
</template>
|
||||
<template #ip6address="{ text, record }" href="javascript:;">
|
||||
<span>{{ ipV6Address(text, record) }}</span>
|
||||
</span>
|
||||
<a slot="publicip" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||
</a>
|
||||
<span slot="traffictype" slot-scope="text" href="javascript:;">
|
||||
</template>
|
||||
<template #publicip="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
<template #traffictype="{ text }" href="javascript:;">
|
||||
{{ text }}
|
||||
</span>
|
||||
<a slot="vmname" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: '/vm/' + record.virtualmachineid }">{{ text }}</router-link>
|
||||
</a>
|
||||
<a slot="virtualmachinename" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: '/vm/' + record.virtualmachineid }">{{ text }}</router-link>
|
||||
</a>
|
||||
<span slot="hypervisor" slot-scope="text, record">
|
||||
</template>
|
||||
<template #vmname="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link :to="{ path: '/vm/' + record.virtualmachineid }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
<template #virtualmachinename="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link :to="{ path: '/vm/' + record.virtualmachineid }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
<template #hypervisor="{ text, record }">
|
||||
<span v-if="$route.name === 'hypervisorcapability'">
|
||||
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||
</span>
|
||||
<span v-else>{{ text }}</span>
|
||||
</span>
|
||||
<template slot="state" slot-scope="text, record">
|
||||
</template>
|
||||
<template #state="{ text, record }">
|
||||
<status v-if="$route.path.startsWith('/host')" :text="getHostState(record)" displayText />
|
||||
<status v-else :text="text ? text : ''" displayText style="min-width: 80px" />
|
||||
<status v-else :text="text ? text : ''" displayText :styles="{ 'min-width': '80px' }" />
|
||||
</template>
|
||||
<template slot="allocationstate" slot-scope="text">
|
||||
<template #allocationstate="{ text }">
|
||||
<status :text="text ? text : ''" displayText />
|
||||
</template>
|
||||
<template slot="resourcestate" slot-scope="text">
|
||||
<template #resourcestate="{ text }">
|
||||
<status :text="text ? text : ''" displayText />
|
||||
</template>
|
||||
<template slot="powerstate" slot-scope="text">
|
||||
<template #powerstate="{ text }">
|
||||
<status :text="text ? text : ''" displayText />
|
||||
</template>
|
||||
<template slot="agentstate" slot-scope="text">
|
||||
<template #agentstate="{ text }">
|
||||
<status :text="text ? text : ''" displayText />
|
||||
</template>
|
||||
<a slot="guestnetworkname" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: '/guestnetwork/' + record.guestnetworkid }">{{ text }}</router-link>
|
||||
</a>
|
||||
<a slot="associatednetworkname" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: '/guestnetwork/' + record.associatednetworkid }">{{ text }}</router-link>
|
||||
</a>
|
||||
<a slot="vpcname" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: '/vpc/' + record.vpcid }">{{ text }}</router-link>
|
||||
</a>
|
||||
<a slot="hostname" slot-scope="text, record" href="javascript:;">
|
||||
<router-link v-if="record.hostid" :to="{ path: '/host/' + record.hostid }">{{ text }}</router-link>
|
||||
<router-link v-else-if="record.hostname" :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</a>
|
||||
<a slot="storage" slot-scope="text, record" href="javascript:;">
|
||||
<router-link v-if="record.storageid" :to="{ path: '/storagepool/' + record.storageid }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</a>
|
||||
<template #guestnetworkname="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link :to="{ path: '/guestnetwork/' + record.guestnetworkid }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
<template #associatednetworkname="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link :to="{ path: '/guestnetwork/' + record.associatednetworkid }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
<template #vpcname="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link :to="{ path: '/vpc/' + record.vpcid }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
<template #hostname="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link v-if="record.hostid" :to="{ path: '/host/' + record.hostid }">{{ text }}</router-link>
|
||||
<router-link v-else-if="record.hostname" :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</a>
|
||||
</template>
|
||||
<template #storage="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link v-if="record.storageid" :to="{ path: '/storagepool/' + record.storageid }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<template v-for="(value, name) in thresholdMapping" :slot="name" slot-scope="text, record" href="javascript:;">
|
||||
<span :key="name">
|
||||
<template
|
||||
v-for="(value, name) in thresholdMapping"
|
||||
:key="name"
|
||||
#[name]="{ text, record }"
|
||||
href="javascript:;">
|
||||
<span>
|
||||
<span v-if="record[value.disable]" class="alert-disable-threshold">
|
||||
{{ text }}
|
||||
</span>
|
||||
@ -218,20 +254,26 @@
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<a slot="level" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: '/event/' + record.id }">{{ text }}</router-link>
|
||||
</a>
|
||||
<template #level="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link :to="{ path: '/event/' + record.id }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<a slot="clustername" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: '/cluster/' + record.clusterid }">{{ text }}</router-link>
|
||||
</a>
|
||||
<a slot="podname" slot-scope="text, record" href="javascript:;">
|
||||
<router-link :to="{ path: '/pod/' + record.podid }">{{ text }}</router-link>
|
||||
</a>
|
||||
<span slot="account" slot-scope="text, record">
|
||||
<template #clustername="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link :to="{ path: '/cluster/' + record.clusterid }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
<template #podname="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link :to="{ path: '/pod/' + record.podid }">{{ text }}</router-link>
|
||||
</a>
|
||||
</template>
|
||||
<template #account="{ text, record }">
|
||||
<template v-if="record.owner">
|
||||
<template v-for="(item,idx) in record.owner">
|
||||
<span style="margin-right:5px" :key="idx">
|
||||
<template v-for="(item, idx) in record.owner" :key="idx">
|
||||
<span style="margin-right:5px">
|
||||
<span v-if="$store.getters.userInfo.roletype !== 'User'">
|
||||
<router-link v-if="'user' in item" :to="{ path: '/accountuser', query: { username: item.user, domainid: record.domainid }}">{{ item.account + '(' + item.user + ')' }}</router-link>
|
||||
<router-link v-else :to="{ path: '/account', query: { name: item.account, domainid: record.domainid, dataView: true } }">{{ item.account }}</router-link>
|
||||
@ -248,87 +290,91 @@
|
||||
<router-link :to="{ path: '/account', query: { name: record.account, domainid: record.domainid, dataView: true } }" v-else-if="$store.getters.userInfo.roletype !== 'User'">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</template>
|
||||
</span>
|
||||
<span slot="domain" slot-scope="text, record" href="javascript:;">
|
||||
<router-link v-if="record.domainid && !record.domainid.toString().includes(',') && $store.getters.userInfo.roletype !== 'User'" :to="{ path: '/domain/' + record.domainid + '?tab=details' }">{{ text }}</router-link>
|
||||
</template>
|
||||
<template #domain="{ text, record }">
|
||||
<router-link v-if="record.domainid && !record.domainid.toString().includes(',') && $store.getters.userInfo.roletype !== 'User'" :to="{ path: '/domain/' + record.domainid, query: { tab: 'details' } }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</span>
|
||||
<span slot="domainpath" slot-scope="text, record" href="javascript:;">
|
||||
<router-link v-if="record.domainid && !record.domainid.includes(',') && $router.resolve('/domain/' + record.domainid).route.name !== '404'" :to="{ path: '/domain/' + record.domainid + '?tab=details' }">{{ text }}</router-link>
|
||||
</template>
|
||||
<template #domainpath="{ text, record }">
|
||||
<router-link v-if="record.domainid && !record.domainid.includes(',') && $router.resolve('/domain/' + record.domainid).name !== '404'" :to="{ path: '/domain/' + record.domainid, query: { tab: 'details' } }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</span>
|
||||
<a slot="zone" slot-scope="text, record" href="javascript:;">
|
||||
<router-link v-if="record.zoneid && !record.zoneid.includes(',') && $router.resolve('/zone/' + record.zoneid).route.name !== '404'" :to="{ path: '/zone/' + record.zoneid }">{{ text }}</router-link>
|
||||
</template>
|
||||
<template #zone="{ text, record }">
|
||||
<a href="javascript:;">
|
||||
<router-link v-if="record.zoneid && !record.zoneid.includes(',') && $router.resolve('/zone/' + record.zoneid).name !== '404'" :to="{ path: '/zone/' + record.zoneid }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</a>
|
||||
</template>
|
||||
<template #zonename="{ text, record }">
|
||||
<router-link v-if="$router.resolve('/zone/' + record.zoneid).name !== '404'" :to="{ path: '/zone/' + record.zoneid }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</a>
|
||||
<span slot="zonename" slot-scope="text, record">
|
||||
<router-link v-if="$router.resolve('/zone/' + record.zoneid).route.name !== '404'" :to="{ path: '/zone/' + record.zoneid }">{{ text }}</router-link>
|
||||
</template>
|
||||
<template #rolename="{ text, record }">
|
||||
<router-link v-if="record.roleid && $router.resolve('/role/' + record.roleid).name !== '404'" :to="{ path: '/role/' + record.roleid }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</span>
|
||||
<span slot="rolename" slot-scope="text, record">
|
||||
<router-link v-if="record.roleid && $router.resolve('/role/' + record.roleid).route.name !== '404'" :to="{ path: '/role/' + record.roleid }">{{ text }}</router-link>
|
||||
<span v-else>{{ text }}</span>
|
||||
</span>
|
||||
<a slot="readonly" slot-scope="text, record">
|
||||
</template>
|
||||
<template #readonly="{ record }">
|
||||
<status :text="record.readonly ? 'ReadOnly' : 'ReadWrite'" displayText />
|
||||
</a>
|
||||
<span slot="requiresupgrade" slot-scope="text, record">
|
||||
</template>
|
||||
<template #requiresupgrade="{ record }">
|
||||
<status :text="record.requiresupgrade ? 'warning' : ''" />
|
||||
{{ record.requiresupgrade ? 'Yes' : 'No' }}
|
||||
</span>
|
||||
<span slot="autoscalingenabled" slot-scope="text, record">
|
||||
</template>
|
||||
<template #autoscalingenabled="{ record }">
|
||||
<status :text="record.autoscalingenabled ? 'Enabled' : 'Disabled'" />
|
||||
{{ record.autoscalingenabled ? 'Enabled' : 'Disabled' }}
|
||||
</span>
|
||||
<span slot="current" slot-scope="text, record">
|
||||
</template>
|
||||
<template #current="{record}">
|
||||
<status :text="record.current ? record.current.toString() : 'false'" />
|
||||
</span>
|
||||
<span slot="created" slot-scope="text">
|
||||
</template>
|
||||
<template #created="{ text }">
|
||||
{{ $toLocaleDate(text) }}
|
||||
</span>
|
||||
<span slot="sent" slot-scope="text">
|
||||
</template>
|
||||
<template #sent="{ text }">
|
||||
{{ $toLocaleDate(text) }}
|
||||
</span>
|
||||
<div slot="order" slot-scope="text, record" class="shift-btns">
|
||||
<a-tooltip placement="top">
|
||||
<template slot="title">{{ $t('label.move.to.top') }}</template>
|
||||
<a-button
|
||||
shape="round"
|
||||
@click="moveItemTop(record)"
|
||||
class="shift-btn">
|
||||
<a-icon type="double-left" class="shift-btn shift-btn--rotated" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="top">
|
||||
<template slot="title">{{ $t('label.move.to.bottom') }}</template>
|
||||
<a-button
|
||||
shape="round"
|
||||
@click="moveItemBottom(record)"
|
||||
class="shift-btn">
|
||||
<a-icon type="double-right" class="shift-btn shift-btn--rotated" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="top">
|
||||
<template slot="title">{{ $t('label.move.up.row') }}</template>
|
||||
<a-button shape="round" @click="moveItemUp(record)" class="shift-btn">
|
||||
<a-icon type="caret-up" class="shift-btn" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="top">
|
||||
<template slot="title">{{ $t('label.move.down.row') }}</template>
|
||||
<a-button shape="round" @click="moveItemDown(record)" class="shift-btn">
|
||||
<a-icon type="caret-down" class="shift-btn" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<template #order="{ text, record }">
|
||||
<div class="shift-btns">
|
||||
<a-tooltip :name="text" placement="top">
|
||||
<template #title>{{ $t('label.move.to.top') }}</template>
|
||||
<a-button
|
||||
shape="round"
|
||||
@click="moveItemTop(record)"
|
||||
class="shift-btn">
|
||||
<DoubleLeftOutlined class="shift-btn shift-btn--rotated" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="top">
|
||||
<template #title>{{ $t('label.move.to.bottom') }}</template>
|
||||
<a-button
|
||||
shape="round"
|
||||
@click="moveItemBottom(record)"
|
||||
class="shift-btn">
|
||||
<DoubleRightOutlined class="shift-btn shift-btn--rotated" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="top">
|
||||
<template #title>{{ $t('label.move.up.row') }}</template>
|
||||
<a-button shape="round" @click="moveItemUp(record)" class="shift-btn">
|
||||
<CaretUpOutlined class="shift-btn" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="top">
|
||||
<template #title>{{ $t('label.move.down.row') }}</template>
|
||||
<a-button shape="round" @click="moveItemDown(record)" class="shift-btn">
|
||||
<CaretDownOutlined class="shift-btn" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template slot="value" slot-scope="text, record">
|
||||
<template #value="{ text, record }">
|
||||
<a-input
|
||||
v-if="editableValueKey === record.key"
|
||||
:autoFocus="true"
|
||||
v-focus="true"
|
||||
:defaultValue="record.value"
|
||||
:disabled="!('updateConfiguration' in $store.getters.apis)"
|
||||
v-model="editableValue"
|
||||
v-model:value="editableValue"
|
||||
@keydown.esc="editableValueKey = null"
|
||||
@pressEnter="saveValue(record)">
|
||||
</a-input>
|
||||
@ -336,40 +382,40 @@
|
||||
{{ text }}
|
||||
</div>
|
||||
</template>
|
||||
<template slot="actions" slot-scope="text, record">
|
||||
<template #actions="{ record }">
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.edit')"
|
||||
:disabled="!('updateConfiguration' in $store.getters.apis)"
|
||||
v-if="editableValueKey !== record.key"
|
||||
icon="edit"
|
||||
@click="editValue(record)" />
|
||||
icon="edit-outlined"
|
||||
@onClick="editValue(record)" />
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.cancel')"
|
||||
@click="editableValueKey = null"
|
||||
@onClick="editableValueKey = null"
|
||||
v-if="editableValueKey === record.key"
|
||||
iconType="close-circle"
|
||||
iconType="CloseCircleTwoTone"
|
||||
iconTwoToneColor="#f5222d" />
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.ok')"
|
||||
:disabled="!('updateConfiguration' in $store.getters.apis)"
|
||||
@click="saveValue(record)"
|
||||
@onClick="saveValue(record)"
|
||||
v-if="editableValueKey === record.key"
|
||||
iconType="check-circle"
|
||||
iconType="CheckCircleTwoTone"
|
||||
iconTwoToneColor="#52c41a" />
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.reset.config.value')"
|
||||
@click="resetConfig(record)"
|
||||
@onClick="resetConfig(record)"
|
||||
v-if="editableValueKey !== record.key"
|
||||
icon="reload"
|
||||
icon="reload-outlined"
|
||||
:disabled="!('updateConfiguration' in $store.getters.apis)" />
|
||||
</template>
|
||||
<template slot="tariffActions" slot-scope="text, record">
|
||||
<template #tariffActions="{ record }">
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.edit')"
|
||||
v-if="editableValueKey !== record.key"
|
||||
:disabled="!('quotaTariffUpdate' in $store.getters.apis)"
|
||||
icon="edit"
|
||||
@click="editTariffValue(record)" />
|
||||
icon="edit-outlined"
|
||||
@onClick="editTariffValue(record)" />
|
||||
<slot></slot>
|
||||
</template>
|
||||
</a-table>
|
||||
@ -377,30 +423,36 @@
|
||||
|
||||
<script>
|
||||
import { api } from '@/api'
|
||||
import Console from '@/components/widgets/Console'
|
||||
import OsLogo from '@/components/widgets/OsLogo'
|
||||
import Status from '@/components/widgets/Status'
|
||||
import InfoCard from '@/components/view/InfoCard'
|
||||
import QuickView from '@/components/view/QuickView'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||
import RenderIcon from '@/utils/renderIcon'
|
||||
|
||||
export default {
|
||||
name: 'ListView',
|
||||
components: {
|
||||
Console,
|
||||
OsLogo,
|
||||
Status,
|
||||
InfoCard,
|
||||
QuickView,
|
||||
TooltipButton,
|
||||
ResourceIcon
|
||||
ResourceIcon,
|
||||
RenderIcon
|
||||
},
|
||||
props: {
|
||||
columns: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
columnKeys: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
selectedColumns: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
@ -660,7 +712,7 @@ export default {
|
||||
return record.nic.filter(e => { return e.ip6address }).map(e => { return e.ip6address }).join(', ') || text
|
||||
},
|
||||
generateCommentsPath (record) {
|
||||
return '/' + this.entityTypeToPath(record.entitytype) + '/' + record.entityid + '?tab=comments'
|
||||
return '/' + this.entityTypeToPath(record.entitytype) + '/' + record.entityid
|
||||
},
|
||||
generateHumanReadableEntityType (record) {
|
||||
switch (record.entitytype) {
|
||||
@ -738,31 +790,40 @@ export default {
|
||||
return 'Unsecure'
|
||||
}
|
||||
return host.state
|
||||
},
|
||||
getColumnKey (name) {
|
||||
if (typeof name === 'object') {
|
||||
name = Object.keys(name)[0]
|
||||
}
|
||||
return name
|
||||
},
|
||||
updateSelectedColumns (name) {
|
||||
this.$emit('update-selected-columns', name)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/deep/ .ant-table-thead {
|
||||
<style>
|
||||
:deep(.ant-table-thead) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
/deep/ .ant-table-small > .ant-table-content > .ant-table-body {
|
||||
:deep(.ant-table-small) > .ant-table-content > .ant-table-body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/deep/ .light-row {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/deep/ .dark-row {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
/deep/ .ant-table-tbody>tr>td, .ant-table-thead>tr>th {
|
||||
:deep(.ant-table-tbody)>tr>td, :deep(.ant-table-thead)>tr>th {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.filter-dropdown .ant-menu-vertical {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.filter-dropdown .ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
|
||||
background-color: transparent;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
<a-input-search
|
||||
class="top-spaced"
|
||||
:placeholder="$t('label.search')"
|
||||
v-model="searchQuery"
|
||||
v-model:value="searchQuery"
|
||||
style="margin-bottom: 10px;"
|
||||
@search="fetchNetworks"
|
||||
autoFocus />
|
||||
@ -33,7 +33,7 @@
|
||||
:dataSource="networks"
|
||||
:pagination="false"
|
||||
:rowKey="record => record.id">
|
||||
<template slot="select" slot-scope="record">
|
||||
<template #select="{record}">
|
||||
<a-radio
|
||||
@click="updateSelection(record)"
|
||||
:checked="selectedNetwork != null && record.id === selectedNetwork.id">
|
||||
@ -51,7 +51,7 @@
|
||||
@change="handleChangePage"
|
||||
@showSizeChange="handleChangePageSize"
|
||||
showSizeChanger>
|
||||
<template slot="buildOptionText" slot-scope="props">
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
@ -114,7 +114,7 @@ export default {
|
||||
},
|
||||
{
|
||||
title: this.$t('label.select'),
|
||||
scopedSlots: { customRender: 'select' }
|
||||
slots: { customRender: 'select' }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
<template>
|
||||
<a-popover v-if="enabled && actionsExist" triggers="hover" placement="topLeft" v-model="visible">
|
||||
<template slot="content">
|
||||
<template #content>
|
||||
<action-button
|
||||
:size="size"
|
||||
:actions="actions"
|
||||
@ -25,7 +25,9 @@
|
||||
:resource="resource"
|
||||
@exec-action="execAction" />
|
||||
</template>
|
||||
<a-button shape="circle" size="small" icon="more" style="float: right; background-color: transparent; border-color: transparent"/>
|
||||
<a-button shape="circle" size="small" style="float: right; background-color: transparent; border-color: transparent">
|
||||
<template #icon><MoreOutlined /></template>
|
||||
</a-button>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
@ -58,8 +60,11 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource () {
|
||||
this.actionsExist = this.doActionsExist()
|
||||
actions: {
|
||||
deep: true,
|
||||
handler () {
|
||||
this.actionsExist = this.doActionsExist()
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
|
||||
@ -20,23 +20,25 @@
|
||||
size="small"
|
||||
:loading="loading"
|
||||
:dataSource="usageList" >
|
||||
<a-list-item slot="renderItem" slot-scope="item" class="list-item" v-if="!($route.meta.name === 'project' && item === 'project')">
|
||||
<div class="list-item__container">
|
||||
<strong>
|
||||
{{ $t('label.' + item + 'limit') }}
|
||||
</strong>
|
||||
({{ resource[item + 'available'] === '-1' ? $t('label.unlimited') : resource[item + 'available'] }} {{ $t('label.available') }})
|
||||
<div class="list-item__vals">
|
||||
<div class="list-item__data">
|
||||
{{ $t('label.used') }} / {{ $t('label.limit') }} : {{ resource[item + 'total'] }} / {{ resource[item + 'limit'] === '-1' ? $t('label.unlimited') : resource[item + 'limit'] }}
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item class="list-item" v-if="!($route.meta.name === 'project' && item === 'project')">
|
||||
<div class="list-item__container">
|
||||
<strong>
|
||||
{{ $t('label.' + item + 'limit') }}
|
||||
</strong>
|
||||
({{ resource[item + 'available'] === '-1' ? $t('label.unlimited') : resource[item + 'available'] }} {{ $t('label.available') }})
|
||||
<div class="list-item__vals">
|
||||
<div class="list-item__data">
|
||||
{{ $t('label.used') }} / {{ $t('label.limit') }} : {{ resource[item + 'total'] }} / {{ resource[item + 'limit'] === '-1' ? $t('label.unlimited') : resource[item + 'limit'] }}
|
||||
</div>
|
||||
<a-progress
|
||||
status="normal"
|
||||
:percent="parseFloat(getPercentUsed(resource[item + 'total'], resource[item + 'limit']))"
|
||||
:format="p => resource[item + 'limit'] !== '-1' && resource[item + 'limit'] !== 'Unlimited' ? p.toFixed(2) + '%' : ''" />
|
||||
</div>
|
||||
<a-progress
|
||||
status="normal"
|
||||
:percent="parseFloat(getPercentUsed(resource[item + 'total'], resource[item + 'limit']))"
|
||||
:format="p => resource[item + 'limit'] !== '-1' && resource[item + 'limit'] !== 'Unlimited' ? p.toFixed(2) + '%' : ''" />
|
||||
</div>
|
||||
</div>
|
||||
</a-list-item>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</template>
|
||||
|
||||
@ -61,14 +63,6 @@ export default {
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource (newData, oldData) {
|
||||
if (!newData || !newData.id) {
|
||||
return
|
||||
}
|
||||
this.resource = newData
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getPercentUsed (total, limit) {
|
||||
return (limit === 'Unlimited') ? 0 : (total / limit) * 100
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<img :src="getImg()" :height="getDimensions()" :width="getDimensions()" :style="{ marginTop: (getDimensions() === '56px' || ['deployVirtualMachine'].includes(this.$route.path.split('/')[2])) ? '' : '-5px' }"/>
|
||||
<img :src="getImg()" :height="getDimensions()" :width="getDimensions()" :style="{ marginTop: (getDimensions() === 56 || ['deployVirtualMachine'].includes($route.path.split('/')[2])) ? '' : '-5px' }"/>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
@ -45,13 +45,13 @@ export default {
|
||||
getDimensions () {
|
||||
switch (this.size) {
|
||||
case '4x':
|
||||
return '56px'
|
||||
return 56
|
||||
case '2x':
|
||||
return '24px'
|
||||
return 24
|
||||
case '1x':
|
||||
return '16px'
|
||||
return 16
|
||||
default:
|
||||
return '16px'
|
||||
return 16
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,26 +18,28 @@
|
||||
<template>
|
||||
<a-spin :spinning="formLoading">
|
||||
<a-form
|
||||
:form="form"
|
||||
@submit="handleSubmit"
|
||||
:ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
@finish="handleSubmit"
|
||||
layout="vertical"
|
||||
v-ctrl-enter="handleSubmit"
|
||||
>
|
||||
<a-form-item
|
||||
v-for="(item, index) in dataResource"
|
||||
:key="index"
|
||||
v-if="item.resourcetypename !== 'project'"
|
||||
:v-bind="item.resourcetypename"
|
||||
:label="$t('label.max' + item.resourcetypename.replace('_', ''))">
|
||||
<a-input-number
|
||||
:disabled="!('updateResourceLimit' in $store.getters.apis)"
|
||||
style="width: 100%;"
|
||||
v-decorator="[item.resourcetype, {
|
||||
initialValue: item.max
|
||||
}]"
|
||||
:autoFocus="index === 0"
|
||||
/>
|
||||
</a-form-item>
|
||||
<div v-for="(item, index) in dataResource" :key="index">
|
||||
<a-form-item
|
||||
v-if="item.resourcetypename !== 'project'"
|
||||
:v-bind="item.resourcetypename"
|
||||
:label="$t('label.max' + (item.resourcetypename ? item.resourcetypename.replace('_', '') : ''))"
|
||||
:name="item.resourcetype"
|
||||
:ref="item.resourcetype">
|
||||
<a-input-number
|
||||
:disabled="!('updateResourceLimit' in $store.getters.apis)"
|
||||
style="width: 100%;"
|
||||
v-model:value="form[item.resourcetype]"
|
||||
v-focus="index === 0"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a-button
|
||||
:disabled="!('updateResourceLimit' in $store.getters.apis)"
|
||||
@ -52,6 +54,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
|
||||
export default {
|
||||
@ -72,19 +75,22 @@ export default {
|
||||
dataResource: []
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
},
|
||||
created () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({})
|
||||
this.dataResource = this.resource
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
resource (newData, oldData) {
|
||||
if (!newData || !newData.id) {
|
||||
return
|
||||
resource: {
|
||||
deep: true,
|
||||
handler (newData) {
|
||||
if (!newData || !newData.id) {
|
||||
return
|
||||
}
|
||||
this.fetchData()
|
||||
}
|
||||
this.resource = newData
|
||||
this.fetchData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -102,10 +108,15 @@ export default {
|
||||
},
|
||||
async fetchData () {
|
||||
const params = this.getParams()
|
||||
const form = {}
|
||||
try {
|
||||
this.formLoading = true
|
||||
this.dataResource = await this.listResourceLimits(params)
|
||||
this.form.resetFields()
|
||||
this.dataResource.forEach(item => {
|
||||
form[item.resourcetype] = item.max || -1
|
||||
})
|
||||
this.form = form
|
||||
this.formRef.value.resetFields()
|
||||
this.formLoading = false
|
||||
} catch (e) {
|
||||
this.$notification.error({
|
||||
@ -120,10 +131,8 @@ export default {
|
||||
|
||||
if (this.formLoading) return
|
||||
|
||||
this.form.validateFieldsAndScroll((err, values) => {
|
||||
if (err) {
|
||||
return
|
||||
}
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
const arrAsync = []
|
||||
const params = this.getParams()
|
||||
for (const key in values) {
|
||||
@ -147,6 +156,8 @@ export default {
|
||||
}).finally(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
})
|
||||
},
|
||||
listResourceLimits (params) {
|
||||
|
||||
@ -17,38 +17,41 @@
|
||||
|
||||
<template>
|
||||
<resource-layout>
|
||||
<div slot="left">
|
||||
<template #left>
|
||||
<slot name="info-card">
|
||||
<info-card :resource="resource" :loading="loading" />
|
||||
</slot>
|
||||
</div>
|
||||
<a-spin :spinning="loading" slot="right">
|
||||
</template>
|
||||
<template #right>
|
||||
<a-card
|
||||
class="spin-content"
|
||||
:loading="loading"
|
||||
:bordered="true"
|
||||
style="width:100%">
|
||||
<component
|
||||
v-if="tabs.length === 1"
|
||||
:is="tabs[0].component"
|
||||
:resource="resource"
|
||||
:loading="loading"
|
||||
:tab="tabs[0].name" />
|
||||
<keep-alive v-if="tabs.length === 1">
|
||||
<component
|
||||
:is="tabs[0].component"
|
||||
:resource="resource"
|
||||
:loading="loading"
|
||||
:tab="tabs[0].name" />
|
||||
</keep-alive>
|
||||
<a-tabs
|
||||
v-else
|
||||
style="width: 100%"
|
||||
:animated="false"
|
||||
:activeKey="activeTab || tabs[0].name"
|
||||
@change="onTabChange" >
|
||||
<a-tab-pane
|
||||
v-for="tab in tabs"
|
||||
:tab="$t('label.' + tab.name)"
|
||||
:key="tab.name"
|
||||
v-if="showTab(tab)">
|
||||
<component :is="tab.component" :resource="resource" :loading="loading" :tab="activeTab" />
|
||||
</a-tab-pane>
|
||||
<template v-for="tab in tabs" :key="tab.name">
|
||||
<a-tab-pane
|
||||
:key="tab.name"
|
||||
:tab="$t('label.' + tab.name)"
|
||||
v-if="showTab(tab)">
|
||||
<keep-alive><component :is="tab.component" :resource="resource" :loading="loading" :tab="activeTab" /></keep-alive>
|
||||
</a-tab-pane>
|
||||
</template>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</a-spin>
|
||||
</template>
|
||||
</resource-layout>
|
||||
</template>
|
||||
|
||||
@ -97,33 +100,39 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource: function (newItem, oldItem) {
|
||||
this.resource = newItem
|
||||
if (newItem.id === oldItem.id) return
|
||||
resource: {
|
||||
deep: true,
|
||||
handler (newItem, oldItem) {
|
||||
if (newItem.id === oldItem.id) return
|
||||
|
||||
if (this.resource.associatednetworkid) {
|
||||
api('listNetworks', { id: this.resource.associatednetworkid, listall: true }).then(response => {
|
||||
if (response && response.listnetworksresponse && response.listnetworksresponse.network) {
|
||||
this.networkService = response.listnetworksresponse.network[0]
|
||||
} else {
|
||||
this.networkService = {}
|
||||
}
|
||||
})
|
||||
if (this.resource.associatednetworkid) {
|
||||
api('listNetworks', { id: this.resource.associatednetworkid, listall: true }).then(response => {
|
||||
if (response && response.listnetworksresponse && response.listnetworksresponse.network) {
|
||||
this.networkService = response.listnetworksresponse.network[0]
|
||||
} else {
|
||||
this.networkService = {}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
$route: function (newItem, oldItem) {
|
||||
'$route.fullPath': function () {
|
||||
this.setActiveTab()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
created () {
|
||||
const self = this
|
||||
this.setActiveTab()
|
||||
window.addEventListener('popstate', function () {
|
||||
self.setActiveTab()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
onTabChange (key) {
|
||||
this.activeTab = key
|
||||
const query = Object.assign({}, this.$route.query)
|
||||
query.tab = key
|
||||
history.replaceState(
|
||||
history.pushState(
|
||||
{},
|
||||
null,
|
||||
'#' + this.$route.path + '?' + Object.keys(query).map(key => {
|
||||
|
||||
@ -19,11 +19,11 @@
|
||||
<span :style="styleSearch">
|
||||
<span v-if="!searchFilters || searchFilters.length === 0" style="display: flex;">
|
||||
<a-input-search
|
||||
style="width: 100%; display: table-cell"
|
||||
v-model:value="searchQuery"
|
||||
:placeholder="$t('label.search')"
|
||||
v-model="searchQuery"
|
||||
allowClear
|
||||
@search="onSearch" />
|
||||
@search="onSearch"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span
|
||||
@ -33,113 +33,117 @@
|
||||
allowClear
|
||||
class="input-search"
|
||||
:placeholder="$t('label.search')"
|
||||
v-model="searchQuery"
|
||||
v-model:value="searchQuery"
|
||||
@search="onSearch">
|
||||
<a-popover
|
||||
placement="bottomRight"
|
||||
slot="addonBefore"
|
||||
trigger="click"
|
||||
v-model="visibleFilter">
|
||||
<template slot="content" v-if="visibleFilter">
|
||||
<a-form
|
||||
style="min-width: 170px"
|
||||
:form="form"
|
||||
layout="vertical"
|
||||
@submit="handleSubmit">
|
||||
<a-form-item
|
||||
v-for="(field, index) in fields"
|
||||
:key="index"
|
||||
:label="field.name==='keyword' ?
|
||||
('listAnnotations' in $store.getters.apis ? $t('label.annotation') : $t('label.name')) :
|
||||
(field.name==='entitytype' ? $t('label.entity.type') : $t('label.' + field.name))">
|
||||
<a-select
|
||||
allowClear
|
||||
v-if="field.type==='list'"
|
||||
v-decorator="[field.name, {
|
||||
initialValue: fieldValues[field.name] || null
|
||||
}]"
|
||||
showSearch
|
||||
:dropdownMatchSelectWidth="false"
|
||||
optionFilterProp="children"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.propsData.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="field.loading">
|
||||
<a-select-option
|
||||
v-for="(opt, idx) in field.opts"
|
||||
:key="idx"
|
||||
:value="opt.id"
|
||||
:label="$t(opt.name)">
|
||||
<div>
|
||||
<span v-if="(field.name.startsWith('zone'))">
|
||||
<span v-if="opt.icon">
|
||||
<resource-icon :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||
<template #addonBefore>
|
||||
<a-popover
|
||||
placement="bottomRight"
|
||||
trigger="click"
|
||||
v-model:visible="visibleFilter">
|
||||
<template #content v-if="visibleFilter">
|
||||
<a-form
|
||||
style="min-width: 170px"
|
||||
:ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
layout="vertical"
|
||||
@finish="handleSubmit"
|
||||
v-ctrl-enter="handleSubmit">
|
||||
<a-form-item
|
||||
v-for="(field, index) in fields"
|
||||
:key="index"
|
||||
:label="field.name==='keyword' ?
|
||||
('listAnnotations' in $store.getters.apis ? $t('label.annotation') : $t('label.name')) :
|
||||
(field.name==='entitytype' ? $t('label.entity.type') : $t('label.' + field.name))">
|
||||
<a-select
|
||||
allowClear
|
||||
v-if="field.type==='list'"
|
||||
v-model:value="form[field.name]"
|
||||
showSearch
|
||||
:dropdownMatchSelectWidth="false"
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="field.loading">
|
||||
<a-select-option
|
||||
v-for="(opt, idx) in field.opts"
|
||||
:key="idx"
|
||||
:value="opt.id"
|
||||
:label="$t(opt.name)">
|
||||
<div>
|
||||
<span v-if="(field.name.startsWith('zone'))">
|
||||
<span v-if="opt.icon">
|
||||
<resource-icon :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||
</span>
|
||||
<global-outlined v-else style="margin-right: 5px" />
|
||||
</span>
|
||||
<a-icon v-else type="global" style="margin-right: 5px" />
|
||||
</span>
|
||||
<span v-if="(field.name.startsWith('domain'))">
|
||||
<span v-if="opt.icon">
|
||||
<resource-icon :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||
<span v-if="(field.name.startsWith('domain'))">
|
||||
<span v-if="opt.icon">
|
||||
<resource-icon :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||
</span>
|
||||
<block-outlined v-else style="margin-right: 5px" />
|
||||
</span>
|
||||
<a-icon v-else type="block" style="margin-right: 5px" />
|
||||
</span>
|
||||
{{ $t(opt.path || opt.name) }}
|
||||
</div>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-input
|
||||
v-else-if="field.type==='input'"
|
||||
v-decorator="[field.name, {
|
||||
initialValue: fieldValues[field.name] || null
|
||||
}]" />
|
||||
<div v-else-if="field.type==='tag'">
|
||||
<div>
|
||||
{{ $t(opt.path || opt.name) }}
|
||||
</div>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-input
|
||||
v-else-if="field.type==='input'"
|
||||
v-model:value="form[field.name]" />
|
||||
<div v-else-if="field.type==='tag'">
|
||||
<a-input-group
|
||||
type="text"
|
||||
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 ref="input" v-model:value="inputKey" style="width: 50px; text-align: center" :placeholder="$t('label.key')" />
|
||||
<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 v-model:value="inputValue" style="width: 50px; text-align: center; border-left: 0" :placeholder="$t('label.value')" />
|
||||
<tooltip-button :tooltip="$t('label.clear')" icon="close-outlined" size="small" @onClick="inputKey = inputValue = ''" />
|
||||
</a-input-group>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<div class="filter-group-button">
|
||||
<a-button
|
||||
class="filter-group-button-clear"
|
||||
type="default"
|
||||
size="small"
|
||||
@click="onClear">
|
||||
<template #icon><stop-outlined /></template>
|
||||
{{ $t('label.reset') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
class="filter-group-button-search"
|
||||
type="primary"
|
||||
size="small"
|
||||
ref="submit"
|
||||
html-type="submit">
|
||||
<template #icon><search-outlined /></template>
|
||||
{{ $t('label.search') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<div class="filter-group-button">
|
||||
<a-button
|
||||
class="filter-group-button-clear"
|
||||
type="default"
|
||||
size="small"
|
||||
icon="stop"
|
||||
@click="onClear">{{ $t('label.reset') }}</a-button>
|
||||
<a-button
|
||||
class="filter-group-button-search"
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="search"
|
||||
html-type="submit"
|
||||
@click="handleSubmit">{{ $t('label.search') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</template>
|
||||
<a-button
|
||||
class="filter-button"
|
||||
size="small"
|
||||
@click="() => { searchQuery = null }">
|
||||
<a-icon type="filter" :theme="isFiltered ? 'twoTone' : 'outlined'" />
|
||||
</a-button>
|
||||
</a-popover>
|
||||
</a-form>
|
||||
</template>
|
||||
<a-button
|
||||
class="filter-button"
|
||||
size="small"
|
||||
@click="() => { searchQuery = null }">
|
||||
<filter-two-tone v-if="isFiltered" />
|
||||
<filter-outlined v-else />
|
||||
</a-button>
|
||||
</a-popover>
|
||||
</template>
|
||||
</a-input-search>
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||
@ -176,8 +180,10 @@ export default {
|
||||
isFiltered: false
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
created () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({})
|
||||
},
|
||||
watch: {
|
||||
visibleFilter (newValue, oldValue) {
|
||||
@ -222,6 +228,11 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onVisibleForm () {
|
||||
this.visibleFilter = !this.visibleFilter
|
||||
if (!this.visibleFilter) return
|
||||
this.initFormFieldData()
|
||||
},
|
||||
async initFormFieldData () {
|
||||
const arrayField = []
|
||||
this.fields = []
|
||||
@ -331,7 +342,6 @@ export default {
|
||||
this.fields[clusterIndex].opts = this.sortArray(cluster[0].data)
|
||||
}
|
||||
}
|
||||
this.$forceUpdate()
|
||||
}).finally(() => {
|
||||
if (zoneIndex > -1) {
|
||||
this.fields[zoneIndex].loading = false
|
||||
@ -364,6 +374,9 @@ export default {
|
||||
if (this.$route.meta.params) {
|
||||
Object.assign(this.fieldValues, this.$route.meta.params)
|
||||
}
|
||||
this.fields.forEach(field => {
|
||||
this.form[field.name] = this.fieldValues[field.name]
|
||||
})
|
||||
this.inputKey = this.fieldValues['tags[0].key'] || null
|
||||
this.inputValue = this.fieldValues['tags[0].value'] || null
|
||||
},
|
||||
@ -506,11 +519,7 @@ export default {
|
||||
this.$emit('search', { searchQuery: this.searchQuery })
|
||||
},
|
||||
onClear () {
|
||||
this.searchFilters.map(item => {
|
||||
const field = {}
|
||||
field[item] = undefined
|
||||
this.form.setFieldsValue(field)
|
||||
})
|
||||
this.formRef.value.resetFields()
|
||||
this.isFiltered = false
|
||||
this.inputKey = null
|
||||
this.inputValue = null
|
||||
@ -518,13 +527,10 @@ export default {
|
||||
this.paramsFilter = {}
|
||||
this.$emit('search', this.paramsFilter)
|
||||
},
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
handleSubmit () {
|
||||
this.paramsFilter = {}
|
||||
this.form.validateFieldsAndScroll((err, values) => {
|
||||
if (err) {
|
||||
return
|
||||
}
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
this.isFiltered = true
|
||||
for (const key in values) {
|
||||
const input = values[key]
|
||||
@ -542,12 +548,6 @@ export default {
|
||||
this.$emit('search', this.paramsFilter)
|
||||
})
|
||||
},
|
||||
handleKeyChange (e) {
|
||||
this.inputKey = e.target.value
|
||||
},
|
||||
handleValueChange (e) {
|
||||
this.inputValue = e.target.value
|
||||
},
|
||||
changeFilter (filter) {
|
||||
this.$emit('change-filter', filter)
|
||||
}
|
||||
@ -561,7 +561,7 @@ export default {
|
||||
}
|
||||
|
||||
.filter-group {
|
||||
/deep/.ant-input-group-addon {
|
||||
:deep(.ant-input-group-addon) {
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
@ -587,7 +587,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-input-group {
|
||||
:deep(.ant-input-group) {
|
||||
.ant-input-affix-wrapper {
|
||||
width: calc(100% - 10px);
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
<a-radio-group
|
||||
class="setting-group"
|
||||
name="themeGroup"
|
||||
v-model="layoutMode"
|
||||
v-model:value="layoutMode"
|
||||
@change="switchLayoutMode">
|
||||
<setting-item
|
||||
view-type="radio-group"
|
||||
@ -58,7 +58,7 @@
|
||||
<a-input
|
||||
:disabled="layoutMode === 'dark'"
|
||||
type="color"
|
||||
v-model="navBgColorPick"
|
||||
v-model:value="navBgColorPick"
|
||||
@blur="(e) => updateSetting('@navigation-background-color', e.target.value)" />
|
||||
</div>
|
||||
</div>
|
||||
@ -70,7 +70,7 @@
|
||||
<a-input
|
||||
:disabled="layoutMode === 'dark'"
|
||||
type="color"
|
||||
v-model="navBgColorPick"
|
||||
v-model:value="navBgColorPick"
|
||||
@blur="(e) => updateSetting('@navigation-text-color', e.target.value)" />
|
||||
</div>
|
||||
</div>
|
||||
@ -89,7 +89,7 @@
|
||||
<div class="color-picker" :style="{ backgroundColor: projectNavBgColorPick }">
|
||||
<a-input
|
||||
type="color"
|
||||
v-model="projectNavBgColorPick"
|
||||
v-model:value="projectNavBgColorPick"
|
||||
@blur="(e) => updateSetting('@project-nav-background-color', e.target.value)" />
|
||||
</div>
|
||||
</div>
|
||||
@ -100,7 +100,7 @@
|
||||
<div class="color-picker" :style="{ backgroundColor: projectNavTextColorPick }">
|
||||
<a-input
|
||||
type="color"
|
||||
v-model="projectNavTextColorPick"
|
||||
v-model:value="projectNavTextColorPick"
|
||||
@blur="(e) => updateSetting('@project-nav-text-color', e.target.value)" />
|
||||
</div>
|
||||
</div>
|
||||
@ -113,12 +113,16 @@
|
||||
<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>
|
||||
@click="downloadSetting">
|
||||
<template #icon><download-outlined /></template>
|
||||
{{ $t('label.download.setting') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
class="setting-action-btn"
|
||||
icon="undo"
|
||||
@click="resetSetting">{{ $t('label.reset.to.default') }}</a-button>
|
||||
@click="resetSetting">
|
||||
<template #icon><undo-outlined /></template>
|
||||
{{ $t('label.reset.to.default') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -139,12 +143,12 @@ export default {
|
||||
},
|
||||
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'],
|
||||
layoutMode: this.$config.theme['@layout-mode'] || 'light',
|
||||
colorPick: this.$config.theme['@primary-color'],
|
||||
navBgColorPick: this.$config.theme['@navigation-background-color'],
|
||||
navTextColorPick: this.$config.theme['@navigation-text-color'],
|
||||
projectNavBgColorPick: this.$config.theme['@project-nav-background-color'],
|
||||
projectNavTextColorPick: this.$config.theme['@project-nav-text-color'],
|
||||
uiSettings: {},
|
||||
originalSetting: {}
|
||||
}
|
||||
@ -158,12 +162,12 @@ export default {
|
||||
{
|
||||
name: 'light',
|
||||
type: 'image-checkbox',
|
||||
component: () => import('@/assets/icons/light.svg?inline')
|
||||
icon: 'light'
|
||||
},
|
||||
{
|
||||
name: 'dark',
|
||||
type: 'image-checkbox',
|
||||
component: () => import('@/assets/icons/dark.svg?inline')
|
||||
icon: 'dark'
|
||||
}
|
||||
]
|
||||
return arrStyle
|
||||
@ -225,14 +229,12 @@ export default {
|
||||
methods: {
|
||||
fetchData () {
|
||||
this.originalSetting = Object.assign({}, this.$config.theme)
|
||||
this.layoutMode = 'light'
|
||||
if (this.$store.getters.darkMode) {
|
||||
this.layoutMode = 'dark'
|
||||
}
|
||||
this.layoutMode = this.$config.theme['@layout-mode'] || 'light'
|
||||
this.uiSettings = this.$config.theme
|
||||
},
|
||||
switchLayoutMode () {
|
||||
this.$store.dispatch('SetDarkMode', (this.layoutMode === 'dark'))
|
||||
this.updateSetting('@layout-mode', this.layoutMode)
|
||||
},
|
||||
switchColor (e) {
|
||||
this.colorPick = e.target.value
|
||||
@ -248,13 +250,8 @@ export default {
|
||||
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)
|
||||
downloadSetting () {
|
||||
this.downloadObjectAsJson(this.uiSettings)
|
||||
},
|
||||
resetSetting () {
|
||||
this.layoutMode = 'light'
|
||||
@ -264,78 +261,20 @@ export default {
|
||||
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}`
|
||||
downloadObjectAsJson (exportObj) {
|
||||
const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(exportObj, null, 2))
|
||||
const downloadAnchorNode = document.createElement('a')
|
||||
downloadAnchorNode.setAttribute('href', dataStr)
|
||||
downloadAnchorNode.setAttribute('download', 'theme.json')
|
||||
document.body.appendChild(downloadAnchorNode)
|
||||
downloadAnchorNode.click()
|
||||
downloadAnchorNode.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -394,8 +333,15 @@ export default {
|
||||
padding: 0 24px;
|
||||
|
||||
&-alert {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
margin: 20px 0 8px;
|
||||
word-break: break-word;
|
||||
position: relative;
|
||||
|
||||
:deep(.ant-alert-icon) {
|
||||
}
|
||||
}
|
||||
|
||||
&-btn {
|
||||
|
||||
@ -27,15 +27,11 @@
|
||||
<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'
|
||||
}"/>
|
||||
<light v-if="item.icon==='light'" :style="{ height: '56px', width: '56px' }" />
|
||||
<dark v-if="item.icon==='dark'" :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" />
|
||||
<a-radio v-model:value="item.name" :disabled="item.disabled"></a-radio>
|
||||
<check-outlined :class="['check-icon', item.name]" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -43,8 +39,8 @@
|
||||
<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" />
|
||||
<a-radio v-model:value="item.color"></a-radio>
|
||||
<check-outlined class="check-icon" />
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
@ -55,11 +51,16 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AddNetscalerLoadBalancer from '@/views/infra/network/providers/AddNetscalerLoadBalancer.vue'
|
||||
|
||||
import light from '@/assets/icons/light.svg?inline'
|
||||
import dark from '@/assets/icons/dark.svg?inline'
|
||||
|
||||
export default {
|
||||
components: { AddNetscalerLoadBalancer },
|
||||
name: 'SettingItem',
|
||||
components: {
|
||||
light,
|
||||
dark
|
||||
},
|
||||
props: {
|
||||
viewType: {
|
||||
type: String,
|
||||
@ -113,8 +114,8 @@ export default {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
padding-top: 25px;
|
||||
padding-left: 20px;
|
||||
padding-top: 18px;
|
||||
padding-left: 15px;
|
||||
height: 100%;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
|
||||
@ -20,23 +20,23 @@
|
||||
<a-input-search
|
||||
style="width: 25vw;float: right;margin-bottom: 10px; z-index: 8;"
|
||||
:placeholder="$t('label.search')"
|
||||
v-model="filter"
|
||||
v-model:value="filter"
|
||||
@search="handleSearch" />
|
||||
|
||||
<a-list size="large" class="list" :loading="loading || tabLoading">
|
||||
<a-list-item :key="index" v-for="(item, index) in items" class="item">
|
||||
<a-list-item-meta>
|
||||
<span slot="title" style="word-break: break-all">{{ item.name }}</span>
|
||||
<span slot="description" style="word-break: break-all">{{ item.description }}</span>
|
||||
<template #title style="word-break: break-all">{{ item.name }}</template>
|
||||
<template #description style="word-break: break-all">{{ item.description }}</template>
|
||||
</a-list-item-meta>
|
||||
|
||||
<div class="item__content">
|
||||
<a-input
|
||||
:autoFocus="editableValueKey === index"
|
||||
v-focus="editableValueKey === index"
|
||||
v-if="editableValueKey === index"
|
||||
class="editable-value value"
|
||||
:defaultValue="item.value"
|
||||
v-model="editableValue"
|
||||
v-model:value="editableValue"
|
||||
@keydown.esc="editableValueKey = null"
|
||||
@pressEnter="updateData(item)">
|
||||
</a-input>
|
||||
@ -45,32 +45,32 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div slot="actions" class="action">
|
||||
<template #actions class="action">
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.edit')"
|
||||
:disabled="!('updateConfiguration' in $store.getters.apis)"
|
||||
v-if="editableValueKey !== index"
|
||||
icon="edit"
|
||||
@click="setEditableSetting(item, index)" />
|
||||
icon="edit-outlined"
|
||||
@onClick="setEditableSetting(item, index)" />
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.cancel')"
|
||||
@click="editableValueKey = null"
|
||||
@onClick="editableValueKey = null"
|
||||
v-if="editableValueKey === index"
|
||||
iconType="close-circle"
|
||||
iconType="CloseCircleTwoTone"
|
||||
iconTwoToneColor="#f5222d" />
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.ok')"
|
||||
@click="updateData(item)"
|
||||
@onClick="updateData(item)"
|
||||
v-if="editableValueKey === index"
|
||||
iconType="check-circle"
|
||||
iconType="CheckCircleTwoTone"
|
||||
iconTwoToneColor="#52c41a" />
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.reset.config.value')"
|
||||
@click="resetConfig(item)"
|
||||
@onClick="resetConfig(item)"
|
||||
v-if="editableValueKey !== index"
|
||||
icon="reload"
|
||||
icon="reload-outlined"
|
||||
:disabled="!('updateConfiguration' in $store.getters.apis)" />
|
||||
</div>
|
||||
</template>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</div>
|
||||
@ -131,10 +131,12 @@ export default {
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
resource: function (newItem, oldItem) {
|
||||
if (!newItem.id) return
|
||||
this.resource = newItem
|
||||
this.fetchData()
|
||||
resource: {
|
||||
deep: true,
|
||||
handler (newItem) {
|
||||
if (!newItem.id) return
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -239,7 +241,7 @@ export default {
|
||||
|
||||
&__content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
display: block;
|
||||
word-break: break-all;
|
||||
|
||||
@media (min-width: 760px) {
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
<a-input-search
|
||||
class="top-spaced"
|
||||
:placeholder="$t('label.search')"
|
||||
v-model="searchQuery"
|
||||
v-model:value="searchQuery"
|
||||
style="margin-bottom: 10px;"
|
||||
@search="fetchStoragePools"
|
||||
autoFocus />
|
||||
@ -32,42 +32,38 @@
|
||||
:dataSource="storagePools"
|
||||
:pagination="false"
|
||||
:rowKey="record => record.id">
|
||||
<span slot="suitabilityCustomTitle">
|
||||
<template #suitabilityCustomTitle>
|
||||
{{ $t('label.suitability') }}
|
||||
<a-tooltip :title="$t('message.volume.state.primary.storage.suitability')" placement="top">
|
||||
<a-icon type="info-circle" class="table-tooltip-icon" />
|
||||
<info-circle-outlined class="table-tooltip-icon" />
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<div slot="name" slot-scope="record">
|
||||
</template>
|
||||
<template #name="{ record }">
|
||||
{{ record.name }}
|
||||
<a-tooltip v-if="record.name === $t('label.auto.assign')" :title="$t('message.migrate.volume.pool.auto.assign')" placement="top">
|
||||
<a-icon type="info-circle" class="table-tooltip-icon" />
|
||||
<info-circle-outlined class="table-tooltip-icon" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div slot="suitability" slot-scope="record">
|
||||
<a-icon
|
||||
</template>
|
||||
<template #suitability="{ record }">
|
||||
<check-circle-two-tone
|
||||
class="host-item__suitability-icon"
|
||||
type="check-circle"
|
||||
theme="twoTone"
|
||||
twoToneColor="#52c41a"
|
||||
v-if="record.suitableformigration" />
|
||||
<a-icon
|
||||
<close-circle-two-tone
|
||||
class="host-item__suitability-icon"
|
||||
type="close-circle"
|
||||
theme="twoTone"
|
||||
twoToneColor="#f5222d"
|
||||
v-else />
|
||||
</div>
|
||||
<div slot="disksizetotal" slot-scope="record">
|
||||
</template>
|
||||
<template #disksizetotal="{ record }">
|
||||
<span v-if="record.disksizetotal">{{ $bytesToHumanReadableSize(record.disksizetotal) }}</span>
|
||||
</div>
|
||||
<div slot="disksizeused" slot-scope="record">
|
||||
</template>
|
||||
<template #disksizeused="{ record }">
|
||||
<span v-if="record.disksizeused">{{ $bytesToHumanReadableSize(record.disksizeused) }}</span>
|
||||
</div>
|
||||
<div slot="disksizefree" slot-scope="record">
|
||||
</template>
|
||||
<template #disksizefree="{ record }">
|
||||
<span v-if="record.disksizetotal && record.disksizeused">{{ $bytesToHumanReadableSize(record.disksizetotal * 1 - record.disksizeused * 1) }}</span>
|
||||
</div>
|
||||
<template slot="select" slot-scope="record">
|
||||
</template>
|
||||
<template #select="{ record }">
|
||||
<a-tooltip placement="top" :title="record.state !== 'Up' ? $t('message.primary.storage.invalid.state') : ''">
|
||||
<a-radio
|
||||
:disabled="record.id !== -1 && record.state !== 'Up'"
|
||||
@ -88,7 +84,7 @@
|
||||
@change="handleChangePage"
|
||||
@showSizeChange="handleChangePageSize"
|
||||
showSizeChanger>
|
||||
<template slot="buildOptionText" slot-scope="props">
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
@ -137,7 +133,7 @@ export default {
|
||||
columns: [
|
||||
{
|
||||
title: this.$t('label.storageid'),
|
||||
scopedSlots: { customRender: 'name' }
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.clusterid'),
|
||||
@ -149,27 +145,26 @@ export default {
|
||||
},
|
||||
{
|
||||
title: this.$t('label.disksizetotal'),
|
||||
scopedSlots: { customRender: 'disksizetotal' }
|
||||
slots: { customRender: 'disksizetotal' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.disksizeused'),
|
||||
scopedSlots: { customRender: 'disksizeused' }
|
||||
slots: { customRender: 'disksizeused' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.disksizefree'),
|
||||
scopedSlots: { customRender: 'disksizefree' }
|
||||
slots: { customRender: 'disksizefree' }
|
||||
},
|
||||
{
|
||||
title: this.$t('label.select'),
|
||||
scopedSlots: { customRender: 'select' }
|
||||
slots: { customRender: 'select' }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (this.suitabilityEnabled) {
|
||||
this.columns.splice(1, 0, { slots: { title: 'suitabilityCustomTitle' }, scopedSlots: { customRender: 'suitability' } }
|
||||
)
|
||||
this.columns.splice(1, 0, { title: 'suitabilityCustomTitle', slots: 'suitability' })
|
||||
}
|
||||
this.preselectStoragePool()
|
||||
this.fetchStoragePools()
|
||||
|
||||
@ -17,62 +17,66 @@
|
||||
|
||||
<template>
|
||||
<resource-layout>
|
||||
<a-spin :spinning="loading" slot="left">
|
||||
<a-card :bordered="false">
|
||||
<a-input-search
|
||||
size="default"
|
||||
:placeholder="$t('label.search')"
|
||||
v-model="searchQuery"
|
||||
@search="onSearch"
|
||||
>
|
||||
<a-icon slot="prefix" type="search" />
|
||||
</a-input-search>
|
||||
<a-spin :spinning="loadingSearch">
|
||||
<a-tree
|
||||
showLine
|
||||
v-if="treeViewData.length > 0"
|
||||
class="list-tree-view"
|
||||
:treeData="treeViewData"
|
||||
:loadData="onLoadData"
|
||||
:expandAction="false"
|
||||
:showIcon="true"
|
||||
:selectedKeys="defaultSelected"
|
||||
:checkStrictly="true"
|
||||
@select="onSelect"
|
||||
@expand="onExpand"
|
||||
:expandedKeys="arrExpand">
|
||||
<a-icon slot="parent" type="folder" />
|
||||
<a-icon slot="leaf" type="block" />
|
||||
</a-tree>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</a-spin>
|
||||
<a-spin :spinning="detailLoading" slot="right">
|
||||
<a-card
|
||||
class="spin-content"
|
||||
:bordered="true"
|
||||
style="width:100%">
|
||||
<a-tabs
|
||||
style="width: 100%"
|
||||
:animated="false"
|
||||
:defaultActiveKey="tabs[0].name"
|
||||
@change="onTabChange" >
|
||||
<a-tab-pane
|
||||
v-for="tab in tabs"
|
||||
:tab="$t('label.' + tab.name)"
|
||||
:key="tab.name"
|
||||
v-if="checkShowTabDetail(tab)">
|
||||
<component
|
||||
:is="tab.component"
|
||||
:resource="resource"
|
||||
:items="items"
|
||||
:tab="tabActive"
|
||||
:loading="loading"
|
||||
:bordered="false" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</a-spin>
|
||||
<template #left>
|
||||
<a-spin :spinning="loading">
|
||||
<a-card :bordered="false">
|
||||
<a-input-search
|
||||
size="default"
|
||||
:placeholder="$t('label.search')"
|
||||
v-model:value="searchQuery"
|
||||
@search="onSearch"
|
||||
>
|
||||
<template #prefix><search-outlined /></template>
|
||||
</a-input-search>
|
||||
<a-spin :spinning="loadingSearch">
|
||||
<a-tree
|
||||
showLine
|
||||
v-if="treeViewData.length > 0"
|
||||
class="list-tree-view"
|
||||
:treeData="treeViewData"
|
||||
:loadData="onLoadData"
|
||||
:expandAction="false"
|
||||
:showIcon="true"
|
||||
:selectedKeys="defaultSelected"
|
||||
:checkStrictly="true"
|
||||
@select="onSelect"
|
||||
@expand="onExpand"
|
||||
:expandedKeys="arrExpand">
|
||||
<template #parent><folder-outlined /></template>
|
||||
<template #leaf><block-outlined /></template>
|
||||
</a-tree>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</a-spin>
|
||||
</template>
|
||||
<template #right>
|
||||
<a-spin :spinning="detailLoading">
|
||||
<a-card
|
||||
class="spin-content"
|
||||
:bordered="true"
|
||||
style="width:100%">
|
||||
<a-tabs
|
||||
style="width: 100%"
|
||||
:animated="false"
|
||||
:defaultActiveKey="tabs[0].name"
|
||||
@change="onTabChange" >
|
||||
<template v-for="tab in tabs" :tab="$t('label.' + tab.name)" :key="tab.name">
|
||||
<a-tab-pane :tab="$t('label.' + tab.name)" :key="tab.name" v-if="checkShowTabDetail(tab)">
|
||||
<keep-alive>
|
||||
<component
|
||||
:is="tab.component"
|
||||
:resource="resource"
|
||||
:items="items"
|
||||
:tab="tabActive"
|
||||
:loading="loading"
|
||||
:bordered="false" />
|
||||
</keep-alive>
|
||||
</a-tab-pane>
|
||||
</template>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</a-spin>
|
||||
</template>
|
||||
</resource-layout>
|
||||
</template>
|
||||
|
||||
@ -154,7 +158,7 @@ export default {
|
||||
this.metaName = this.$route.meta.name
|
||||
this.apiList = this.$route.meta.permission[0] ? this.$route.meta.permission[0] : ''
|
||||
this.apiChildren = this.$route.meta.permission[1] ? this.$route.meta.permission[1] : ''
|
||||
eventBus.$on('refresh-domain-icon', () => {
|
||||
eventBus.on('refresh-domain-icon', () => {
|
||||
this.getDetailResource(this.selectedTreeKey)
|
||||
})
|
||||
},
|
||||
@ -173,14 +177,31 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
treeSelected () {
|
||||
if (Object.keys(this.treeSelected).length === 0) {
|
||||
return
|
||||
}
|
||||
treeSelected: {
|
||||
deep: true,
|
||||
handler () {
|
||||
if (Object.keys(this.treeSelected).length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Object.keys(this.resource).length > 0) {
|
||||
this.selectedTreeKey = this.resource.key
|
||||
this.$emit('change-resource', this.resource)
|
||||
if (Object.keys(this.resource).length > 0) {
|
||||
this.selectedTreeKey = this.resource.key
|
||||
this.$emit('change-resource', this.resource)
|
||||
|
||||
// set default expand
|
||||
if (this.defaultSelected.length > 1) {
|
||||
const arrSelected = this.defaultSelected
|
||||
this.defaultSelected = []
|
||||
this.defaultSelected.push(arrSelected[0])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.resource = this.treeSelected
|
||||
this.resource = this.createResourceData(this.resource)
|
||||
this.selectedTreeKey = this.treeSelected.key
|
||||
this.defaultSelected.push(this.selectedTreeKey)
|
||||
|
||||
// set default expand
|
||||
if (this.defaultSelected.length > 1) {
|
||||
@ -188,33 +209,22 @@ export default {
|
||||
this.defaultSelected = []
|
||||
this.defaultSelected.push(arrSelected[0])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.resource = this.treeSelected
|
||||
this.resource = this.createResourceData(this.resource)
|
||||
this.selectedTreeKey = this.treeSelected.key
|
||||
this.defaultSelected.push(this.selectedTreeKey)
|
||||
|
||||
// set default expand
|
||||
if (this.defaultSelected.length > 1) {
|
||||
const arrSelected = this.defaultSelected
|
||||
this.defaultSelected = []
|
||||
this.defaultSelected.push(arrSelected[0])
|
||||
}
|
||||
},
|
||||
treeVerticalData () {
|
||||
if (!this.treeStore.isExpand) {
|
||||
return
|
||||
}
|
||||
if (this.treeStore.expands && this.treeStore.expands.length > 0) {
|
||||
for (const expandKey of this.treeStore.expands) {
|
||||
if (this.arrExpand.includes(expandKey)) {
|
||||
continue
|
||||
treeVerticalData: {
|
||||
deep: true,
|
||||
handler () {
|
||||
if (!this.treeStore.isExpand) {
|
||||
return
|
||||
}
|
||||
if (this.treeStore.expands && this.treeStore.expands.length > 0) {
|
||||
for (const expandKey of this.treeStore.expands) {
|
||||
if (this.arrExpand.includes(expandKey)) {
|
||||
continue
|
||||
}
|
||||
const keyVisible = this.treeVerticalData.findIndex(item => item.key === expandKey)
|
||||
if (keyVisible > -1) this.arrExpand.push(expandKey)
|
||||
}
|
||||
const keyVisible = this.treeVerticalData.findIndex(item => item.key === expandKey)
|
||||
if (keyVisible > -1) this.arrExpand.push(expandKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -256,7 +266,7 @@ export default {
|
||||
if (item.id === dataGenerate[i].id) {
|
||||
// replace all value of tree data
|
||||
Object.keys(dataGenerate[i]).forEach((value, idx) => {
|
||||
this.$set(this.treeVerticalData[index], value, dataGenerate[i][value])
|
||||
this.treeVerticalData[index][value] = dataGenerate[i][value]
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -307,18 +317,20 @@ export default {
|
||||
this.defaultSelected = []
|
||||
this.defaultSelected.push(this.selectedTreeKey)
|
||||
|
||||
this.treeStore.expands = this.arrExpand
|
||||
this.treeStore.selected = this.selectedTreeKey
|
||||
const treeStore = this.treeStore
|
||||
treeStore.expands = this.arrExpand
|
||||
treeStore.selected = this.selectedTreeKey
|
||||
this.$emit('change-tree-store', this.treeStore)
|
||||
|
||||
this.getDetailResource(this.selectedTreeKey)
|
||||
},
|
||||
onExpand (treeExpand) {
|
||||
const treeStore = this.treeStore
|
||||
this.arrExpand = treeExpand
|
||||
this.treeStore.isExpand = true
|
||||
this.treeStore.expands = this.arrExpand
|
||||
this.treeStore.selected = this.selectedTreeKey
|
||||
this.$emit('change-tree-store', this.treeStore)
|
||||
treeStore.isExpand = true
|
||||
treeStore.expands = this.arrExpand
|
||||
treeStore.selected = this.selectedTreeKey
|
||||
this.$emit('change-tree-store', treeStore)
|
||||
},
|
||||
onSearch (value) {
|
||||
if (this.searchQuery === '' && this.oldSearchQuery === '') {
|
||||
@ -492,17 +504,17 @@ export default {
|
||||
|
||||
Object.keys(resource).forEach((value, idx) => {
|
||||
if (resource[value] === 'Unlimited') {
|
||||
this.$set(resource, value, '-1')
|
||||
resource.value = '-1'
|
||||
}
|
||||
})
|
||||
this.$set(resource, 'title', resource.name)
|
||||
this.$set(resource, 'key', resource.id)
|
||||
resource.title = resource.name
|
||||
resource.key = resource.id
|
||||
resource.slots = {
|
||||
icon: 'parent'
|
||||
}
|
||||
|
||||
if (!resource.haschild) {
|
||||
this.$set(resource, 'isLeaf', true)
|
||||
resource.isLeaf = true
|
||||
resource.slots = {
|
||||
icon: 'leaf'
|
||||
}
|
||||
@ -562,7 +574,7 @@ export default {
|
||||
.list-tree-view {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
/deep/.ant-tree.ant-tree-directory {
|
||||
:deep(.ant-tree).ant-tree-directory {
|
||||
li.ant-tree-treenode-selected {
|
||||
span.ant-tree-switcher {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
@ -588,20 +600,20 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-tree li span.ant-tree-switcher.ant-tree-switcher-noop {
|
||||
:deep(.ant-tree) li span.ant-tree-switcher.ant-tree-switcher-noop {
|
||||
display: none
|
||||
}
|
||||
|
||||
:deep(.ant-tree-node-content-wrapper-open) > span:first-child,
|
||||
:deep(.ant-tree-node-content-wrapper-close) > span:first-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/deep/.ant-tree-node-content-wrapper-open > span:first-child,
|
||||
/deep/.ant-tree-node-content-wrapper-close > span:first-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/deep/.ant-tree-icon__customize {
|
||||
:deep(.ant-tree-icon__customize) {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
/deep/.ant-tree li .ant-tree-node-content-wrapper {
|
||||
:deep(.ant-tree) li .ant-tree-node-content-wrapper {
|
||||
padding-left: 0;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-modal
|
||||
v-if="visible"
|
||||
:title="$t('label.upload.resource.icon')"
|
||||
:visible="visible"
|
||||
:maskClosable="true"
|
||||
@ -56,41 +57,56 @@
|
||||
<a-row>
|
||||
<a-col :xs="2" :md="2">
|
||||
<a-upload name="file" :beforeUpload="beforeUpload" :showUploadList="false">
|
||||
<a-button><a-icon type="upload" />{{ $t('label.choose.resource.icon') }} </a-button>
|
||||
<a-button><upload-outlined />{{ $t('label.choose.resource.icon') }} </a-button>
|
||||
</a-upload>
|
||||
</a-col>
|
||||
<a-col :xs="{span: 2, offset: 4}" :md="1">
|
||||
<a-button icon="plus" @click="changeScale(5)"/>
|
||||
<a-button @click="changeScale(5)">
|
||||
<template #icon><plus-outlined /></template>
|
||||
</a-button>
|
||||
</a-col>
|
||||
<a-col :xs="{span: 1, offset: 0}" :md="2">
|
||||
<a-button icon="minus" @click="changeScale(-5)"/>
|
||||
<a-button @click="changeScale(-5)">
|
||||
<template #icon><minus-outlined /></template>
|
||||
</a-button>
|
||||
</a-col>
|
||||
<a-col :lg="{span: 1, offset: 0}" :md="2">
|
||||
<a-button icon="undo" @click="rotateLeft"/>
|
||||
<a-button @click="rotateLeft">
|
||||
<template #icon><undo-outlined /></template>
|
||||
</a-button>
|
||||
</a-col>
|
||||
<a-col :lg="{span: 1, offset: 0}" :md="2">
|
||||
<a-button icon="redo" @click="rotateRight"/>
|
||||
<a-button @click="rotateRight">
|
||||
<template #icon><redo-outlined /></template>
|
||||
</a-button>
|
||||
</a-col>
|
||||
<a-col :xs="{span: 1, offset: 3}" :md="1">
|
||||
<a-button type="primary" @click="uploadIcon('blob')"> {{ $t('label.upload') }} </a-button>
|
||||
</a-col>
|
||||
<a-col :xs="{span: 2, offset: 5}" :md="2">
|
||||
<a-button v-if="resource.icon && resource.icon.resourcetype.toLowerCase() === $getResourceType().toLowerCase()" type="danger" @click="deleteIcon('blob')"> {{ $t('label.delete') }} </a-button>
|
||||
<a-button
|
||||
v-if="resource.icon && resource.icon.resourcetype.toLowerCase() === $getResourceType().toLowerCase()"
|
||||
type="primary"
|
||||
danger
|
||||
@click="deleteIcon('blob')"> {{ $t('label.delete') }} </a-button>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-modal>
|
||||
<a-modal
|
||||
v-if="showAlert"
|
||||
:visible="showAlert"
|
||||
:footer="null"
|
||||
style="top: 20px;"
|
||||
centered
|
||||
width="auto"
|
||||
:maskClosable="false">
|
||||
<span slot="title">
|
||||
<template #title>
|
||||
{{ $t('label.warning') }}
|
||||
</span>
|
||||
</template>
|
||||
<a-alert type="warning">
|
||||
<span slot="message" v-html="$t('message.warn.filetype')" />
|
||||
<template #message>
|
||||
<span v-html="$t('message.warn.filetype')" />
|
||||
</template>
|
||||
</a-alert>
|
||||
<a-divider style="margin-top: 0;"></a-divider>
|
||||
<div :span="24" class="action-button">
|
||||
@ -119,13 +135,17 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource: function (oldVal, newVal) {
|
||||
if (oldVal === newVal) return
|
||||
this.defaultImage = this.resource?.icon?.base64image || ''
|
||||
resource: {
|
||||
deep: true,
|
||||
handler () {
|
||||
this.defaultImage = this.resource?.icon?.base64image || ''
|
||||
}
|
||||
},
|
||||
preview: function (data) {
|
||||
this.realTime(data)
|
||||
return this.previews
|
||||
preview: {
|
||||
deep: true,
|
||||
handler () {
|
||||
this.realTime(this.preview)
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -151,7 +171,7 @@ export default {
|
||||
handleClose () {
|
||||
this.options.img = ''
|
||||
this.previews = {}
|
||||
eventBus.$emit('handle-close')
|
||||
eventBus.emit('handle-close')
|
||||
},
|
||||
realTime (data) {
|
||||
if (data && data.url) {
|
||||
@ -247,12 +267,12 @@ export default {
|
||||
})
|
||||
}).finally(() => {
|
||||
this.handleClose()
|
||||
eventBus.$emit('refresh-icon')
|
||||
eventBus.emit('refresh-icon')
|
||||
if (['user', 'account'].includes(resourceType.toLowerCase())) {
|
||||
eventBus.$emit('refresh-header')
|
||||
eventBus.emit('refresh-header')
|
||||
}
|
||||
if (['domain'].includes(this.$route.path.split('/')[1])) {
|
||||
eventBus.$emit('refresh-domain-icon')
|
||||
eventBus.emit('refresh-domain-icon')
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -277,12 +297,12 @@ export default {
|
||||
})
|
||||
}).finally(() => {
|
||||
this.handleClose()
|
||||
eventBus.$emit('refresh-icon')
|
||||
eventBus.emit('refresh-icon')
|
||||
if (['user', 'account'].includes(resourceType.toLowerCase())) {
|
||||
eventBus.$emit('refresh-header')
|
||||
eventBus.emit('refresh-header')
|
||||
}
|
||||
if (['domain'].includes(this.$route.path.split('/')[1])) {
|
||||
eventBus.$emit('refresh-domain-icon')
|
||||
eventBus.emit('refresh-domain-icon')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -50,9 +50,12 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resource (newItem, oldItem) {
|
||||
if (this.resource && this.resource.id && newItem && newItem.id !== oldItem.id) {
|
||||
this.fetchData()
|
||||
resource: {
|
||||
deep: true,
|
||||
handler (newItem, oldItem) {
|
||||
if (this.resource && this.resource.id && newItem && newItem.id !== oldItem.id) {
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -62,14 +65,12 @@ export default {
|
||||
methods: {
|
||||
fetchData () {
|
||||
if (!this.resource.id) return
|
||||
this.$set(this.resource, 'vmwaredc', null)
|
||||
api('listVmwareDcs', {
|
||||
zoneid: this.resource.id
|
||||
}).then(response => {
|
||||
if (response.listvmwaredcsresponse.VMwareDC && response.listvmwaredcsresponse.VMwareDC.length > 0) {
|
||||
this.vmwaredc = response.listvmwaredcsresponse.VMwareDC[0]
|
||||
}
|
||||
this.$set(this.resource, 'vmwaredc', this.vmwaredc)
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
})
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
v-if="item && item.name"
|
||||
:to="{ path: item.path === '' ? '/' : item.path }"
|
||||
>
|
||||
<a-icon v-if="index == 0" :type="item.meta.icon" style="font-size: 16px" @click="resetToMainView" />
|
||||
{{ $t(item.meta.title) }}
|
||||
<render-icon v-if="index == 0" :icon="item.meta.icon" style="font-size: 16px" @click="resetToMainView" />
|
||||
<span v-if="item.meta.title">{{ $t(item.meta.title) }}</span>
|
||||
</router-link>
|
||||
<span v-else-if="$route.params.id">
|
||||
<label
|
||||
@ -40,9 +40,9 @@
|
||||
<span v-else>
|
||||
{{ $t(item.meta.title) }}
|
||||
</span>
|
||||
<span v-if="index === (breadList.length - 1)" style="margin-left: 5px">
|
||||
<span v-if="index === (breadList.length - 1)" style="margin-left: 8px">
|
||||
<a-tooltip placement="bottom">
|
||||
<template slot="title">
|
||||
<template #title>
|
||||
{{ $t('label.open.documentation') }}
|
||||
</template>
|
||||
<a
|
||||
@ -50,7 +50,7 @@
|
||||
style="margin-right: 12px"
|
||||
:href="$config.docBase + '/' + $route.meta.docHelp"
|
||||
target="_blank">
|
||||
<a-icon type="question-circle-o"></a-icon>
|
||||
<QuestionCircleOutlined />
|
||||
</a>
|
||||
</a-tooltip>
|
||||
<slot name="end">
|
||||
@ -61,9 +61,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RenderIcon from '@/utils/renderIcon'
|
||||
|
||||
export default {
|
||||
name: 'Breadcrumb',
|
||||
components: { RenderIcon },
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
@ -82,7 +84,7 @@ export default {
|
||||
this.getBreadcrumb()
|
||||
},
|
||||
watch: {
|
||||
$route () {
|
||||
'$route.fullPath' () {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
},
|
||||
@ -90,8 +92,9 @@ export default {
|
||||
getBreadcrumb () {
|
||||
this.name = this.$route.name
|
||||
this.breadList = []
|
||||
this.$route.matched.forEach((item) => {
|
||||
if (item && item.parent && item.parent.name !== 'index' && !item.path.endsWith(':id')) {
|
||||
this.$route.matched.forEach((item, idx) => {
|
||||
const parent = this.$route.matched[idx - 1]
|
||||
if (item && parent && parent.name !== 'index' && !item.path.endsWith(':id')) {
|
||||
this.breadList.pop()
|
||||
}
|
||||
this.breadList.push(item)
|
||||
|
||||
@ -21,13 +21,12 @@
|
||||
: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" />
|
||||
<code-outlined />
|
||||
</a-button>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import { SERVER_MANAGER } from '@/store/mutation-types'
|
||||
|
||||
export default {
|
||||
@ -47,7 +46,7 @@ export default {
|
||||
if (!this.$config.multipleServer) {
|
||||
return this.$config.apiBase.replace('/api', '')
|
||||
}
|
||||
const serverStorage = Vue.ls.get(SERVER_MANAGER)
|
||||
const serverStorage = this.$localStorage.get(SERVER_MANAGER)
|
||||
const apiBase = serverStorage.apiBase.replace('/api', '')
|
||||
if (!serverStorage.apiHost || serverStorage.apiHost === '/') {
|
||||
return [location.origin, apiBase].join('')
|
||||
|
||||
@ -144,7 +144,7 @@ export default {
|
||||
border-radius: 0 5px 5px 0;
|
||||
}
|
||||
|
||||
button {
|
||||
:deep(button) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
padding-left: 10px;
|
||||
@ -159,7 +159,7 @@ export default {
|
||||
border-radius: 5px 0 0 5px;
|
||||
}
|
||||
|
||||
button {
|
||||
:deep(button) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
padding-left: 12px;
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
<template>
|
||||
<a-tooltip placement="bottom">
|
||||
<template slot="title">
|
||||
<template #title>
|
||||
{{ name }}
|
||||
</template>
|
||||
<font-awesome-icon
|
||||
@ -27,6 +27,8 @@
|
||||
v-if="logo !== 'debian'" />
|
||||
<debian-icon
|
||||
v-else-if="logo === 'debian'"
|
||||
:width="size === '4x' ? 56 : 16"
|
||||
:height="size === '4x' ? 56 : 16"
|
||||
:style="{
|
||||
height: size === '4x' ? '56px' : '16px',
|
||||
width: size === '4x' ? '56px' : '16px',
|
||||
@ -74,8 +76,7 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
osId: function (newItem, oldItem) {
|
||||
this.osId = newItem
|
||||
osId: function () {
|
||||
this.fetchData()
|
||||
}
|
||||
},
|
||||
|
||||
@ -16,9 +16,9 @@
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<a-tooltip placement="bottom" :title="$t(getTooltip(text))">
|
||||
<a-tooltip placement="bottom" :title="getTooltip(text)">
|
||||
<a-badge
|
||||
style="display: inline-flex"
|
||||
:style="getStyle()"
|
||||
:title="text"
|
||||
:color="getStatusColor(text)"
|
||||
:status="getBadgeStatus(text)"
|
||||
@ -38,6 +38,10 @@ export default {
|
||||
displayText: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
styles: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -158,34 +162,50 @@ export default {
|
||||
},
|
||||
getTooltip (state) {
|
||||
if (!(state && this.displayText)) {
|
||||
return
|
||||
return ''
|
||||
}
|
||||
if (this.$route.path === '/vmsnapshot' || this.$route.path.includes('/vmsnapshot/')) {
|
||||
return 'message.vmsnapshot.state.' + state.toLowerCase()
|
||||
return this.$t('message.vmsnapshot.state.' + state.toLowerCase())
|
||||
}
|
||||
if (this.$route.path === '/vm' || this.$route.path.includes('/vm/')) {
|
||||
return 'message.vm.state.' + state.toLowerCase()
|
||||
return this.$t('message.vm.state.' + state.toLowerCase())
|
||||
}
|
||||
if (this.$route.path === '/volume' || this.$route.path.includes('/volume/')) {
|
||||
return 'message.volume.state.' + state.toLowerCase()
|
||||
return this.$t('message.volume.state.' + state.toLowerCase())
|
||||
}
|
||||
if (this.$route.path === '/guestnetwork' || this.$route.path.includes('/guestnetwork/')) {
|
||||
return 'message.guestnetwork.state.' + state.toLowerCase()
|
||||
return this.$t('message.guestnetwork.state.' + state.toLowerCase())
|
||||
}
|
||||
if (this.$route.path === '/publicip' || this.$route.path.includes('/publicip/')) {
|
||||
return 'message.publicip.state.' + state.toLowerCase()
|
||||
return this.$t('message.publicip.state.' + state.toLowerCase())
|
||||
}
|
||||
// Nothing for snapshots, vpcs, gateways, vnpnconn, vpnuser, kubectl, event, project, account, infra. They're all self explanatory
|
||||
return state
|
||||
return this.$t(state)
|
||||
},
|
||||
getStyle () {
|
||||
let styles = { display: 'inline-flex' }
|
||||
if (this.styles && typeof this.styles === 'object') {
|
||||
styles = Object.assign({}, styles, this.styles)
|
||||
}
|
||||
|
||||
return styles
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/deep/ .ant-badge-status-dot {
|
||||
<style scoped lang="less">
|
||||
:deep(.ant-badge-status-dot) {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-top: -5px;
|
||||
|
||||
&--end {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -17,31 +17,50 @@
|
||||
|
||||
<template>
|
||||
<a-tooltip arrowPointAtCenter :placement="tooltipPlacement">
|
||||
<template slot="title" v-if="tooltip">
|
||||
<template #title v-if="tooltip">
|
||||
{{ tooltip }}
|
||||
</template>
|
||||
<a-button
|
||||
style="margin-left: -5px"
|
||||
v-if="copyResource"
|
||||
shape="circle"
|
||||
:size="size"
|
||||
:type="type"
|
||||
:danger="danger"
|
||||
:disabled="disabled"
|
||||
:class="buttonClass"
|
||||
:loading="loading"
|
||||
@click="handleClicked()"
|
||||
v-clipboard:copy="copyResource" >
|
||||
<template #icon v-if="icon"><render-icon :icon="icon" /></template>
|
||||
<template v-if="iconType && iconTwoToneColor">
|
||||
<render-icon :icon="iconType" :props="{ theme: 'twoTone', twoToneColor: iconTwoToneColor }" />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button
|
||||
v-else
|
||||
shape="circle"
|
||||
:size="size"
|
||||
:type="type"
|
||||
:danger="danger"
|
||||
:disabled="disabled"
|
||||
:icon="icon"
|
||||
:class="buttonClass"
|
||||
:loading="loading"
|
||||
@click="handleClicked()" >
|
||||
<a-icon
|
||||
v-if="iconType && iconTwoToneColor"
|
||||
:type="iconType"
|
||||
theme="twoTone"
|
||||
:twoToneColor="iconTwoToneColor" />
|
||||
<template #icon v-if="icon"><render-icon :icon="icon" /></template>
|
||||
<template v-if="iconType && iconTwoToneColor">
|
||||
<render-icon :icon="iconType" :props="{ theme: 'twoTone', twoToneColor: iconTwoToneColor }" />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RenderIcon from '@/utils/renderIcon'
|
||||
|
||||
export default {
|
||||
name: 'TooltipButton',
|
||||
components: { RenderIcon },
|
||||
props: {
|
||||
tooltip: {
|
||||
type: String,
|
||||
@ -82,15 +101,19 @@ export default {
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
},
|
||||
copyResource: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
danger: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClicked () {
|
||||
this.$emit('click')
|
||||
this.$emit('onClick')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
<span>
|
||||
{{ title }}
|
||||
<a-tooltip v-if="tooltip" :title="tooltip" :placement="tooltipPlacement">
|
||||
<a-icon type="info-circle" class="tooltip-icon" />
|
||||
<info-circle-outlined class="tooltip-icon" />
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
@ -15,5 +15,5 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import Vue from 'vue'
|
||||
export default new Vue()
|
||||
import mitt from 'mitt'
|
||||
export default mitt()
|
||||
|
||||
@ -16,10 +16,12 @@
|
||||
// under the License.
|
||||
|
||||
// eslint-disable-next-line
|
||||
import { UserLayout, BasicLayout, RouteView, BlankLayout, PageView } from '@/layouts'
|
||||
import { UserLayout, BasicLayout, RouteView } from '@/layouts'
|
||||
import AutogenView from '@/views/AutogenView.vue'
|
||||
import IFramePlugin from '@/views/plugins/IFramePlugin.vue'
|
||||
import Vue from 'vue'
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import { vueProps } from '@/vue-app'
|
||||
|
||||
import compute from '@/config/section/compute'
|
||||
import storage from '@/config/section/storage'
|
||||
@ -46,11 +48,11 @@ function generateRouterMap (section) {
|
||||
meta: {
|
||||
title: section.title,
|
||||
icon: section.icon,
|
||||
docHelp: Vue.prototype.$applyDocHelpMappings(section.docHelp),
|
||||
docHelp: vueProps.$applyDocHelpMappings(section.docHelp),
|
||||
searchFilters: section.searchFilters,
|
||||
related: section.related
|
||||
},
|
||||
component: RouteView
|
||||
component: shallowRef(RouteView)
|
||||
}
|
||||
|
||||
if (section.children && section.children.length > 0) {
|
||||
@ -61,7 +63,7 @@ function generateRouterMap (section) {
|
||||
if ('show' in child && !child.show()) {
|
||||
continue
|
||||
}
|
||||
var component = child.component ? child.component : AutogenView
|
||||
var component = child.component ? child.component : shallowRef(AutogenView)
|
||||
var route = {
|
||||
name: child.name,
|
||||
path: '/' + child.name,
|
||||
@ -70,7 +72,7 @@ function generateRouterMap (section) {
|
||||
title: child.title,
|
||||
name: child.name,
|
||||
icon: child.icon,
|
||||
docHelp: Vue.prototype.$applyDocHelpMappings(child.docHelp),
|
||||
docHelp: vueProps.$applyDocHelpMappings(child.docHelp),
|
||||
permission: child.permission,
|
||||
resourceType: child.resourceType,
|
||||
filters: child.filters,
|
||||
@ -92,7 +94,7 @@ function generateRouterMap (section) {
|
||||
title: child.title,
|
||||
name: child.name,
|
||||
icon: child.icon,
|
||||
docHelp: Vue.prototype.$applyDocHelpMappings(child.docHelp),
|
||||
docHelp: vueProps.$applyDocHelpMappings(child.docHelp),
|
||||
permission: child.permission,
|
||||
resourceType: child.resourceType,
|
||||
params: child.params ? child.params : {},
|
||||
@ -128,7 +130,7 @@ function generateRouterMap (section) {
|
||||
map.children.push(route)
|
||||
}
|
||||
} else {
|
||||
map.component = section.component ? section.component : AutogenView
|
||||
map.component = section.component ? section.component : shallowRef(AutogenView)
|
||||
map.hideChildrenInMenu = true
|
||||
|
||||
map.meta.name = section.name
|
||||
@ -147,7 +149,7 @@ function generateRouterMap (section) {
|
||||
title: section.title,
|
||||
name: section.name,
|
||||
icon: section.icon,
|
||||
docHelp: Vue.prototype.$applyDocHelpMappings(section.docHelp),
|
||||
docHelp: vueProps.$applyDocHelpMappings(section.docHelp),
|
||||
hidden: section.hidden,
|
||||
permission: section.permission,
|
||||
resourceType: section.resourceType,
|
||||
@ -158,7 +160,7 @@ function generateRouterMap (section) {
|
||||
tabs: section.tabs,
|
||||
actions: section.actions ? section.actions : []
|
||||
},
|
||||
component: section.component ? section.component : AutogenView
|
||||
component: section.component ? section.component : shallowRef(AutogenView)
|
||||
}]
|
||||
}
|
||||
|
||||
@ -189,8 +191,8 @@ export function asyncRouterMap () {
|
||||
const routerMap = [{
|
||||
path: '/',
|
||||
name: 'index',
|
||||
component: BasicLayout,
|
||||
meta: { icon: 'home' },
|
||||
component: shallowRef(BasicLayout),
|
||||
meta: { icon: 'HomeOutlined' },
|
||||
redirect: '/dashboard',
|
||||
children: [
|
||||
{
|
||||
@ -198,16 +200,16 @@ export function asyncRouterMap () {
|
||||
name: 'dashboard',
|
||||
meta: {
|
||||
title: 'label.dashboard',
|
||||
icon: 'dashboard',
|
||||
icon: 'DashboardOutlined',
|
||||
tabs: [
|
||||
{
|
||||
name: 'dashboard',
|
||||
component: () => import('@/views/dashboard/UsageDashboardChart')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/dashboard/UsageDashboardChart')))
|
||||
},
|
||||
{
|
||||
name: 'accounts',
|
||||
show: (record, route, user) => { return record.account === user.account || ['Admin', 'DomainAdmin'].includes(user.roletype) },
|
||||
component: () => import('@/views/project/AccountsTab')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/project/AccountsTab')))
|
||||
},
|
||||
{
|
||||
name: 'limits',
|
||||
@ -215,7 +217,7 @@ export function asyncRouterMap () {
|
||||
projectid: 'id'
|
||||
},
|
||||
show: (record, route, user) => { return ['Admin'].includes(user.roletype) },
|
||||
component: () => import('@/components/view/ResourceLimitTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/ResourceLimitTab.vue')))
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -242,7 +244,7 @@ export function asyncRouterMap () {
|
||||
{
|
||||
path: '/exception',
|
||||
name: 'exception',
|
||||
component: RouteView,
|
||||
component: shallowRef(RouteView),
|
||||
hidden: true,
|
||||
redirect: '/exception/404',
|
||||
meta: { title: 'Exception', icon: 'warning' },
|
||||
@ -273,10 +275,10 @@ export function asyncRouterMap () {
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '*', redirect: '/exception/404', hidden: true
|
||||
path: '/:catchAll(.*)', redirect: '/exception/404', hidden: true
|
||||
}]
|
||||
|
||||
const plugins = Vue.prototype.$config.plugins
|
||||
const plugins = vueProps.$config.plugins
|
||||
if (plugins && plugins.length > 0) {
|
||||
plugins.map(plugin => {
|
||||
routerMap[0].children.push({
|
||||
|
||||
@ -15,12 +15,13 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'account',
|
||||
title: 'label.accounts',
|
||||
icon: 'team',
|
||||
icon: 'team-outlined',
|
||||
docHelp: 'adminguide/accounts.html',
|
||||
permission: ['listAccounts'],
|
||||
columns: ['name', 'state', 'rolename', 'roletype', 'domainpath'],
|
||||
@ -33,39 +34,39 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'resources',
|
||||
component: () => import('@/components/view/ResourceCountUsage.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/ResourceCountUsage.vue')))
|
||||
},
|
||||
{
|
||||
name: 'limits',
|
||||
show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) },
|
||||
component: () => import('@/components/view/ResourceLimitTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/ResourceLimitTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'certificate',
|
||||
component: () => import('@/views/iam/SSLCertificateTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/SSLCertificateTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'settings',
|
||||
component: () => import('@/components/view/SettingsTab.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/SettingsTab.vue'))),
|
||||
show: () => { return 'listConfigurations' in store.getters.apis }
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'createAccount',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.account',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/iam/AddAccount.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/AddAccount.vue')))
|
||||
},
|
||||
{
|
||||
api: 'ldapCreateAccount',
|
||||
icon: 'user-add',
|
||||
icon: 'user-add-outlined',
|
||||
label: 'label.add.ldap.account',
|
||||
docHelp: 'adminguide/accounts.html#using-an-ldap-server-for-user-authentication',
|
||||
listView: true,
|
||||
@ -73,11 +74,11 @@ export default {
|
||||
show: (record, store) => {
|
||||
return store.isLdapEnabled
|
||||
},
|
||||
component: () => import('@/views/iam/AddLdapAccount.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/AddLdapAccount.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateAccount',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.action.edit.account',
|
||||
dataView: true,
|
||||
args: ['newname', 'account', 'domainid', 'networkdomain'],
|
||||
@ -92,7 +93,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateResourceCount',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
label: 'label.action.update.resource.count',
|
||||
message: 'message.update.resource.count',
|
||||
dataView: true,
|
||||
@ -109,7 +110,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'enableAccount',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.action.enable.account',
|
||||
message: 'message.enable.account',
|
||||
dataView: true,
|
||||
@ -125,7 +126,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'disableAccount',
|
||||
icon: 'pause-circle',
|
||||
icon: 'pause-circle-outlined',
|
||||
label: 'label.action.disable.account',
|
||||
message: 'message.disable.account',
|
||||
dataView: true,
|
||||
@ -146,7 +147,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'disableAccount',
|
||||
icon: 'lock',
|
||||
icon: 'LockOutlined',
|
||||
label: 'label.action.lock.account',
|
||||
message: 'message.lock.account',
|
||||
dataView: true,
|
||||
@ -167,7 +168,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'uploadSslCert',
|
||||
icon: 'safety-certificate',
|
||||
icon: 'SafetyCertificateOutlined',
|
||||
label: 'label.add.certificate',
|
||||
dataView: true,
|
||||
args: ['name', 'certificate', 'privatekey', 'certchain', 'password', 'account', 'domainid'],
|
||||
@ -184,7 +185,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteAccount',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.account',
|
||||
message: 'message.delete.account',
|
||||
dataView: true,
|
||||
|
||||
@ -15,18 +15,19 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import kubernetes from '@/assets/icons/kubernetes.svg?inline'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'compute',
|
||||
title: 'label.compute',
|
||||
icon: 'cloud',
|
||||
icon: 'cloud-outlined',
|
||||
children: [
|
||||
{
|
||||
name: 'vm',
|
||||
title: 'label.instances',
|
||||
icon: 'desktop',
|
||||
icon: 'desktop-outlined',
|
||||
docHelp: 'adminguide/virtual_machines.html',
|
||||
permission: ['listVirtualMachinesMetrics'],
|
||||
resourceType: 'UserVm',
|
||||
@ -68,12 +69,12 @@ export default {
|
||||
searchFilters: ['name', 'zoneid', 'domainid', 'account', 'tags'],
|
||||
details: ['displayname', 'name', 'id', 'state', 'ipaddress', 'ip6address', 'templatename', 'ostypename', 'serviceofferingname', 'isdynamicallyscalable', 'haenable', 'hypervisor', 'boottype', 'bootmode', 'account', 'domain', 'zonename'],
|
||||
tabs: [{
|
||||
component: () => import('@/views/compute/InstanceTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/InstanceTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'deployVirtualMachine',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.vm.add',
|
||||
docHelp: 'adminguide/virtual_machines.html#creating-vms',
|
||||
listView: true,
|
||||
@ -81,16 +82,16 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateVirtualMachine',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.action.edit.instance',
|
||||
docHelp: 'adminguide/virtual_machines.html#changing-the-vm-name-os-or-group',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/compute/EditVM.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/EditVM.vue')))
|
||||
},
|
||||
{
|
||||
api: 'startVirtualMachine',
|
||||
icon: 'caret-right',
|
||||
icon: 'caret-right-outlined',
|
||||
label: 'label.action.start.instance',
|
||||
message: 'message.action.start.instance',
|
||||
docHelp: 'adminguide/virtual_machines.html#stopping-and-starting-vms',
|
||||
@ -99,11 +100,11 @@ export default {
|
||||
popup: true,
|
||||
groupMap: (selection) => { return selection.map(x => { return { id: x } }) },
|
||||
show: (record) => { return ['Stopped'].includes(record.state) },
|
||||
component: () => import('@/views/compute/StartVirtualMachine.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/StartVirtualMachine.vue')))
|
||||
},
|
||||
{
|
||||
api: 'stopVirtualMachine',
|
||||
icon: 'poweroff',
|
||||
icon: 'poweroff-outlined',
|
||||
label: 'label.action.stop.instance',
|
||||
message: 'message.action.stop.instance',
|
||||
docHelp: 'adminguide/virtual_machines.html#stopping-and-starting-vms',
|
||||
@ -115,7 +116,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'rebootVirtualMachine',
|
||||
icon: 'reload',
|
||||
icon: 'reload-outlined',
|
||||
label: 'label.action.reboot.instance',
|
||||
message: 'message.action.reboot.instance',
|
||||
docHelp: 'adminguide/virtual_machines.html#stopping-and-starting-vms',
|
||||
@ -137,7 +138,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'restoreVirtualMachine',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
label: 'label.reinstall.vm',
|
||||
message: 'message.reinstall.vm',
|
||||
dataView: true,
|
||||
@ -162,7 +163,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'createVMSnapshot',
|
||||
icon: 'camera',
|
||||
icon: 'camera-outlined',
|
||||
label: 'label.action.vmsnapshot.create',
|
||||
docHelp: 'adminguide/virtual_machines.html#virtual-machine-snapshots',
|
||||
dataView: true,
|
||||
@ -189,11 +190,11 @@ export default {
|
||||
return ((['Running'].includes(record.state) && record.hypervisor !== 'LXC') ||
|
||||
(['Stopped'].includes(record.state) && !['KVM', 'LXC'].includes(record.hypervisor)))
|
||||
},
|
||||
component: () => import('@/views/compute/CreateSnapshotWizard.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/CreateSnapshotWizard.vue')))
|
||||
},
|
||||
{
|
||||
api: 'assignVirtualMachineToBackupOffering',
|
||||
icon: 'folder-add',
|
||||
icon: 'folder-add-outlined',
|
||||
label: 'label.backup.offering.assign',
|
||||
message: 'label.backup.offering.assign',
|
||||
docHelp: 'adminguide/virtual_machines.html#backup-offerings',
|
||||
@ -208,7 +209,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'createBackup',
|
||||
icon: 'cloud-upload',
|
||||
icon: 'cloud-upload-outlined',
|
||||
label: 'label.create.backup',
|
||||
message: 'message.backup.create',
|
||||
docHelp: 'adminguide/virtual_machines.html#creating-vm-backups',
|
||||
@ -223,13 +224,13 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'createBackupSchedule',
|
||||
icon: 'schedule',
|
||||
icon: 'schedule-outlined',
|
||||
label: 'Configure Backup Schedule',
|
||||
docHelp: 'adminguide/virtual_machines.html#creating-vm-backups',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
show: (record) => { return record.backupofferingid },
|
||||
component: () => import('@/views/compute/BackupScheduleWizard.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/BackupScheduleWizard.vue'))),
|
||||
mapping: {
|
||||
virtualmachineid: {
|
||||
value: (record, params) => { return record.id }
|
||||
@ -241,7 +242,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'removeVirtualMachineFromBackupOffering',
|
||||
icon: 'scissor',
|
||||
icon: 'scissor-outlined',
|
||||
label: 'label.backup.offering.remove',
|
||||
message: 'label.backup.offering.remove',
|
||||
docHelp: 'adminguide/virtual_machines.html#restoring-vm-backups',
|
||||
@ -256,17 +257,17 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'attachIso',
|
||||
icon: 'paper-clip',
|
||||
icon: 'paper-clip-outlined',
|
||||
label: 'label.action.attach.iso',
|
||||
docHelp: 'adminguide/templates.html#attaching-an-iso-to-a-vm',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
show: (record) => { return ['Running', 'Stopped'].includes(record.state) && !record.isoid },
|
||||
component: () => import('@/views/compute/AttachIso.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/AttachIso.vue')))
|
||||
},
|
||||
{
|
||||
api: 'detachIso',
|
||||
icon: 'link',
|
||||
icon: 'link-outlined',
|
||||
label: 'label.action.detach.iso',
|
||||
message: 'message.detach.iso.confirm',
|
||||
dataView: true,
|
||||
@ -286,50 +287,50 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateVMAffinityGroup',
|
||||
icon: 'swap',
|
||||
icon: 'swap-outlined',
|
||||
label: 'label.change.affinity',
|
||||
docHelp: 'adminguide/virtual_machines.html#change-affinity-group-for-an-existing-vm',
|
||||
dataView: true,
|
||||
args: ['affinitygroupids'],
|
||||
show: (record) => { return ['Stopped'].includes(record.state) },
|
||||
component: () => import('@/views/compute/ChangeAffinity'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ChangeAffinity'))),
|
||||
popup: true
|
||||
},
|
||||
{
|
||||
api: 'scaleVirtualMachine',
|
||||
icon: 'arrows-alt',
|
||||
icon: 'arrows-alt-outlined',
|
||||
label: 'label.scale.vm',
|
||||
docHelp: 'adminguide/virtual_machines.html#how-to-dynamically-scale-cpu-and-ram',
|
||||
dataView: true,
|
||||
show: (record) => { return ['Stopped'].includes(record.state) || (['Running'].includes(record.state) && record.hypervisor !== 'LXC') },
|
||||
disabled: (record) => { return record.state === 'Running' && !record.isdynamicallyscalable },
|
||||
popup: true,
|
||||
component: () => import('@/views/compute/ScaleVM.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ScaleVM.vue')))
|
||||
},
|
||||
{
|
||||
api: 'migrateVirtualMachine',
|
||||
icon: 'drag',
|
||||
icon: 'drag-outlined',
|
||||
label: 'label.migrate.instance.to.host',
|
||||
docHelp: 'adminguide/virtual_machines.html#moving-vms-between-hosts-manual-live-migration',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Running'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
|
||||
popup: true,
|
||||
component: () => import('@/views/compute/MigrateWizard')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateWizard.vue')))
|
||||
},
|
||||
{
|
||||
api: 'migrateVirtualMachine',
|
||||
icon: 'drag',
|
||||
icon: 'drag-outlined',
|
||||
label: 'label.migrate.instance.to.ps',
|
||||
message: 'message.migrate.instance.to.ps',
|
||||
docHelp: 'adminguide/virtual_machines.html#moving-vms-between-hosts-manual-live-migration',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Stopped'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
|
||||
component: () => import('@/views/compute/MigrateVMStorage'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateVMStorage'))),
|
||||
popup: true
|
||||
},
|
||||
{
|
||||
api: 'resetPasswordForVirtualMachine',
|
||||
icon: 'key',
|
||||
icon: 'key-outlined',
|
||||
label: 'label.action.reset.password',
|
||||
message: 'message.action.instance.reset.password',
|
||||
dataView: true,
|
||||
@ -338,27 +339,27 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'resetSSHKeyForVirtualMachine',
|
||||
icon: 'lock',
|
||||
icon: 'lock-outlined',
|
||||
label: 'label.reset.ssh.key.pair',
|
||||
message: 'message.desc.reset.ssh.key.pair',
|
||||
docHelp: 'adminguide/virtual_machines.html#resetting-ssh-keys',
|
||||
dataView: true,
|
||||
show: (record) => { return ['Stopped'].includes(record.state) },
|
||||
popup: true,
|
||||
component: () => import('@/views/compute/ResetSshKeyPair')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ResetSshKeyPair')))
|
||||
},
|
||||
{
|
||||
api: 'assignVirtualMachine',
|
||||
icon: 'user-add',
|
||||
icon: 'user-add-outlined',
|
||||
label: 'label.assign.instance.another',
|
||||
dataView: true,
|
||||
component: () => import('@/views/compute/AssignInstance'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/AssignInstance'))),
|
||||
popup: true,
|
||||
show: (record) => { return ['Stopped'].includes(record.state) }
|
||||
},
|
||||
{
|
||||
api: 'recoverVirtualMachine',
|
||||
icon: 'medicine-box',
|
||||
icon: 'medicine-box-outlined',
|
||||
label: 'label.recover.vm',
|
||||
message: 'message.recover.vm',
|
||||
dataView: true,
|
||||
@ -366,7 +367,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'unmanageVirtualMachine',
|
||||
icon: 'disconnect',
|
||||
icon: 'disconnect-outlined',
|
||||
label: 'label.action.unmanage.virtualmachine',
|
||||
message: 'message.action.unmanage.virtualmachine',
|
||||
dataView: true,
|
||||
@ -374,7 +375,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'expungeVirtualMachine',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.expunge.instance',
|
||||
message: (record) => { return record.backupofferingid ? 'message.action.expunge.instance.with.backups' : 'message.action.expunge.instance' },
|
||||
docHelp: 'adminguide/virtual_machines.html#deleting-vms',
|
||||
@ -383,7 +384,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'destroyVirtualMachine',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.destroy.instance',
|
||||
message: 'message.action.destroy.instance',
|
||||
docHelp: 'adminguide/virtual_machines.html#deleting-vms',
|
||||
@ -396,14 +397,14 @@ export default {
|
||||
popup: true,
|
||||
groupMap: (selection, values) => { return selection.map(x => { return { id: x, expunge: values.expunge } }) },
|
||||
show: (record) => { return ['Running', 'Stopped', 'Error'].includes(record.state) },
|
||||
component: () => import('@/views/compute/DestroyVM.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/DestroyVM.vue')))
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'kubernetes',
|
||||
title: 'label.kubernetes',
|
||||
icon: kubernetes,
|
||||
icon: shallowRef(kubernetes),
|
||||
docHelp: 'plugins/cloudstack-kubernetes-service.html',
|
||||
permission: ['listKubernetesClusters'],
|
||||
columns: (store) => {
|
||||
@ -420,22 +421,22 @@ export default {
|
||||
details: ['name', 'description', 'zonename', 'kubernetesversionname', 'autoscalingenabled', 'minsize', 'maxsize', 'size', 'controlnodes', 'cpunumber', 'memory', 'keypair', 'associatednetworkname', 'account', 'domain', 'zonename'],
|
||||
tabs: [{
|
||||
name: 'k8s',
|
||||
component: () => import('@/views/compute/KubernetesServiceTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/KubernetesServiceTab.vue')))
|
||||
}],
|
||||
resourceType: 'KubernetesCluster',
|
||||
actions: [
|
||||
{
|
||||
api: 'createKubernetesCluster',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.kubernetes.cluster.create',
|
||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#creating-a-new-kubernetes-cluster',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/compute/CreateKubernetesCluster.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/CreateKubernetesCluster.vue')))
|
||||
},
|
||||
{
|
||||
api: 'startKubernetesCluster',
|
||||
icon: 'caret-right',
|
||||
icon: 'caret-right-outlined',
|
||||
label: 'label.kubernetes.cluster.start',
|
||||
message: 'message.kubernetes.cluster.start',
|
||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#starting-a-stopped-kubernetes-cluster',
|
||||
@ -447,7 +448,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'stopKubernetesCluster',
|
||||
icon: 'poweroff',
|
||||
icon: 'poweroff-outlined',
|
||||
label: 'label.kubernetes.cluster.stop',
|
||||
message: 'message.kubernetes.cluster.stop',
|
||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#stopping-kubernetes-cluster',
|
||||
@ -459,29 +460,29 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'scaleKubernetesCluster',
|
||||
icon: 'swap',
|
||||
icon: 'swap-outlined',
|
||||
label: 'label.kubernetes.cluster.scale',
|
||||
message: 'message.kubernetes.cluster.scale',
|
||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#scaling-kubernetes-cluster',
|
||||
dataView: true,
|
||||
show: (record) => { return ['Created', 'Running'].includes(record.state) },
|
||||
popup: true,
|
||||
component: () => import('@/views/compute/ScaleKubernetesCluster.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ScaleKubernetesCluster.vue')))
|
||||
},
|
||||
{
|
||||
api: 'upgradeKubernetesCluster',
|
||||
icon: 'plus-circle',
|
||||
icon: 'plus-circle-outlined',
|
||||
label: 'label.kubernetes.cluster.upgrade',
|
||||
message: 'message.kubernetes.cluster.upgrade',
|
||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#upgrading-kubernetes-cluster',
|
||||
dataView: true,
|
||||
show: (record) => { return ['Created', 'Running'].includes(record.state) },
|
||||
popup: true,
|
||||
component: () => import('@/views/compute/UpgradeKubernetesCluster.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/UpgradeKubernetesCluster.vue')))
|
||||
},
|
||||
{
|
||||
api: 'deleteKubernetesCluster',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.kubernetes.cluster.delete',
|
||||
message: 'message.kubernetes.cluster.delete',
|
||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#deleting-kubernetes-cluster',
|
||||
@ -496,7 +497,7 @@ export default {
|
||||
{
|
||||
name: 'vmgroup',
|
||||
title: 'label.instance.groups',
|
||||
icon: 'gold',
|
||||
icon: 'gold-outlined',
|
||||
docHelp: 'adminguide/virtual_machines.html#changing-the-vm-name-os-or-group',
|
||||
resourceType: 'VMInstanceGroup',
|
||||
permission: ['listInstanceGroups'],
|
||||
@ -510,31 +511,31 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'createInstanceGroup',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.new.instance.group',
|
||||
listView: true,
|
||||
args: ['name']
|
||||
},
|
||||
{
|
||||
api: 'updateInstanceGroup',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.update.instance.group',
|
||||
dataView: true,
|
||||
args: ['name']
|
||||
},
|
||||
{
|
||||
api: 'deleteInstanceGroup',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.instance.group',
|
||||
message: 'message.action.delete.instance.group',
|
||||
dataView: true,
|
||||
@ -547,7 +548,7 @@ export default {
|
||||
{
|
||||
name: 'ssh',
|
||||
title: 'label.ssh.key.pairs',
|
||||
icon: 'key',
|
||||
icon: 'key-outlined',
|
||||
docHelp: 'adminguide/virtual_machines.html#using-ssh-keys-for-authentication',
|
||||
permission: ['listSSHKeyPairs'],
|
||||
columns: () => {
|
||||
@ -567,26 +568,26 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'createSSHKeyPair',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.create.ssh.key.pair',
|
||||
docHelp: 'adminguide/virtual_machines.html#creating-the-ssh-keypair',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/compute/CreateSSHKeyPair.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/CreateSSHKeyPair.vue')))
|
||||
},
|
||||
{
|
||||
api: 'deleteSSHKeyPair',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.remove.ssh.key.pair',
|
||||
message: 'message.please.confirm.remove.ssh.key.pair',
|
||||
dataView: true,
|
||||
@ -618,7 +619,7 @@ export default {
|
||||
{
|
||||
name: 'affinitygroup',
|
||||
title: 'label.affinity.groups',
|
||||
icon: 'swap',
|
||||
icon: 'swap-outlined',
|
||||
docHelp: 'adminguide/virtual_machines.html#affinity-groups',
|
||||
permission: ['listAffinityGroups'],
|
||||
columns: () => {
|
||||
@ -637,7 +638,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'createAffinityGroup',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.affinity.group',
|
||||
docHelp: 'adminguide/virtual_machines.html#creating-a-new-affinity-group',
|
||||
listView: true,
|
||||
@ -650,7 +651,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteAffinityGroup',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.affinity.group',
|
||||
docHelp: 'adminguide/virtual_machines.html#delete-an-affinity-group',
|
||||
message: 'message.delete.affinity.group',
|
||||
|
||||
@ -18,27 +18,27 @@
|
||||
export default {
|
||||
name: 'config',
|
||||
title: 'label.configuration',
|
||||
icon: 'setting',
|
||||
icon: 'setting-outlined',
|
||||
permission: ['listConfigurations', 'listInfrastructure'],
|
||||
children: [
|
||||
{
|
||||
name: 'globalsetting',
|
||||
title: 'label.global.settings',
|
||||
icon: 'setting',
|
||||
icon: 'setting-outlined',
|
||||
permission: ['listConfigurations'],
|
||||
columns: ['name', 'description', 'category', 'value', 'actions']
|
||||
},
|
||||
{
|
||||
name: 'ldapsetting',
|
||||
title: 'label.ldap.configuration',
|
||||
icon: 'team',
|
||||
icon: 'team-outlined',
|
||||
permission: ['listLdapConfigurations'],
|
||||
columns: ['hostname', 'port', 'domainid'],
|
||||
details: ['hostname', 'port', 'domainid'],
|
||||
actions: [
|
||||
{
|
||||
api: 'addLdapConfiguration',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.configure.ldap',
|
||||
listView: true,
|
||||
args: [
|
||||
@ -47,7 +47,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteLdapConfiguration',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.remove.ldap',
|
||||
message: 'message.remove.ldap',
|
||||
dataView: true,
|
||||
@ -69,14 +69,14 @@ export default {
|
||||
{
|
||||
name: 'hypervisorcapability',
|
||||
title: 'label.hypervisor.capabilities',
|
||||
icon: 'database',
|
||||
icon: 'database-outlined',
|
||||
permission: ['listHypervisorCapabilities'],
|
||||
columns: ['hypervisor', 'hypervisorversion', 'maxguestslimit', 'maxhostspercluster'],
|
||||
details: ['hypervisor', 'hypervisorversion', 'maxguestslimit', 'maxdatavolumeslimit', 'maxhostspercluster', 'securitygroupenabled', 'storagemotionenabled'],
|
||||
actions: [
|
||||
{
|
||||
api: 'updateHypervisorCapabilities',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['maxguestslimit']
|
||||
|
||||
@ -15,18 +15,19 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'domain',
|
||||
title: 'label.domains',
|
||||
icon: 'block',
|
||||
icon: 'BlockOutlined',
|
||||
docHelp: 'adminguide/accounts.html#domains',
|
||||
permission: ['listDomains', 'listDomainChildren'],
|
||||
resourceType: 'Domain',
|
||||
columns: ['name', 'state', 'path', 'parentdomainname', 'level'],
|
||||
details: ['name', 'id', 'path', 'parentdomainname', 'level', 'networkdomain', 'created'],
|
||||
component: () => import('@/views/iam/DomainView.vue'),
|
||||
component: shallowRef(() => import('@/views/iam/DomainView.vue')),
|
||||
related: [{
|
||||
name: 'account',
|
||||
title: 'label.accounts',
|
||||
@ -35,37 +36,37 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'domain',
|
||||
component: () => import('@/components/view/InfoCard.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/InfoCard.vue'))),
|
||||
show: (record, route) => { return route.path === '/domain' }
|
||||
},
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'resources',
|
||||
show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) },
|
||||
component: () => import('@/components/view/ResourceCountUsage.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/ResourceCountUsage.vue')))
|
||||
},
|
||||
{
|
||||
name: 'limits',
|
||||
show: (record, route, user) => { return ['Admin'].includes(user.roletype) || (['DomainAdmin'].includes(user.roletype) && record.id !== user.domainid) },
|
||||
component: () => import('@/components/view/ResourceLimitTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/ResourceLimitTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'settings',
|
||||
component: () => import('@/components/view/SettingsTab.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/SettingsTab.vue'))),
|
||||
show: () => { return 'listConfigurations' in store.getters.apis }
|
||||
}, {
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
treeView: true,
|
||||
actions: [
|
||||
{
|
||||
api: 'createDomain',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.domain',
|
||||
listView: true,
|
||||
dataView: false,
|
||||
@ -78,7 +79,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateDomain',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.action.edit.domain',
|
||||
listView: true,
|
||||
dataView: true,
|
||||
@ -96,7 +97,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateResourceCount',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
label: 'label.action.update.resource.count',
|
||||
message: 'message.update.resource.count.domain',
|
||||
listView: true,
|
||||
@ -110,7 +111,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'linkDomainToLdap',
|
||||
icon: 'link',
|
||||
icon: 'LinkOutlined',
|
||||
label: 'label.link.domain.to.ldap',
|
||||
docHelp: 'adminguide/accounts.html#using-an-ldap-server-for-user-authentication',
|
||||
listView: true,
|
||||
@ -130,7 +131,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteDomain',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.domain',
|
||||
listView: true,
|
||||
dataView: true,
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
export default {
|
||||
name: 'event',
|
||||
title: 'label.events',
|
||||
icon: 'schedule',
|
||||
icon: 'ScheduleOutlined',
|
||||
docHelp: 'adminguide/events.html',
|
||||
permission: ['listEvents'],
|
||||
columns: ['level', 'type', 'state', 'description', 'username', 'account', 'domain', 'created'],
|
||||
@ -32,7 +32,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'archiveEvents',
|
||||
icon: 'book',
|
||||
icon: 'book-outlined',
|
||||
label: 'label.archive.events',
|
||||
message: 'message.confirm.archive.selected.events',
|
||||
docHelp: 'adminguide/events.html#deleting-and-archiving-events-and-alerts',
|
||||
@ -49,7 +49,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteEvents',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.events',
|
||||
message: 'message.confirm.remove.selected.events',
|
||||
docHelp: 'adminguide/events.html#deleting-and-archiving-events-and-alerts',
|
||||
|
||||
@ -15,19 +15,20 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import kubernetes from '@/assets/icons/kubernetes.svg?inline'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'image',
|
||||
title: 'label.images',
|
||||
icon: 'picture',
|
||||
icon: 'picture-outlined',
|
||||
docHelp: 'adminguide/templates.html',
|
||||
children: [
|
||||
{
|
||||
name: 'template',
|
||||
title: 'label.templates',
|
||||
icon: 'save',
|
||||
icon: 'save-outlined',
|
||||
docHelp: 'adminguide/templates.html',
|
||||
permission: ['listTemplates'],
|
||||
params: { templatefilter: 'self', showunique: 'true' },
|
||||
@ -60,40 +61,40 @@ export default {
|
||||
}],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'zones',
|
||||
component: () => import('@/views/image/TemplateZones.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/TemplateZones.vue')))
|
||||
}, {
|
||||
name: 'settings',
|
||||
component: () => import('@/components/view/DetailSettings')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailSettings')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'registerTemplate',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.action.register.template',
|
||||
docHelp: 'adminguide/templates.html#uploading-templates-from-a-remote-http-server',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/image/RegisterOrUploadTemplate.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/RegisterOrUploadTemplate.vue')))
|
||||
},
|
||||
{
|
||||
api: 'registerTemplate',
|
||||
icon: 'cloud-upload',
|
||||
icon: 'cloud-upload-outlined',
|
||||
label: 'label.upload.template.from.local',
|
||||
docHelp: 'adminguide/templates.html#uploading-templates-and-isos-from-a-local-computer',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/image/RegisterOrUploadTemplate.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/RegisterOrUploadTemplate.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateTemplate',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
show: (record, store) => {
|
||||
@ -103,11 +104,11 @@ export default {
|
||||
record.isready
|
||||
},
|
||||
popup: true,
|
||||
component: () => import('@/views/image/UpdateTemplate.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/UpdateTemplate.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateTemplatePermissions',
|
||||
icon: 'share-alt',
|
||||
icon: 'share-alt-outlined',
|
||||
label: 'label.action.template.share',
|
||||
dataView: true,
|
||||
args: (record, store) => {
|
||||
@ -127,7 +128,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'extractTemplate',
|
||||
icon: 'cloud-download',
|
||||
icon: 'cloud-download-outlined',
|
||||
label: 'label.action.download.template',
|
||||
message: 'message.action.download.template',
|
||||
docHelp: 'adminguide/templates.html#exporting-templates',
|
||||
@ -153,7 +154,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateTemplatePermissions',
|
||||
icon: 'reconciliation',
|
||||
icon: 'reconciliation-outlined',
|
||||
label: 'label.action.template.permission',
|
||||
docHelp: 'adminguide/templates.html#sharing-templates-with-other-accounts-projects',
|
||||
dataView: true,
|
||||
@ -165,14 +166,14 @@ export default {
|
||||
record.templatetype !== 'SYSTEM' &&
|
||||
record.isready
|
||||
},
|
||||
component: () => import('@/views/image/UpdateTemplateIsoPermissions')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/UpdateTemplateIsoPermissions')))
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'iso',
|
||||
title: 'label.isos',
|
||||
icon: 'usb',
|
||||
icon: 'usb-outlined',
|
||||
docHelp: 'adminguide/templates.html#working-with-isos',
|
||||
permission: ['listIsos'],
|
||||
params: { isofilter: 'self', showunique: 'true' },
|
||||
@ -197,37 +198,37 @@ export default {
|
||||
}],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'zones',
|
||||
component: () => import('@/views/image/IsoZones.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/IsoZones.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'registerIso',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.action.register.iso',
|
||||
docHelp: 'adminguide/templates.html#id10',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/image/RegisterOrUploadIso.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/RegisterOrUploadIso.vue')))
|
||||
},
|
||||
{
|
||||
api: 'registerIso',
|
||||
icon: 'cloud-upload',
|
||||
icon: 'cloud-upload-outlined',
|
||||
label: 'label.upload.iso.from.local',
|
||||
docHelp: 'adminguide/templates.html#id10',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/image/RegisterOrUploadIso.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/RegisterOrUploadIso.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateIso',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.action.edit.iso',
|
||||
dataView: true,
|
||||
show: (record, store) => {
|
||||
@ -241,7 +242,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateIsoPermissions',
|
||||
icon: 'share-alt',
|
||||
icon: 'share-alt-outlined',
|
||||
label: 'label.action.iso.share',
|
||||
dataView: true,
|
||||
args: (record, store) => {
|
||||
@ -261,7 +262,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'extractIso',
|
||||
icon: 'cloud-download',
|
||||
icon: 'cloud-download-outlined',
|
||||
label: 'label.action.download.iso',
|
||||
message: 'message.action.download.iso',
|
||||
docHelp: 'adminguide/templates.html#exporting-templates',
|
||||
@ -286,7 +287,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateIsoPermissions',
|
||||
icon: 'reconciliation',
|
||||
icon: 'reconciliation-outlined',
|
||||
label: 'label.action.iso.permission',
|
||||
docHelp: 'adminguide/templates.html#sharing-templates-with-other-accounts-projects',
|
||||
dataView: true,
|
||||
@ -299,14 +300,14 @@ export default {
|
||||
!(record.account === 'system' && record.domainid === 1) &&
|
||||
record.isready
|
||||
},
|
||||
component: () => import('@/views/image/UpdateTemplateIsoPermissions')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/UpdateTemplateIsoPermissions')))
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'kubernetesiso',
|
||||
title: 'label.kubernetes.isos',
|
||||
icon: kubernetes,
|
||||
icon: shallowRef(kubernetes),
|
||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#kubernetes-supported-versions',
|
||||
permission: ['listKubernetesSupportedVersions'],
|
||||
columns: ['name', 'state', 'semanticversion', 'isostate', 'mincpunumber', 'minmemory', 'zonename'],
|
||||
@ -314,23 +315,23 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'addKubernetesSupportedVersion',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.kubernetes.version.add',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/image/AddKubernetesSupportedVersion.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/AddKubernetesSupportedVersion.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateKubernetesSupportedVersion',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.kubernetes.version.update',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/image/UpdateKubernetesSupportedVersion.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/UpdateKubernetesSupportedVersion.vue')))
|
||||
},
|
||||
{
|
||||
api: 'deleteKubernetesSupportedVersion',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.kubernetes.version.delete',
|
||||
message: 'message.kubernetes.version.delete',
|
||||
dataView: true
|
||||
|
||||
@ -30,13 +30,13 @@ import ilbvms from '@/config/section/infra/ilbvms'
|
||||
export default {
|
||||
name: 'infra',
|
||||
title: 'label.infrastructure',
|
||||
icon: 'bank',
|
||||
icon: 'BankOutlined',
|
||||
permission: ['listInfrastructure'],
|
||||
children: [
|
||||
{
|
||||
name: 'infrasummary',
|
||||
title: 'label.summary',
|
||||
icon: 'read',
|
||||
icon: 'ReadOutlined',
|
||||
permission: ['listInfrastructure'],
|
||||
component: () => import('@/views/infra/InfraSummary.vue')
|
||||
},
|
||||
@ -54,7 +54,7 @@ export default {
|
||||
{
|
||||
name: 'cpusocket',
|
||||
title: 'label.cpu.sockets',
|
||||
icon: 'inbox',
|
||||
icon: 'InboxOutlined',
|
||||
docHelp: 'adminguide/management.html#reporting-cpu-sockets',
|
||||
permission: ['listHosts'],
|
||||
component: () => import('@/views/infra/CpuSockets.vue')
|
||||
@ -62,14 +62,14 @@ export default {
|
||||
{
|
||||
name: 'managementserver',
|
||||
title: 'label.management.servers',
|
||||
icon: 'rocket',
|
||||
icon: 'RocketOutlined',
|
||||
permission: ['listManagementServers'],
|
||||
columns: ['name', 'state', 'version']
|
||||
},
|
||||
{
|
||||
name: 'alert',
|
||||
title: 'label.alerts',
|
||||
icon: 'flag',
|
||||
icon: 'FlagOutlined',
|
||||
docHelp: 'adminguide/management.html#administrator-alerts',
|
||||
permission: ['listAlerts'],
|
||||
columns: ['name', 'description', 'type', 'sent'],
|
||||
@ -77,7 +77,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'archiveAlerts',
|
||||
icon: 'book',
|
||||
icon: 'book-outlined',
|
||||
label: 'label.archive.alerts',
|
||||
message: 'message.confirm.archive.selected.alerts',
|
||||
docHelp: 'adminguide/events.html#deleting-and-archiving-events-and-alerts',
|
||||
@ -93,7 +93,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteAlerts',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.alerts',
|
||||
message: 'message.confirm.remove.selected.alerts',
|
||||
docHelp: 'adminguide/events.html#deleting-and-archiving-events-and-alerts',
|
||||
|
||||
@ -15,12 +15,13 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'cluster',
|
||||
title: 'label.clusters',
|
||||
icon: 'cluster',
|
||||
icon: 'cluster-outlined',
|
||||
permission: ['listClustersMetrics'],
|
||||
columns: () => {
|
||||
const fields = ['name', 'state', 'allocationstate', 'clustertype', 'hypervisortype', 'hosts']
|
||||
@ -41,37 +42,37 @@ export default {
|
||||
resourceType: 'Cluster',
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'resources',
|
||||
component: () => import('@/views/infra/Resources.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/Resources.vue')))
|
||||
}, {
|
||||
name: 'settings',
|
||||
component: () => import('@/components/view/SettingsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/SettingsTab.vue')))
|
||||
}, {
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'addCluster',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.cluster',
|
||||
docHelp: 'adminguide/installguide/configuration.html#adding-a-cluster',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/infra/ClusterAdd.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/ClusterAdd.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateCluster',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['clustername']
|
||||
},
|
||||
{
|
||||
api: 'updateCluster',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.action.enable.cluster',
|
||||
message: 'message.action.enable.cluster',
|
||||
docHelp: 'adminguide/installguide/hosts.html#disabling-and-enabling-zones-pods-and-clusters',
|
||||
@ -81,7 +82,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateCluster',
|
||||
icon: 'pause-circle',
|
||||
icon: 'pause-circle-outlined',
|
||||
label: 'label.action.disable.cluster',
|
||||
message: 'message.action.disable.cluster',
|
||||
docHelp: 'adminguide/installguide/hosts.html#disabling-and-enabling-zones-pods-and-clusters',
|
||||
@ -91,7 +92,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateCluster',
|
||||
icon: 'plus-square',
|
||||
icon: 'plus-square-outlined',
|
||||
label: 'label.action.manage.cluster',
|
||||
message: 'message.action.manage.cluster',
|
||||
dataView: true,
|
||||
@ -100,7 +101,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateCluster',
|
||||
icon: 'minus-square',
|
||||
icon: 'minus-square-outlined',
|
||||
label: 'label.action.unmanage.cluster',
|
||||
message: 'message.action.unmanage.cluster',
|
||||
dataView: true,
|
||||
@ -109,7 +110,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'enableOutOfBandManagementForCluster',
|
||||
icon: 'plus-circle',
|
||||
icon: 'plus-circle-outlined',
|
||||
label: 'label.outofbandmanagement.enable',
|
||||
message: 'label.outofbandmanagement.enable',
|
||||
dataView: true,
|
||||
@ -125,7 +126,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'disableOutOfBandManagementForCluster',
|
||||
icon: 'minus-circle',
|
||||
icon: 'minus-circle-outlined',
|
||||
label: 'label.outofbandmanagement.disable',
|
||||
message: 'label.outofbandmanagement.disable',
|
||||
dataView: true,
|
||||
@ -141,7 +142,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'enableHAForCluster',
|
||||
icon: 'eye',
|
||||
icon: 'eye-outlined',
|
||||
label: 'label.ha.enable',
|
||||
message: 'label.ha.enable',
|
||||
dataView: true,
|
||||
@ -157,7 +158,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'disableHAForCluster',
|
||||
icon: 'eye-invisible',
|
||||
icon: 'eye-invisible-outlined',
|
||||
label: 'label.ha.disable',
|
||||
message: 'label.ha.disable',
|
||||
dataView: true,
|
||||
@ -173,7 +174,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'startRollingMaintenance',
|
||||
icon: 'setting',
|
||||
icon: 'setting-outlined',
|
||||
label: 'label.start.rolling.maintenance',
|
||||
message: 'label.start.rolling.maintenance',
|
||||
dataView: true,
|
||||
@ -186,7 +187,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteCluster',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.cluster',
|
||||
message: 'message.action.delete.cluster',
|
||||
dataView: true
|
||||
|
||||
@ -15,12 +15,13 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'host',
|
||||
title: 'label.hosts',
|
||||
icon: 'desktop',
|
||||
icon: 'desktop-outlined',
|
||||
permission: ['listHostsMetrics'],
|
||||
resourceType: 'Host',
|
||||
params: { type: 'routing' },
|
||||
@ -37,10 +38,10 @@ export default {
|
||||
details: ['name', 'id', 'resourcestate', 'ipaddress', 'hypervisor', 'type', 'clustername', 'podname', 'zonename', 'disconnected', 'created'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
related: [{
|
||||
name: 'vm',
|
||||
@ -50,16 +51,16 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'addHost',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.host',
|
||||
docHelp: 'adminguide/installguide/configuration.html#adding-a-host',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/infra/HostAdd.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/HostAdd.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateHost',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['name', 'hosttags', 'oscategoryid'],
|
||||
@ -71,7 +72,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'provisionCertificate',
|
||||
icon: 'safety-certificate',
|
||||
icon: 'safety-certificate-outlined',
|
||||
label: 'label.action.secure.host',
|
||||
message: 'message.action.secure.host',
|
||||
dataView: true,
|
||||
@ -85,7 +86,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'reconnectHost',
|
||||
icon: 'forward',
|
||||
icon: 'forward-outlined',
|
||||
label: 'label.action.force.reconnect',
|
||||
message: 'message.confirm.action.force.reconnect',
|
||||
dataView: true,
|
||||
@ -93,7 +94,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateHost',
|
||||
icon: 'pause-circle',
|
||||
icon: 'pause-circle-outlined',
|
||||
label: 'label.disable.host',
|
||||
message: 'message.confirm.disable.host',
|
||||
dataView: true,
|
||||
@ -102,7 +103,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateHost',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.enable.host',
|
||||
message: 'message.confirm.enable.host',
|
||||
dataView: true,
|
||||
@ -111,7 +112,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'prepareHostForMaintenance',
|
||||
icon: 'plus-square',
|
||||
icon: 'plus-square-outlined',
|
||||
label: 'label.action.enable.maintenance.mode',
|
||||
message: 'message.action.host.enable.maintenance.mode',
|
||||
docHelp: 'adminguide/hosts.html#maintaining-hypervisors-on-hosts',
|
||||
@ -120,7 +121,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'cancelHostMaintenance',
|
||||
icon: 'minus-square',
|
||||
icon: 'minus-square-outlined',
|
||||
label: 'label.action.cancel.maintenance.mode',
|
||||
message: 'message.action.cancel.maintenance.mode',
|
||||
docHelp: 'adminguide/hosts.html#maintaining-hypervisors-on-hosts',
|
||||
@ -129,7 +130,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'configureOutOfBandManagement',
|
||||
icon: 'setting',
|
||||
icon: 'setting-outlined',
|
||||
label: 'label.outofbandmanagement.configure',
|
||||
message: 'label.outofbandmanagement.configure',
|
||||
docHelp: 'adminguide/hosts.html#out-of-band-management',
|
||||
@ -146,7 +147,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'enableOutOfBandManagementForHost',
|
||||
icon: 'plus-circle',
|
||||
icon: 'plus-circle-outlined',
|
||||
label: 'label.outofbandmanagement.enable',
|
||||
message: 'label.outofbandmanagement.enable',
|
||||
docHelp: 'adminguide/hosts.html#out-of-band-management',
|
||||
@ -163,7 +164,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'disableOutOfBandManagementForHost',
|
||||
icon: 'minus-circle',
|
||||
icon: 'minus-circle-outlined',
|
||||
label: 'label.outofbandmanagement.disable',
|
||||
message: 'label.outofbandmanagement.disable',
|
||||
docHelp: 'adminguide/hosts.html#out-of-band-management',
|
||||
@ -180,7 +181,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'issueOutOfBandManagementPowerAction',
|
||||
icon: 'login',
|
||||
icon: 'login-outlined',
|
||||
label: 'label.outofbandmanagement.action.issue',
|
||||
message: 'label.outofbandmanagement.action.issue',
|
||||
docHelp: 'adminguide/hosts.html#out-of-band-management',
|
||||
@ -200,7 +201,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'changeOutOfBandManagementPassword',
|
||||
icon: 'key',
|
||||
icon: 'key-outlined',
|
||||
label: 'label.outofbandmanagement.changepassword',
|
||||
message: 'label.outofbandmanagement.changepassword',
|
||||
docHelp: 'adminguide/hosts.html#out-of-band-management',
|
||||
@ -217,7 +218,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'configureHAForHost',
|
||||
icon: 'tool',
|
||||
icon: 'tool-outlined',
|
||||
label: 'label.ha.configure',
|
||||
message: 'label.ha.configure',
|
||||
docHelp: 'adminguide/reliability.html#ha-for-hosts',
|
||||
@ -235,7 +236,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'enableHAForHost',
|
||||
icon: 'eye',
|
||||
icon: 'eye-outlined',
|
||||
label: 'label.ha.enable',
|
||||
message: 'label.ha.enable',
|
||||
docHelp: 'adminguide/reliability.html#ha-for-hosts',
|
||||
@ -252,7 +253,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'disableHAForHost',
|
||||
icon: 'eye-invisible',
|
||||
icon: 'eye-invisible-outlined',
|
||||
label: 'label.ha.disable',
|
||||
message: 'label.ha.disable',
|
||||
docHelp: 'adminguide/reliability.html#ha-for-hosts',
|
||||
@ -270,7 +271,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'startRollingMaintenance',
|
||||
icon: 'setting',
|
||||
icon: 'setting-outlined',
|
||||
label: 'label.start.rolling.maintenance',
|
||||
message: 'label.start.rolling.maintenance',
|
||||
docHelp: 'adminguide/hosts.html#kvm-rolling-maintenance',
|
||||
@ -287,7 +288,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteHost',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.remove.host',
|
||||
docHelp: 'adminguide/hosts.html#removing-hosts',
|
||||
dataView: true,
|
||||
|
||||
@ -15,10 +15,11 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
export default {
|
||||
name: 'ilbvm',
|
||||
title: 'label.internal.lb',
|
||||
icon: 'share-alt',
|
||||
icon: 'share-alt-outlined',
|
||||
permission: ['listInternalLoadBalancerVMs'],
|
||||
params: { projectid: '-1' },
|
||||
columns: ['name', 'state', 'publicip', 'guestnetworkname', 'vpcname', 'version', 'hostname', 'account', 'zonename', 'requiresupgrade'],
|
||||
@ -26,7 +27,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'startInternalLoadBalancerVM',
|
||||
icon: 'caret-right',
|
||||
icon: 'caret-right-outlined',
|
||||
label: 'label.action.start.router',
|
||||
message: 'message.confirm.start.lb.vm',
|
||||
dataView: true,
|
||||
@ -37,7 +38,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'stopInternalLoadBalancerVM',
|
||||
icon: 'poweroff',
|
||||
icon: 'poweroff-outlined',
|
||||
label: 'label.action.stop.router',
|
||||
dataView: true,
|
||||
args: ['forced'],
|
||||
@ -48,11 +49,11 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'migrateSystemVm',
|
||||
icon: 'drag',
|
||||
icon: 'drag-outlined',
|
||||
label: 'label.action.migrate.router',
|
||||
dataView: true,
|
||||
show: (record, store) => { return record.state === 'Running' && ['Admin'].includes(store.userInfo.roletype) },
|
||||
component: () => import('@/views/compute/MigrateWizard'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateWizard'))),
|
||||
popup: true
|
||||
},
|
||||
{
|
||||
@ -61,7 +62,7 @@ export default {
|
||||
label: 'label.action.migrate.systemvm.to.ps',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
|
||||
component: () => import('@/views/compute/MigrateVMStorage'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateVMStorage'))),
|
||||
popup: true
|
||||
}
|
||||
]
|
||||
|
||||
@ -15,10 +15,11 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
export default {
|
||||
name: 'nsp',
|
||||
title: 'label.network.service.providers',
|
||||
icon: 'compass',
|
||||
icon: 'compass-outlined',
|
||||
docHelp: 'adminguide/networking.html#network-service-providers',
|
||||
hidden: true,
|
||||
permission: ['listNetworkServiceProviders'],
|
||||
@ -26,12 +27,12 @@ export default {
|
||||
details: ['name', 'state', 'servicelist', 'canenableindividualservice', 'physicalnetworkid'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'updateNetworkServiceProvider',
|
||||
icon: 'stop',
|
||||
icon: 'stop-outlined',
|
||||
label: 'label.disable.provider',
|
||||
message: 'message.confirm.disable.provider',
|
||||
dataView: true,
|
||||
@ -45,7 +46,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateNetworkServiceProvider',
|
||||
icon: 'right-circle',
|
||||
icon: 'right-circle-outlined',
|
||||
label: 'label.enable.provider',
|
||||
message: 'message.confirm.enable.provider',
|
||||
dataView: true,
|
||||
|
||||
@ -15,27 +15,28 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
export default {
|
||||
name: 'physicalnetwork',
|
||||
title: 'label.physical.network',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#basic-zone-physical-network-configuration',
|
||||
icon: 'api',
|
||||
icon: 'api-outlined',
|
||||
hidden: true,
|
||||
permission: ['listPhysicalNetworks'],
|
||||
columns: ['name', 'state', 'isolationmethods', 'vlan', 'broadcastdomainrange', 'zonename', 'tags'],
|
||||
details: ['name', 'state', 'isolationmethods', 'vlan', 'broadcastdomainrange', 'zonename', 'tags'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'traffic.types',
|
||||
component: () => import('@/views/infra/network/TrafficTypesTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/network/TrafficTypesTab.vue')))
|
||||
}, {
|
||||
name: 'network.service.providers',
|
||||
component: () => import('@/views/infra/network/ServiceProvidersTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/network/ServiceProvidersTab.vue')))
|
||||
}, {
|
||||
name: 'dedicated.vlan.vni.ranges',
|
||||
component: () => import('@/views/infra/network/DedicatedVLANTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/network/DedicatedVLANTab.vue')))
|
||||
}],
|
||||
related: [{
|
||||
name: 'guestnetwork',
|
||||
@ -45,7 +46,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'createPhysicalNetwork',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.physical.network',
|
||||
listView: true,
|
||||
args: ['name', 'zoneid', 'isolationmethods', 'vlan', 'tags', 'networkspeed', 'broadcastdomainrange'],
|
||||
@ -57,7 +58,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updatePhysicalNetwork',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.action.enable.physical.network',
|
||||
dataView: true,
|
||||
args: ['state'],
|
||||
@ -70,7 +71,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updatePhysicalNetwork',
|
||||
icon: 'stop',
|
||||
icon: 'stop-outlined',
|
||||
label: 'label.action.disable.physical.network',
|
||||
dataView: true,
|
||||
args: ['state'],
|
||||
@ -83,14 +84,14 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updatePhysicalNetwork',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.update.physical.network',
|
||||
dataView: true,
|
||||
args: ['vlan', 'tags']
|
||||
},
|
||||
{
|
||||
api: 'addTrafficType',
|
||||
icon: 'plus-square',
|
||||
icon: 'plus-square-outlined',
|
||||
label: 'label.add.traffic.type',
|
||||
dataView: true,
|
||||
args: ['traffictype', 'physicalnetworkid', 'isolationmethod'],
|
||||
@ -108,15 +109,15 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateTrafficType',
|
||||
icon: 'branches',
|
||||
icon: 'branches-outlined',
|
||||
label: 'label.update.traffic.label',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/infra/network/EditTrafficLabel.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/network/EditTrafficLabel.vue')))
|
||||
},
|
||||
{
|
||||
api: 'deletePhysicalNetwork',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.physical.network',
|
||||
message: 'message.action.delete.physical.network',
|
||||
dataView: true
|
||||
|
||||
@ -15,10 +15,11 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
export default {
|
||||
name: 'pod',
|
||||
title: 'label.pods',
|
||||
icon: 'appstore',
|
||||
icon: 'appstore-outlined',
|
||||
permission: ['listPods'],
|
||||
columns: ['name', 'allocationstate', 'gateway', 'netmask', 'zonename'],
|
||||
details: ['name', 'id', 'allocationstate', 'netmask', 'gateway', 'zonename'],
|
||||
@ -34,34 +35,34 @@ export default {
|
||||
resourceType: 'Pod',
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'resources',
|
||||
component: () => import('@/views/infra/Resources.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/Resources.vue')))
|
||||
}, {
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'createPod',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.pod',
|
||||
docHelp: 'installguide/configuration.html#adding-a-pod',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/infra/PodAdd.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/PodAdd.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updatePod',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['name', 'netmask', 'gateway']
|
||||
},
|
||||
{
|
||||
api: 'updatePod',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.action.enable.pod',
|
||||
message: 'message.action.enable.pod',
|
||||
docHelp: 'adminguide/hosts.html#disabling-and-enabling-zones-pods-and-clusters',
|
||||
@ -76,7 +77,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updatePod',
|
||||
icon: 'pause-circle',
|
||||
icon: 'pause-circle-outlined',
|
||||
label: 'label.action.disable.pod',
|
||||
message: 'message.action.disable.pod',
|
||||
docHelp: 'adminguide/hosts.html#disabling-and-enabling-zones-pods-and-clusters',
|
||||
@ -91,7 +92,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'startRollingMaintenance',
|
||||
icon: 'setting',
|
||||
icon: 'setting-outlined',
|
||||
label: 'label.start.rolling.maintenance',
|
||||
message: 'label.start.rolling.maintenance',
|
||||
dataView: true,
|
||||
@ -104,7 +105,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deletePod',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.pod',
|
||||
message: 'message.action.delete.pod',
|
||||
dataView: true
|
||||
|
||||
@ -15,12 +15,13 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'storagepool',
|
||||
title: 'label.primary.storage',
|
||||
icon: 'database',
|
||||
icon: 'database-outlined',
|
||||
docHelp: 'adminguide/storage.html#primary-storage',
|
||||
permission: ['listStoragePoolsMetrics'],
|
||||
columns: () => {
|
||||
@ -42,34 +43,34 @@ export default {
|
||||
resourceType: 'PrimaryStorage',
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'settings',
|
||||
component: () => import('@/components/view/SettingsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/SettingsTab.vue')))
|
||||
}, {
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'createStoragePool',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
docHelp: 'installguide/configuration.html#add-primary-storage',
|
||||
label: 'label.add.primary.storage',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/infra/AddPrimaryStorage.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/AddPrimaryStorage.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateStoragePool',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['name', 'tags', 'capacitybytes', 'capacityiops']
|
||||
},
|
||||
{
|
||||
api: 'updateStoragePool',
|
||||
icon: 'pause-circle',
|
||||
icon: 'pause-circle-outlined',
|
||||
label: 'label.disable.storage',
|
||||
message: 'message.confirm.disable.storage',
|
||||
dataView: true,
|
||||
@ -78,7 +79,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateStoragePool',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.enable.storage',
|
||||
message: 'message.confirm.enable.storage',
|
||||
dataView: true,
|
||||
@ -87,7 +88,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'syncStoragePool',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
label: 'label.sync.storage',
|
||||
message: 'message.confirm.sync.storage',
|
||||
dataView: true,
|
||||
@ -95,7 +96,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'enableStorageMaintenance',
|
||||
icon: 'plus-square',
|
||||
icon: 'plus-square-outlined',
|
||||
label: 'label.action.enable.maintenance.mode',
|
||||
message: 'message.action.primarystorage.enable.maintenance.mode',
|
||||
dataView: true,
|
||||
@ -103,7 +104,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'cancelStorageMaintenance',
|
||||
icon: 'minus-square',
|
||||
icon: 'minus-square-outlined',
|
||||
label: 'label.action.cancel.maintenance.mode',
|
||||
message: 'message.action.cancel.maintenance.mode',
|
||||
dataView: true,
|
||||
@ -111,7 +112,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteStoragePool',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.primary.storage',
|
||||
dataView: true,
|
||||
args: ['forced'],
|
||||
|
||||
@ -15,10 +15,12 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'router',
|
||||
title: 'label.virtual.routers',
|
||||
icon: 'fork',
|
||||
icon: 'fork-outlined',
|
||||
docHelp: 'adminguide/systemvm.html#virtual-router',
|
||||
permission: ['listRouters'],
|
||||
params: { projectid: '-1' },
|
||||
@ -28,17 +30,17 @@ export default {
|
||||
resourceType: 'VirtualRouter',
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'nics',
|
||||
component: () => import('@/views/network/NicsTable.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/NicsTable.vue')))
|
||||
}, {
|
||||
name: 'router.health.checks',
|
||||
show: (record, route, user) => { return ['Running'].includes(record.state) && ['Admin'].includes(user.roletype) },
|
||||
component: () => import('@views/infra/routers/RouterHealthCheck.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@views/infra/routers/RouterHealthCheck.vue')))
|
||||
}, {
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
related: [{
|
||||
name: 'vm',
|
||||
@ -49,7 +51,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'startRouter',
|
||||
icon: 'caret-right',
|
||||
icon: 'caret-right-outlined',
|
||||
label: 'label.action.start.router',
|
||||
message: 'message.action.start.router',
|
||||
dataView: true,
|
||||
@ -60,7 +62,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'stopRouter',
|
||||
icon: 'poweroff',
|
||||
icon: 'poweroff-outlined',
|
||||
label: 'label.action.stop.router',
|
||||
message: 'message.action.stop.router',
|
||||
dataView: true,
|
||||
@ -72,7 +74,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'rebootRouter',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
label: 'label.action.reboot.router',
|
||||
message: 'message.action.reboot.router',
|
||||
dataView: true,
|
||||
@ -84,7 +86,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'scaleSystemVm',
|
||||
icon: 'arrows-alt',
|
||||
icon: 'arrows-alt-outlined',
|
||||
label: 'label.change.service.offering',
|
||||
message: 'message.confirm.scale.up.router.vm',
|
||||
dataView: true,
|
||||
@ -105,7 +107,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'upgradeRouterTemplate',
|
||||
icon: 'fullscreen',
|
||||
icon: 'fullscreen-outlined',
|
||||
label: 'label.upgrade.router.newer.template',
|
||||
message: 'message.confirm.upgrade.router.newer.template',
|
||||
docHelp: 'adminguide/systemvm.html#upgrading-virtual-routers',
|
||||
@ -115,12 +117,12 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'migrateSystemVm',
|
||||
icon: 'drag',
|
||||
icon: 'drag-outlined',
|
||||
label: 'label.action.migrate.router',
|
||||
message: 'message.migrate.router.confirm',
|
||||
dataView: true,
|
||||
show: (record, store) => { return record.state === 'Running' && ['Admin'].includes(store.userInfo.roletype) },
|
||||
component: () => import('@/views/compute/MigrateWizard'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateWizard'))),
|
||||
popup: true
|
||||
},
|
||||
{
|
||||
@ -129,12 +131,12 @@ export default {
|
||||
label: 'label.action.migrate.systemvm.to.ps',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
|
||||
component: () => import('@/views/compute/MigrateVMStorage'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateVMStorage'))),
|
||||
popup: true
|
||||
},
|
||||
{
|
||||
api: 'runDiagnostics',
|
||||
icon: 'reconciliation',
|
||||
icon: 'reconciliation-outlined',
|
||||
label: 'label.action.run.diagnostics',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Running'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
|
||||
@ -151,7 +153,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'getDiagnosticsData',
|
||||
icon: 'download',
|
||||
icon: 'download-outlined',
|
||||
label: 'label.action.get.diagnostics',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Running'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
|
||||
@ -165,7 +167,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'destroyRouter',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.destroy.router',
|
||||
message: 'message.confirm.destroy.router',
|
||||
dataView: true,
|
||||
|
||||
@ -14,12 +14,14 @@
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'imagestore',
|
||||
title: 'label.secondary.storage',
|
||||
icon: 'picture',
|
||||
icon: 'picture-outlined',
|
||||
docHelp: 'adminguide/storage.html#secondary-storage',
|
||||
permission: ['listImageStores'],
|
||||
columns: () => {
|
||||
@ -42,35 +44,35 @@ export default {
|
||||
resourceType: 'SecondaryStorage',
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'settings',
|
||||
component: () => import('@/components/view/SettingsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/SettingsTab.vue')))
|
||||
}, {
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'addImageStore',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
docHelp: 'installguide/configuration.html#add-secondary-storage',
|
||||
label: 'label.add.secondary.storage',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/infra/AddSecondaryStorage.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/AddSecondaryStorage.vue')))
|
||||
},
|
||||
{
|
||||
api: 'migrateSecondaryStorageData',
|
||||
icon: 'drag',
|
||||
icon: 'drag-outlined',
|
||||
label: 'label.migrate.data.from.image.store',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/infra/MigrateData.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/MigrateData.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateImageStore',
|
||||
icon: 'stop',
|
||||
icon: 'stop-outlined',
|
||||
label: 'label.action.image.store.read.only',
|
||||
message: 'message.action.secondary.storage.read.only',
|
||||
dataView: true,
|
||||
@ -79,7 +81,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateImageStore',
|
||||
icon: 'check-circle',
|
||||
icon: 'check-circle-outlined',
|
||||
label: 'label.action.image.store.read.write',
|
||||
message: 'message.action.secondary.storage.read.write',
|
||||
dataView: true,
|
||||
@ -88,7 +90,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteImageStore',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.secondary.storage',
|
||||
message: 'message.action.delete.secondary.storage',
|
||||
dataView: true,
|
||||
|
||||
@ -15,10 +15,12 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'systemvm',
|
||||
title: 'label.system.vms',
|
||||
icon: 'thunderbolt',
|
||||
icon: 'thunderbolt-outlined',
|
||||
docHelp: 'adminguide/systemvm.html',
|
||||
permission: ['listSystemVms'],
|
||||
columns: ['name', 'state', 'agentstate', 'systemvmtype', 'publicip', 'privateip', 'linklocalip', 'hostname', 'zonename'],
|
||||
@ -27,17 +29,17 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'startSystemVm',
|
||||
icon: 'caret-right',
|
||||
icon: 'caret-right-outlined',
|
||||
label: 'label.action.start.systemvm',
|
||||
message: 'message.action.start.systemvm',
|
||||
dataView: true,
|
||||
@ -48,7 +50,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'stopSystemVm',
|
||||
icon: 'poweroff',
|
||||
icon: 'poweroff-outlined',
|
||||
label: 'label.action.stop.systemvm',
|
||||
message: 'message.action.stop.systemvm',
|
||||
dataView: true,
|
||||
@ -60,7 +62,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'rebootSystemVm',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
label: 'label.action.reboot.systemvm',
|
||||
message: 'message.action.reboot.systemvm',
|
||||
dataView: true,
|
||||
@ -72,7 +74,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'scaleSystemVm',
|
||||
icon: 'arrows-alt',
|
||||
icon: 'arrows-alt-outlined',
|
||||
label: 'label.change.service.offering',
|
||||
message: 'message.confirm.scale.up.system.vm',
|
||||
dataView: true,
|
||||
@ -87,12 +89,12 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'migrateSystemVm',
|
||||
icon: 'drag',
|
||||
icon: 'drag-outlined',
|
||||
label: 'label.action.migrate.systemvm',
|
||||
message: 'message.migrate.systemvm.confirm',
|
||||
dataView: true,
|
||||
show: (record, store) => { return record.state === 'Running' && ['Admin'].includes(store.userInfo.roletype) },
|
||||
component: () => import('@/views/compute/MigrateWizard'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateWizard'))),
|
||||
popup: true
|
||||
},
|
||||
{
|
||||
@ -101,12 +103,12 @@ export default {
|
||||
label: 'label.action.migrate.systemvm.to.ps',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
|
||||
component: () => import('@/views/compute/MigrateVMStorage'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateVMStorage'))),
|
||||
popup: true
|
||||
},
|
||||
{
|
||||
api: 'runDiagnostics',
|
||||
icon: 'reconciliation',
|
||||
icon: 'reconciliation-outlined',
|
||||
label: 'label.action.run.diagnostics',
|
||||
dataView: true,
|
||||
show: (record) => { return record.state === 'Running' },
|
||||
@ -123,7 +125,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'getDiagnosticsData',
|
||||
icon: 'download',
|
||||
icon: 'download-outlined',
|
||||
label: 'label.action.get.diagnostics',
|
||||
dataView: true,
|
||||
show: (record) => { return record.state === 'Running' },
|
||||
@ -137,7 +139,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'destroySystemVm',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.destroy.systemvm',
|
||||
message: 'message.action.destroy.systemvm',
|
||||
dataView: true,
|
||||
|
||||
@ -15,12 +15,13 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'zone',
|
||||
title: 'label.zones',
|
||||
icon: 'global',
|
||||
icon: 'global-outlined',
|
||||
permission: ['listZonesMetrics'],
|
||||
columns: () => {
|
||||
const fields = ['name', 'allocationstate', 'networktype', 'clusters']
|
||||
@ -56,36 +57,36 @@ export default {
|
||||
resourceType: 'Zone',
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'physical.network',
|
||||
component: () => import('@/views/infra/zone/PhysicalNetworksTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/PhysicalNetworksTab.vue')))
|
||||
}, {
|
||||
name: 'system.vms',
|
||||
component: () => import('@/views/infra/zone/SystemVmsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/SystemVmsTab.vue')))
|
||||
}, {
|
||||
name: 'resources',
|
||||
component: () => import('@/views/infra/Resources.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/Resources.vue')))
|
||||
}, {
|
||||
name: 'settings',
|
||||
component: () => import('@/components/view/SettingsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/SettingsTab.vue')))
|
||||
}, {
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'createZone',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.zone',
|
||||
docHelp: 'installguide/configuration.html#adding-a-zone',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/infra/zone/ZoneWizard.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/ZoneWizard.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateZone',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.action.edit.zone',
|
||||
dataView: true,
|
||||
args: ['name', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'internaldns1', 'internaldns2', 'guestcidraddress', 'domain', 'localstorageenabled'],
|
||||
@ -93,7 +94,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateZone',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.action.edit.zone',
|
||||
dataView: true,
|
||||
args: ['name', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'internaldns1', 'internaldns2', 'domain', 'localstorageenabled'],
|
||||
@ -101,7 +102,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateZone',
|
||||
icon: 'pause-circle',
|
||||
icon: 'pause-circle-outlined',
|
||||
label: 'label.action.disable.zone',
|
||||
message: 'message.action.disable.zone',
|
||||
docHelp: 'adminguide/hosts.html#disabling-and-enabling-zones-pods-and-clusters',
|
||||
@ -111,7 +112,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateZone',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.action.enable.zone',
|
||||
message: 'message.action.enable.zone',
|
||||
docHelp: 'adminguide/hosts.html#disabling-and-enabling-zones-pods-and-clusters',
|
||||
@ -121,7 +122,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'enableOutOfBandManagementForZone',
|
||||
icon: 'plus-circle',
|
||||
icon: 'plus-circle-outlined',
|
||||
label: 'label.outofbandmanagement.enable',
|
||||
message: 'label.outofbandmanagement.enable',
|
||||
dataView: true,
|
||||
@ -137,7 +138,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'disableOutOfBandManagementForZone',
|
||||
icon: 'minus-circle',
|
||||
icon: 'minus-circle-outlined',
|
||||
label: 'label.outofbandmanagement.disable',
|
||||
message: 'label.outofbandmanagement.disable',
|
||||
dataView: true,
|
||||
@ -153,7 +154,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'enableHAForZone',
|
||||
icon: 'eye',
|
||||
icon: 'eye-outlined',
|
||||
label: 'label.ha.enable',
|
||||
message: 'label.ha.enable',
|
||||
dataView: true,
|
||||
@ -169,7 +170,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'disableHAForZone',
|
||||
icon: 'eye-invisible',
|
||||
icon: 'eye-invisible-outlined',
|
||||
label: 'label.ha.disable',
|
||||
message: 'label.ha.disable',
|
||||
dataView: true,
|
||||
@ -185,7 +186,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'addVmwareDc',
|
||||
icon: 'block',
|
||||
icon: 'block-outlined',
|
||||
label: 'label.add.vmware.datacenter',
|
||||
dataView: true,
|
||||
show: record => !record.vmwaredc,
|
||||
@ -198,7 +199,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateVmwareDc',
|
||||
icon: 'block',
|
||||
icon: 'block-outlined',
|
||||
label: 'label.update.vmware.datacenter',
|
||||
message: 'message.restart.mgmt.server',
|
||||
additionalMessage: 'message.restart.mgmt.server',
|
||||
@ -213,7 +214,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'removeVmwareDc',
|
||||
icon: 'minus-square',
|
||||
icon: 'minus-square-outlined',
|
||||
label: 'label.remove.vmware.datacenter',
|
||||
message: 'message.confirm.remove.vmware.datacenter',
|
||||
dataView: true,
|
||||
@ -227,7 +228,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'startRollingMaintenance',
|
||||
icon: 'setting',
|
||||
icon: 'setting-outlined',
|
||||
label: 'label.start.rolling.maintenance',
|
||||
message: 'label.start.rolling.maintenance',
|
||||
dataView: true,
|
||||
@ -240,7 +241,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteZone',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.zone',
|
||||
message: 'message.action.delete.zone',
|
||||
dataView: true
|
||||
|
||||
@ -15,19 +15,20 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
import { isAdmin } from '@/role'
|
||||
|
||||
export default {
|
||||
name: 'network',
|
||||
title: 'label.network',
|
||||
icon: 'wifi',
|
||||
icon: 'wifi-outlined',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#advanced-zone-physical-network-configuration',
|
||||
children: [
|
||||
{
|
||||
name: 'guestnetwork',
|
||||
title: 'label.guest.networks',
|
||||
icon: 'apartment',
|
||||
icon: 'apartment-outlined',
|
||||
permission: ['listNetworks'],
|
||||
resourceType: 'Network',
|
||||
columns: () => {
|
||||
@ -53,49 +54,49 @@ export default {
|
||||
}],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'egress.rules',
|
||||
component: () => import('@/views/network/EgressRulesTab.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/EgressRulesTab.vue'))),
|
||||
show: (record) => { return record.type === 'Isolated' && !('vpcid' in record) && 'listEgressFirewallRules' in store.getters.apis }
|
||||
}, {
|
||||
name: 'public.ip.addresses',
|
||||
component: () => import('@/views/network/IpAddressesTab.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/IpAddressesTab.vue'))),
|
||||
show: (record) => { return (record.type === 'Isolated' || record.type === 'Shared') && !('vpcid' in record) && 'listPublicIpAddresses' in store.getters.apis }
|
||||
}, {
|
||||
name: 'virtual.routers',
|
||||
component: () => import('@/views/network/RoutersTab.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/RoutersTab.vue'))),
|
||||
show: (record) => { return (record.type === 'Isolated' || record.type === 'Shared') && 'listRouters' in store.getters.apis }
|
||||
}, {
|
||||
name: 'guest.ip.range',
|
||||
component: () => import('@/views/network/GuestIpRanges.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/GuestIpRanges.vue'))),
|
||||
show: (record) => { return 'listVlanIpRanges' in store.getters.apis && (record.type === 'Shared' || (record.service && record.service.filter(x => x.name === 'SourceNat').count === 0)) }
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'createNetwork',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.network',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#configure-guest-traffic-in-an-advanced-zone',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/network/CreateNetwork.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/CreateNetwork.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateNetwork',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.update.network',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/network/UpdateNetwork.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/UpdateNetwork.vue')))
|
||||
},
|
||||
{
|
||||
api: 'restartNetwork',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
label: 'label.restart.network',
|
||||
message: 'message.restart.network',
|
||||
dataView: true,
|
||||
@ -107,7 +108,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'replaceNetworkACLList',
|
||||
icon: 'swap',
|
||||
icon: 'swap-outlined',
|
||||
label: 'label.replace.acl.list',
|
||||
message: 'message.confirm.replace.acl.new.one',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#configuring-network-access-control-list',
|
||||
@ -126,7 +127,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteNetwork',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.network',
|
||||
message: 'message.action.delete.network',
|
||||
dataView: true,
|
||||
@ -139,7 +140,7 @@ export default {
|
||||
{
|
||||
name: 'vpc',
|
||||
title: 'label.vpc',
|
||||
icon: 'deployment-unit',
|
||||
icon: 'deployment-unit-outlined',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#configuring-a-virtual-private-cloud',
|
||||
permission: ['listVPCs'],
|
||||
resourceType: 'Vpc',
|
||||
@ -161,28 +162,28 @@ export default {
|
||||
}],
|
||||
tabs: [{
|
||||
name: 'vpc',
|
||||
component: () => import('@/views/network/VpcTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/VpcTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'createVPC',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.vpc',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#adding-a-virtual-private-cloud',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/network/CreateVpc.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/CreateVpc.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateVPC',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['name', 'displaytext']
|
||||
},
|
||||
{
|
||||
api: 'restartVPC',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
label: 'label.restart.vpc',
|
||||
message: (record) => { return record.redundantvpcrouter ? 'message.restart.vpc' : 'message.restart.vpc.remark' },
|
||||
dataView: true,
|
||||
@ -199,7 +200,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteVPC',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.remove.vpc',
|
||||
message: 'message.remove.vpc',
|
||||
dataView: true,
|
||||
@ -212,7 +213,7 @@ export default {
|
||||
{
|
||||
name: 'securitygroups',
|
||||
title: 'label.security.groups',
|
||||
icon: 'fire',
|
||||
icon: 'fire-outlined',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#security-groups',
|
||||
permission: ['listSecurityGroups'],
|
||||
resourceType: 'SecurityGroup',
|
||||
@ -220,13 +221,13 @@ export default {
|
||||
details: ['name', 'id', 'description', 'account', 'domain'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'ingress.rule',
|
||||
component: () => import('@/views/network/IngressEgressRuleConfigure.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/IngressEgressRuleConfigure.vue')))
|
||||
}, {
|
||||
name: 'egress.rule',
|
||||
component: () => import('@/views/network/IngressEgressRuleConfigure.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/IngressEgressRuleConfigure.vue')))
|
||||
}],
|
||||
show: () => {
|
||||
if (!store.getters.zones || store.getters.zones.length === 0) {
|
||||
@ -241,7 +242,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'createSecurityGroup',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.security.group',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#adding-a-security-group',
|
||||
listView: true,
|
||||
@ -249,7 +250,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateSecurityGroup',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['name'],
|
||||
@ -257,7 +258,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteSecurityGroup',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.security.group',
|
||||
message: 'message.action.delete.security.group',
|
||||
dataView: true,
|
||||
@ -268,19 +269,19 @@ export default {
|
||||
{
|
||||
name: 'publicip',
|
||||
title: 'label.public.ip.addresses',
|
||||
icon: 'environment',
|
||||
icon: 'environment-outlined',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#reserving-public-ip-addresses-and-vlans-for-accounts',
|
||||
permission: ['listPublicIpAddresses'],
|
||||
resourceType: 'PublicIpAddress',
|
||||
columns: ['ipaddress', 'state', 'associatednetworkname', 'virtualmachinename', 'allocated', 'account', 'zonename'],
|
||||
details: ['ipaddress', 'id', 'associatednetworkname', 'virtualmachinename', 'networkid', 'issourcenat', 'isstaticnat', 'virtualmachinename', 'vmipaddress', 'vlan', 'allocated', 'account', 'zonename'],
|
||||
component: () => import('@/views/network/PublicIpResource.vue'),
|
||||
component: shallowRef(() => import('@/views/network/PublicIpResource.vue')),
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'firewall',
|
||||
component: () => import('@/views/network/FirewallRules.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/FirewallRules.vue'))),
|
||||
networkServiceFilter: networkService => networkService.filter(x => x.name === 'Firewall').length > 0,
|
||||
groupAction: true,
|
||||
popup: true,
|
||||
@ -288,35 +289,35 @@ export default {
|
||||
},
|
||||
{
|
||||
name: 'portforwarding',
|
||||
component: () => import('@/views/network/PortForwarding.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/PortForwarding.vue'))),
|
||||
networkServiceFilter: networkService => networkService.filter(x => x.name === 'PortForwarding').length > 0
|
||||
}, {
|
||||
name: 'loadbalancing',
|
||||
component: () => import('@/views/network/LoadBalancing.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/LoadBalancing.vue'))),
|
||||
networkServiceFilter: networkService => networkService.filter(x => x.name === 'Lb').length > 0
|
||||
}, {
|
||||
name: 'vpn',
|
||||
component: () => import('@/views/network/VpnDetails.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/VpnDetails.vue'))),
|
||||
show: (record) => { return record.issourcenat }
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'enableStaticNat',
|
||||
icon: 'plus-circle',
|
||||
icon: 'plus-circle-outlined',
|
||||
label: 'label.action.enable.static.nat',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#enabling-or-disabling-static-nat',
|
||||
dataView: true,
|
||||
show: (record) => { return !record.virtualmachineid && !record.issourcenat },
|
||||
popup: true,
|
||||
component: () => import('@/views/network/EnableStaticNat.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/EnableStaticNat.vue')))
|
||||
},
|
||||
{
|
||||
api: 'disableStaticNat',
|
||||
icon: 'minus-circle',
|
||||
icon: 'minus-circle-outlined',
|
||||
label: 'label.action.disable.static.nat',
|
||||
message: 'message.action.disable.static.nat',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#enabling-or-disabling-static-nat',
|
||||
@ -331,7 +332,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'disassociateIpAddress',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.release.ip',
|
||||
message: 'message.action.release.ip',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#releasing-an-ip-address-alloted-to-a-vpc',
|
||||
@ -346,23 +347,23 @@ export default {
|
||||
{
|
||||
name: 'privategw',
|
||||
title: 'label.private.gateway',
|
||||
icon: 'gateway',
|
||||
icon: 'gateway-outlined',
|
||||
hidden: true,
|
||||
permission: ['listPrivateGateways'],
|
||||
columns: ['ipaddress', 'state', 'gateway', 'netmask', 'account'],
|
||||
details: ['ipaddress', 'gateway', 'netmask', 'vlan', 'sourcenatsupported', 'aclname', 'account', 'domain', 'zone'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'static.routes',
|
||||
component: () => import('@/views/network/StaticRoutesTab.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/StaticRoutesTab.vue'))),
|
||||
show: () => true
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'createPrivateGateway',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.private.gateway',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#adding-a-private-gateway-to-a-vpc',
|
||||
listView: true,
|
||||
@ -381,7 +382,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'replaceNetworkACLList',
|
||||
icon: 'swap',
|
||||
icon: 'swap-outlined',
|
||||
label: 'label.replace.acl.list',
|
||||
message: 'message.confirm.replace.acl.new.one',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#acl-on-private-gateway',
|
||||
@ -399,7 +400,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deletePrivateGateway',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.gateway',
|
||||
message: 'message.delete.gateway',
|
||||
dataView: true
|
||||
@ -409,7 +410,7 @@ export default {
|
||||
{
|
||||
name: 's2svpn',
|
||||
title: 'label.site.to.site.vpn',
|
||||
icon: 'lock',
|
||||
icon: 'lock-outlined',
|
||||
hidden: true,
|
||||
permission: ['listVpnGateways'],
|
||||
columns: ['publicip', 'account', 'domain'],
|
||||
@ -417,7 +418,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'createVpnGateway',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.vpn.gateway',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#creating-a-vpn-gateway-for-the-vpc',
|
||||
listView: true,
|
||||
@ -425,7 +426,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteVpnGateway',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.vpn.gateway',
|
||||
message: 'message.delete.vpn.gateway',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#restarting-and-removing-a-vpn-connection',
|
||||
@ -437,7 +438,7 @@ export default {
|
||||
name: 's2svpnconn',
|
||||
title: 'label.site.to.site.vpn.connections',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#setting-up-a-site-to-site-vpn-connection',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
hidden: true,
|
||||
permission: ['listVpnConnections'],
|
||||
columns: ['publicip', 'state', 'gateway', 'ipsecpsk', 'ikepolicy', 'esppolicy'],
|
||||
@ -445,7 +446,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'createVpnConnection',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.create.vpn.connection',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#creating-a-vpn-connection',
|
||||
listView: true,
|
||||
@ -461,7 +462,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'resetVpnConnection',
|
||||
icon: 'reload',
|
||||
icon: 'reload-outlined',
|
||||
label: 'label.reset.vpn.connection',
|
||||
message: 'message.reset.vpn.connection',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#restarting-and-removing-a-vpn-connection',
|
||||
@ -469,7 +470,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteVpnConnection',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.vpn.connection',
|
||||
message: 'message.delete.vpn.connection',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#restarting-and-removing-a-vpn-connection',
|
||||
@ -480,7 +481,7 @@ export default {
|
||||
{
|
||||
name: 'acllist',
|
||||
title: 'label.network.acl.lists',
|
||||
icon: 'bars',
|
||||
icon: 'bars-outlined',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#configuring-network-access-control-list',
|
||||
hidden: true,
|
||||
permission: ['listNetworkACLLists'],
|
||||
@ -488,16 +489,16 @@ export default {
|
||||
details: ['name', 'description', 'id'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'acl.list.rules',
|
||||
component: () => import('@/views/network/AclListRulesTab.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/AclListRulesTab.vue'))),
|
||||
show: () => true
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'createNetworkACLList',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.acl.list',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#creating-acl-lists',
|
||||
listView: true,
|
||||
@ -505,14 +506,14 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateNetworkACLList',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit.acl.list',
|
||||
dataView: true,
|
||||
args: ['name', 'description']
|
||||
},
|
||||
{
|
||||
api: 'deleteNetworkACLList',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.acl.list',
|
||||
message: 'message.confirm.delete.acl.list',
|
||||
dataView: true
|
||||
@ -523,23 +524,23 @@ export default {
|
||||
name: 'ilb',
|
||||
title: 'label.internal.lb',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#load-balancing-across-tiers',
|
||||
icon: 'share-alt',
|
||||
icon: 'share-alt-outlined',
|
||||
hidden: true,
|
||||
permission: ['listLoadBalancers'],
|
||||
columns: ['name', 'sourceipaddress', 'loadbalancerrule', 'algorithm', 'account', 'domain'],
|
||||
details: ['name', 'sourceipaddress', 'loadbalancerrule', 'algorithm', 'account', 'domain'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'loadbalancerinstance',
|
||||
component: () => import('@/views/network/InternalLBAssignedVmTab.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/InternalLBAssignedVmTab.vue'))),
|
||||
show: () => true
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'createLoadBalancer',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.internal.lb',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#creating-an-internal-lb-rule',
|
||||
listView: true,
|
||||
@ -563,15 +564,15 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'assignToLoadBalancerRule',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.assign.vms',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/network/InternalLBAssignVmForm.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/InternalLBAssignVmForm.vue')))
|
||||
},
|
||||
{
|
||||
api: 'deleteLoadBalancer',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.internal.lb',
|
||||
message: 'message.confirm.delete.internal.lb',
|
||||
dataView: true
|
||||
@ -581,7 +582,7 @@ export default {
|
||||
{
|
||||
name: 'vpnuser',
|
||||
title: 'label.vpn.users',
|
||||
icon: 'user',
|
||||
icon: 'user-alt-outlined',
|
||||
permission: ['listVpnUsers'],
|
||||
hidden: true,
|
||||
columns: ['username', 'state', 'account', 'domain'],
|
||||
@ -589,7 +590,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'addVpnUser',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.vpn.user',
|
||||
listView: true,
|
||||
args: (record, store) => {
|
||||
@ -602,7 +603,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'removeVpnUser',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.vpn.user',
|
||||
message: 'message.action.delete.vpn.user',
|
||||
dataView: true,
|
||||
@ -634,7 +635,7 @@ export default {
|
||||
{
|
||||
name: 'vpncustomergateway',
|
||||
title: 'label.vpncustomergatewayid',
|
||||
icon: 'lock',
|
||||
icon: 'lock-outlined',
|
||||
permission: ['listVpnCustomerGateways'],
|
||||
columns: ['name', 'gateway', 'cidrlist', 'ipsecpsk', 'account'],
|
||||
details: ['name', 'id', 'gateway', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'ikelifetime', 'ikeversion', 'esppolicy', 'esplifetime', 'dpd', 'splitconnections', 'forceencap', 'account', 'domain'],
|
||||
@ -643,26 +644,26 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'createVpnCustomerGateway',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.vpn.customer.gateway',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#creating-and-updating-a-vpn-customer-gateway',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/network/CreateVpnCustomerGateway.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/CreateVpnCustomerGateway.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateVpnCustomerGateway',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#updating-and-removing-a-vpn-customer-gateway',
|
||||
dataView: true,
|
||||
@ -675,7 +676,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteVpnCustomerGateway',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.vpn.customer.gateway',
|
||||
message: 'message.delete.vpn.customer.gateway',
|
||||
docHelp: 'adminguide/networking_and_traffic.html#updating-and-removing-a-vpn-customer-gateway',
|
||||
|
||||
@ -14,19 +14,20 @@
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'offering',
|
||||
title: 'label.menu.service.offerings',
|
||||
icon: 'shopping',
|
||||
icon: 'shopping-outlined',
|
||||
permission: ['listServiceOfferings', 'listDiskOfferings', 'listDomains'],
|
||||
children: [
|
||||
{
|
||||
name: 'computeoffering',
|
||||
title: 'label.compute.offerings',
|
||||
docHelp: 'adminguide/service_offerings.html#compute-and-disk-service-offerings',
|
||||
icon: 'cloud',
|
||||
icon: 'cloud-outlined',
|
||||
permission: ['listServiceOfferings', 'listDomains'],
|
||||
params: { isrecursive: 'true' },
|
||||
columns: ['name', 'displaytext', 'cpunumber', 'cpuspeed', 'memory', 'domain', 'zone', 'order'],
|
||||
@ -46,11 +47,11 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
related: [{
|
||||
@ -60,30 +61,30 @@ export default {
|
||||
}],
|
||||
actions: [{
|
||||
api: 'createServiceOffering',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.compute.offering',
|
||||
docHelp: 'adminguide/service_offerings.html#creating-a-new-compute-offering',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/offering/AddComputeOffering.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/offering/AddComputeOffering.vue')))
|
||||
}, {
|
||||
api: 'updateServiceOffering',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
dataView: true,
|
||||
args: ['name', 'displaytext', 'storagetags', 'hosttags']
|
||||
}, {
|
||||
api: 'updateServiceOffering',
|
||||
icon: 'lock',
|
||||
icon: 'lock-outlined',
|
||||
label: 'label.action.update.offering.access',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/offering/UpdateOfferingAccess.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/offering/UpdateOfferingAccess.vue')))
|
||||
}, {
|
||||
api: 'deleteServiceOffering',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.service.offering',
|
||||
message: 'message.action.delete.service.offering',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
@ -96,7 +97,7 @@ export default {
|
||||
{
|
||||
name: 'systemoffering',
|
||||
title: 'label.system.offerings',
|
||||
icon: 'setting',
|
||||
icon: 'setting-outlined',
|
||||
docHelp: 'adminguide/service_offerings.html#system-service-offerings',
|
||||
permission: ['listServiceOfferings', 'listInfrastructure'],
|
||||
params: { issystem: 'true', isrecursive: 'true' },
|
||||
@ -104,16 +105,16 @@ export default {
|
||||
details: ['name', 'id', 'displaytext', 'systemvmtype', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness'],
|
||||
actions: [{
|
||||
api: 'createServiceOffering',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.system.service.offering',
|
||||
docHelp: 'adminguide/service_offerings.html#creating-a-new-system-service-offering',
|
||||
listView: true,
|
||||
params: { issystem: 'true' },
|
||||
popup: true,
|
||||
component: () => import('@/views/offering/AddComputeOffering.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/offering/AddComputeOffering.vue')))
|
||||
}, {
|
||||
api: 'updateServiceOffering',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
params: { issystem: 'true' },
|
||||
@ -121,7 +122,7 @@ export default {
|
||||
args: ['name', 'displaytext']
|
||||
}, {
|
||||
api: 'deleteServiceOffering',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.system.service.offering',
|
||||
message: 'message.action.delete.system.service.offering',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
@ -135,7 +136,7 @@ export default {
|
||||
{
|
||||
name: 'diskoffering',
|
||||
title: 'label.disk.offerings',
|
||||
icon: 'hdd',
|
||||
icon: 'hdd-outlined',
|
||||
docHelp: 'adminguide/service_offerings.html#compute-and-disk-service-offerings',
|
||||
permission: ['listDiskOfferings', 'listDomains'],
|
||||
params: { isrecursive: 'true' },
|
||||
@ -152,11 +153,11 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
related: [{
|
||||
@ -166,30 +167,30 @@ export default {
|
||||
}],
|
||||
actions: [{
|
||||
api: 'createDiskOffering',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.disk.offering',
|
||||
docHelp: 'adminguide/service_offerings.html#creating-a-new-disk-offering',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/offering/AddDiskOffering.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/offering/AddDiskOffering.vue')))
|
||||
}, {
|
||||
api: 'updateDiskOffering',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
dataView: true,
|
||||
args: ['name', 'displaytext', 'tags']
|
||||
}, {
|
||||
api: 'updateDiskOffering',
|
||||
icon: 'lock',
|
||||
icon: 'lock-outlined',
|
||||
label: 'label.action.update.offering.access',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/offering/UpdateOfferingAccess.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/offering/UpdateOfferingAccess.vue')))
|
||||
}, {
|
||||
api: 'deleteDiskOffering',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.disk.offering',
|
||||
message: 'message.action.delete.disk.offering',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
@ -202,7 +203,7 @@ export default {
|
||||
{
|
||||
name: 'backupoffering',
|
||||
title: 'label.backup.offerings',
|
||||
icon: 'cloud-upload',
|
||||
icon: 'cloud-upload-outlined',
|
||||
docHelp: 'adminguide/virtual_machines.html#backup-offerings',
|
||||
permission: ['listBackupOfferings', 'listInfrastructure'],
|
||||
columns: ['name', 'description', 'zonename'],
|
||||
@ -214,12 +215,12 @@ export default {
|
||||
}],
|
||||
actions: [{
|
||||
api: 'importBackupOffering',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.import.backup.offering',
|
||||
docHelp: 'adminguide/virtual_machines.html#importing-backup-offerings',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/offering/ImportBackupOffering.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/offering/ImportBackupOffering.vue')))
|
||||
}, {
|
||||
api: 'updateBackupOffering',
|
||||
icon: 'edit',
|
||||
@ -230,7 +231,7 @@ export default {
|
||||
args: ['name', 'description']
|
||||
}, {
|
||||
api: 'deleteBackupOffering',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.backup.offering',
|
||||
message: 'message.action.delete.backup.offering',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
@ -243,7 +244,7 @@ export default {
|
||||
{
|
||||
name: 'networkoffering',
|
||||
title: 'label.network.offerings',
|
||||
icon: 'wifi',
|
||||
icon: 'wifi-outlined',
|
||||
docHelp: 'adminguide/networking.html#network-offerings',
|
||||
permission: ['listNetworkOfferings', 'listInfrastructure'],
|
||||
params: { isrecursive: 'true' },
|
||||
@ -253,24 +254,24 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
actions: [{
|
||||
api: 'createNetworkOffering',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.network.offering',
|
||||
docHelp: 'adminguide/networking.html#creating-a-new-network-offering',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/offering/AddNetworkOffering.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/offering/AddNetworkOffering.vue')))
|
||||
}, {
|
||||
api: 'updateNetworkOffering',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
dataView: true,
|
||||
@ -282,7 +283,7 @@ export default {
|
||||
}
|
||||
}, {
|
||||
api: 'updateNetworkOffering',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.enable.network.offering',
|
||||
message: 'message.confirm.enable.network.offering',
|
||||
dataView: true,
|
||||
@ -298,7 +299,7 @@ export default {
|
||||
groupMap: (selection) => { return selection.map(x => { return { id: x, state: 'Enabled' } }) }
|
||||
}, {
|
||||
api: 'updateNetworkOffering',
|
||||
icon: 'pause-circle',
|
||||
icon: 'pause-circle-outlined',
|
||||
label: 'label.disable.network.offering',
|
||||
message: 'message.confirm.disable.network.offering',
|
||||
dataView: true,
|
||||
@ -314,15 +315,15 @@ export default {
|
||||
groupMap: (selection) => { return selection.map(x => { return { id: x, state: 'Disabled' } }) }
|
||||
}, {
|
||||
api: 'updateNetworkOffering',
|
||||
icon: 'lock',
|
||||
icon: 'lock-outlined',
|
||||
label: 'label.action.update.offering.access',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/offering/UpdateOfferingAccess.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/offering/UpdateOfferingAccess.vue')))
|
||||
}, {
|
||||
api: 'deleteNetworkOffering',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.remove.network.offering',
|
||||
message: 'message.confirm.remove.network.offering',
|
||||
docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering',
|
||||
@ -335,7 +336,7 @@ export default {
|
||||
{
|
||||
name: 'vpcoffering',
|
||||
title: 'label.vpc.offerings',
|
||||
icon: 'deployment-unit',
|
||||
icon: 'deployment-unit-outlined',
|
||||
docHelp: 'plugins/nuage-plugin.html?#vpc-offerings',
|
||||
permission: ['listVPCOfferings', 'listInfrastructure'],
|
||||
params: { isrecursive: 'true' },
|
||||
@ -349,21 +350,21 @@ export default {
|
||||
}],
|
||||
actions: [{
|
||||
api: 'createVPCOffering',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
docHelp: 'plugins/nuage-plugin.html?#optional-create-and-enable-vpc-offering',
|
||||
label: 'label.add.vpc.offering',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/offering/AddVpcOffering.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/offering/AddVpcOffering.vue')))
|
||||
}, {
|
||||
api: 'updateVPCOffering',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['name', 'displaytext']
|
||||
}, {
|
||||
api: 'updateVPCOffering',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.enable.vpc.offering',
|
||||
message: 'message.confirm.enable.vpc.offering',
|
||||
dataView: true,
|
||||
@ -379,7 +380,7 @@ export default {
|
||||
groupMap: (selection) => { return selection.map(x => { return { id: x, state: 'Enabled' } }) }
|
||||
}, {
|
||||
api: 'updateVPCOffering',
|
||||
icon: 'pause-circle',
|
||||
icon: 'pause-circle-outlined',
|
||||
label: 'label.disable.vpc.offering',
|
||||
message: 'message.confirm.disable.vpc.offering',
|
||||
dataView: true,
|
||||
@ -395,14 +396,14 @@ export default {
|
||||
groupMap: (selection) => { return selection.map(x => { return { id: x, state: 'Disabled' } }) }
|
||||
}, {
|
||||
api: 'updateVPCOffering',
|
||||
icon: 'lock',
|
||||
icon: 'lock-outlined',
|
||||
label: 'label.action.update.offering.access',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/offering/UpdateOfferingAccess.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/offering/UpdateOfferingAccess.vue')))
|
||||
}, {
|
||||
api: 'deleteVPCOffering',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.remove.vpc.offering',
|
||||
message: 'message.confirm.remove.vpc.offering',
|
||||
dataView: true,
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import cloudian from '@/assets/icons/cloudian.svg?inline'
|
||||
|
||||
export default {
|
||||
@ -23,5 +24,5 @@ export default {
|
||||
docHelp: 'plugins/cloudian-connector.html',
|
||||
icon: cloudian,
|
||||
permission: ['cloudianSsoLogin'],
|
||||
component: () => import('@/views/plugins/CloudianPlugin.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/plugins/CloudianPlugin.vue')))
|
||||
}
|
||||
|
||||
@ -15,39 +15,40 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
export default {
|
||||
name: 'quota',
|
||||
title: 'label.quota',
|
||||
icon: 'pie-chart',
|
||||
icon: 'pie-chart-outlined',
|
||||
docHelp: 'plugins/quota.html',
|
||||
permission: ['quotaSummary'],
|
||||
children: [
|
||||
{
|
||||
name: 'quotasummary',
|
||||
title: 'label.summary',
|
||||
icon: 'bars',
|
||||
icon: 'bars-outlined',
|
||||
permission: ['quotaSummary'],
|
||||
columns: ['account', 'domain', 'state', 'currency', 'balance', 'quota'],
|
||||
details: ['account', 'domain', 'state', 'currency', 'balance', 'quota', 'startdate', 'enddate'],
|
||||
component: () => import('@/views/plugins/quota/QuotaSummary.vue'),
|
||||
component: shallowRef(() => import('@/views/plugins/quota/QuotaSummary.vue')),
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'quota.statement.quota',
|
||||
component: () => import('@/views/plugins/quota/QuotaUsage.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/plugins/quota/QuotaUsage.vue')))
|
||||
},
|
||||
{
|
||||
name: 'quota.statement.balance',
|
||||
component: () => import('@/views/plugins/quota/QuotaBalance.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/plugins/quota/QuotaBalance.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'quotaCredits',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
docHelp: 'plugins/quota.html#quota-credits',
|
||||
label: 'label.quota.add.credits',
|
||||
dataView: true,
|
||||
@ -66,23 +67,23 @@ export default {
|
||||
{
|
||||
name: 'quotatariff',
|
||||
title: 'label.quota.tariff',
|
||||
icon: 'credit-card',
|
||||
icon: 'credit-card-outlined',
|
||||
docHelp: 'plugins/quota.html#quota-tariff',
|
||||
permission: ['quotaTariffList'],
|
||||
columns: ['usageName', 'description', 'usageUnit', 'tariffValue', 'tariffActions'],
|
||||
details: ['usageName', 'description', 'usageUnit', 'tariffValue'],
|
||||
component: () => import('@/views/plugins/quota/QuotaTariff.vue')
|
||||
component: shallowRef(() => import('@/views/plugins/quota/QuotaTariff.vue'))
|
||||
},
|
||||
{
|
||||
name: 'quotaemailtemplate',
|
||||
title: 'label.templatetype',
|
||||
icon: 'mail',
|
||||
icon: 'mail-outlined',
|
||||
permission: ['quotaEmailTemplateList'],
|
||||
columns: ['templatetype', 'templatesubject', 'templatebody'],
|
||||
details: ['templatetype', 'templatesubject', 'templatebody'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/views/plugins/quota/EmailTemplateDetails.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/plugins/quota/EmailTemplateDetails.vue')))
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
@ -14,12 +14,14 @@
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'project',
|
||||
title: 'label.projects',
|
||||
icon: 'project',
|
||||
icon: 'project-outlined',
|
||||
docHelp: 'adminguide/projects.html',
|
||||
permission: ['listProjects'],
|
||||
resourceType: 'Project',
|
||||
@ -29,16 +31,16 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/views/project/ProjectDetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/project/ProjectDetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'accounts',
|
||||
component: () => import('@/views/project/AccountsTab.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/project/AccountsTab.vue'))),
|
||||
show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) || record.isCurrentUserProjectAdmin }
|
||||
},
|
||||
{
|
||||
name: 'project.roles',
|
||||
component: () => import('@/views/project/iam/ProjectRoleTab.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/project/iam/ProjectRoleTab.vue'))),
|
||||
show: (record, route, user) => {
|
||||
return (['Admin', 'DomainAdmin'].includes(user.roletype) || record.isCurrentUserProjectAdmin) &&
|
||||
'listProjectRoles' in store.getters.apis
|
||||
@ -46,18 +48,18 @@ export default {
|
||||
},
|
||||
{
|
||||
name: 'resources',
|
||||
component: () => import('@/components/view/ResourceCountUsage.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/ResourceCountUsage.vue')))
|
||||
},
|
||||
{
|
||||
name: 'limits',
|
||||
show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) },
|
||||
component: () => import('@/components/view/ResourceLimitTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/ResourceLimitTab.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'createProject',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.new.project',
|
||||
docHelp: 'adminguide/projects.html#creating-a-new-project',
|
||||
listView: true,
|
||||
@ -65,17 +67,17 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateProjectInvitation',
|
||||
icon: 'key',
|
||||
icon: 'key-outlined',
|
||||
label: 'label.enter.token',
|
||||
docHelp: 'adminguide/projects.html#accepting-a-membership-invitation',
|
||||
listView: true,
|
||||
popup: true,
|
||||
show: (record, store) => { return store.features.projectinviterequired },
|
||||
component: () => import('@/views/project/InvitationTokenTemplate.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/project/InvitationTokenTemplate.vue')))
|
||||
},
|
||||
{
|
||||
api: 'listProjectInvitations',
|
||||
icon: 'team',
|
||||
icon: 'team-outlined',
|
||||
label: 'label.project.invitation',
|
||||
docHelp: 'adminguide/projects.html#accepting-a-membership-invitation',
|
||||
listView: true,
|
||||
@ -86,11 +88,11 @@ export default {
|
||||
state: 'Pending'
|
||||
},
|
||||
show: (record, store) => { return store.features.projectinviterequired },
|
||||
component: () => import('@/views/project/InvitationsTemplate.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/project/InvitationsTemplate.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateProject',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit.project.details',
|
||||
dataView: true,
|
||||
args: ['displaytext'],
|
||||
@ -100,7 +102,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'activateProject',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.activate.project',
|
||||
message: 'message.activate.project',
|
||||
dataView: true,
|
||||
@ -113,7 +115,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'suspendProject',
|
||||
icon: 'pause-circle',
|
||||
icon: 'pause-circle-outlined',
|
||||
label: 'label.suspend.project',
|
||||
message: 'message.suspend.project',
|
||||
docHelp: 'adminguide/projects.html#sending-project-membership-invitations',
|
||||
@ -128,7 +130,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'addAccountToProject',
|
||||
icon: 'user-add',
|
||||
icon: 'user-add-outlined',
|
||||
label: 'label.action.project.add.account',
|
||||
docHelp: 'adminguide/projects.html#adding-project-members-from-the-ui',
|
||||
dataView: true,
|
||||
@ -136,11 +138,11 @@ export default {
|
||||
show: (record, store) => {
|
||||
return (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) || record.isCurrentUserProjectAdmin
|
||||
},
|
||||
component: () => import('@/views/project/AddAccountOrUserToProject.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/project/AddAccountOrUserToProject.vue')))
|
||||
},
|
||||
{
|
||||
api: 'deleteProject',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.project',
|
||||
message: 'message.delete.project',
|
||||
docHelp: 'adminguide/projects.html#suspending-or-deleting-a-project',
|
||||
|
||||
@ -15,41 +15,42 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
export default {
|
||||
name: 'role',
|
||||
title: 'label.roles',
|
||||
icon: 'idcard',
|
||||
icon: 'idcard-outlined',
|
||||
docHelp: 'adminguide/accounts.html#roles',
|
||||
permission: ['listRoles', 'listRolePermissions'],
|
||||
columns: ['name', 'type', 'description'],
|
||||
details: ['name', 'id', 'type', 'description'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
}, {
|
||||
name: 'rules',
|
||||
component: () => import('@/views/iam/RolePermissionTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/RolePermissionTab.vue')))
|
||||
}],
|
||||
actions: [
|
||||
{
|
||||
api: 'createRole',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.role',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/iam/CreateRole.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/CreateRole.vue')))
|
||||
},
|
||||
{
|
||||
api: 'importRole',
|
||||
icon: 'cloud-upload',
|
||||
icon: 'cloud-upload-outlined',
|
||||
label: 'label.import.role',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/iam/ImportRole.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/ImportRole.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateRole',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit.role',
|
||||
dataView: true,
|
||||
args: ['name', 'description', 'type'],
|
||||
@ -61,7 +62,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteRole',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.role',
|
||||
message: 'label.delete.role',
|
||||
dataView: true
|
||||
|
||||
@ -15,17 +15,18 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'storage',
|
||||
title: 'label.storage',
|
||||
icon: 'database',
|
||||
icon: 'database-outlined',
|
||||
children: [
|
||||
{
|
||||
name: 'volume',
|
||||
title: 'label.volumes',
|
||||
icon: 'hdd',
|
||||
icon: 'hdd-outlined',
|
||||
docHelp: 'adminguide/storage.html#working-with-volumes',
|
||||
permission: ['listVolumesMetrics'],
|
||||
resourceType: 'Volume',
|
||||
@ -65,54 +66,54 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
searchFilters: ['name', 'zoneid', 'domainid', 'account', 'state', 'tags'],
|
||||
actions: [
|
||||
{
|
||||
api: 'createVolume',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
docHelp: 'adminguide/storage.html#creating-a-new-volume',
|
||||
label: 'label.action.create.volume',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/storage/CreateVolume.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/CreateVolume.vue')))
|
||||
},
|
||||
{
|
||||
api: 'createVolume',
|
||||
icon: 'cloud-upload',
|
||||
icon: 'cloud-upload-outlined',
|
||||
docHelp: 'adminguide/storage.html#uploading-an-existing-volume-to-a-virtual-machine',
|
||||
label: 'label.upload.volume.from.local',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/storage/UploadLocalVolume.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/UploadLocalVolume.vue')))
|
||||
},
|
||||
{
|
||||
api: 'uploadVolume',
|
||||
icon: 'link',
|
||||
icon: 'link-outlined',
|
||||
docHelp: 'adminguide/storage.html#uploading-an-existing-volume-to-a-virtual-machine',
|
||||
label: 'label.upload.volume.from.url',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/storage/UploadVolume.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/UploadVolume.vue')))
|
||||
},
|
||||
{
|
||||
api: 'attachVolume',
|
||||
icon: 'paper-clip',
|
||||
icon: 'paper-clip-outlined',
|
||||
label: 'label.action.attach.disk',
|
||||
dataView: true,
|
||||
show: (record) => { return record.type !== 'ROOT' && ['Allocated', 'Ready', 'Uploaded'].includes(record.state) && !('virtualmachineid' in record) },
|
||||
popup: true,
|
||||
component: () => import('@/views/storage/AttachVolume.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/AttachVolume.vue')))
|
||||
},
|
||||
{
|
||||
api: 'detachVolume',
|
||||
icon: 'link',
|
||||
icon: 'link-outlined',
|
||||
label: 'label.action.detach.disk',
|
||||
message: 'message.detach.disk',
|
||||
dataView: true,
|
||||
@ -123,7 +124,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'updateVolume',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['name'],
|
||||
@ -138,7 +139,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'createSnapshot',
|
||||
icon: 'camera',
|
||||
icon: 'camera-outlined',
|
||||
docHelp: 'adminguide/storage.html#working-with-volume-snapshots',
|
||||
label: 'label.action.take.snapshot',
|
||||
dataView: true,
|
||||
@ -148,11 +149,11 @@ export default {
|
||||
record.hypervisor === 'KVM' && record.vmstate !== 'Running')
|
||||
},
|
||||
popup: true,
|
||||
component: () => import('@/views/storage/TakeSnapshot.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/TakeSnapshot.vue')))
|
||||
},
|
||||
{
|
||||
api: 'createSnapshotPolicy',
|
||||
icon: 'clock-circle',
|
||||
icon: 'clock-circle-outlined',
|
||||
docHelp: 'adminguide/storage.html#working-with-volume-snapshots',
|
||||
label: 'label.action.recurring.snapshot',
|
||||
dataView: true,
|
||||
@ -162,7 +163,7 @@ export default {
|
||||
record.hypervisor === 'KVM' && record.vmstate !== 'Running')
|
||||
},
|
||||
popup: true,
|
||||
component: () => import('@/views/storage/RecurringSnapshotVolume.vue'),
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/RecurringSnapshotVolume.vue'))),
|
||||
mapping: {
|
||||
volumeid: {
|
||||
value: (record) => { return record.id }
|
||||
@ -174,39 +175,39 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'resizeVolume',
|
||||
icon: 'fullscreen',
|
||||
icon: 'fullscreen-outlined',
|
||||
docHelp: 'adminguide/storage.html#resizing-volumes',
|
||||
label: 'label.action.resize.volume',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
show: (record) => { return ['Allocated', 'Ready'].includes(record.state) },
|
||||
component: () => import('@/views/storage/ResizeVolume.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/ResizeVolume.vue')))
|
||||
},
|
||||
{
|
||||
api: 'migrateVolume',
|
||||
icon: 'drag',
|
||||
icon: 'drag-outlined',
|
||||
docHelp: 'adminguide/storage.html#id2',
|
||||
label: 'label.migrate.volume',
|
||||
args: ['volumeid', 'storageid', 'livemigrate'],
|
||||
dataView: true,
|
||||
show: (record, store) => { return record.state === 'Ready' && ['Admin'].includes(store.userInfo.roletype) },
|
||||
popup: true,
|
||||
component: () => import('@/views/storage/MigrateVolume.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/MigrateVolume.vue')))
|
||||
},
|
||||
{
|
||||
api: 'changeOfferingForVolume',
|
||||
icon: 'swap',
|
||||
icon: 'swap-outlined',
|
||||
docHelp: 'adminguide/storage.html#id2',
|
||||
label: 'label.change.offering.for.volume',
|
||||
args: ['id', 'diskofferingid', 'size', 'miniops', 'maxiops', 'automigrate'],
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Allocated', 'Ready'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
|
||||
popup: true,
|
||||
component: () => import('@/views/storage/ChangeOfferingForVolume.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/ChangeOfferingForVolume.vue')))
|
||||
},
|
||||
{
|
||||
api: 'extractVolume',
|
||||
icon: 'cloud-download',
|
||||
icon: 'cloud-download-outlined',
|
||||
label: 'label.action.download.volume',
|
||||
message: 'message.download.volume.confirm',
|
||||
dataView: true,
|
||||
@ -224,7 +225,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'createTemplate',
|
||||
icon: 'picture',
|
||||
icon: 'picture-outlined',
|
||||
label: 'label.action.create.template.from.volume',
|
||||
dataView: true,
|
||||
show: (record) => {
|
||||
@ -241,7 +242,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'recoverVolume',
|
||||
icon: 'medicine-box',
|
||||
icon: 'medicine-box-outlined',
|
||||
label: 'label.action.recover.volume',
|
||||
message: 'message.action.recover.volume',
|
||||
dataView: true,
|
||||
@ -251,7 +252,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteVolume',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.volume',
|
||||
message: 'message.action.delete.volume',
|
||||
dataView: true,
|
||||
@ -266,7 +267,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'destroyVolume',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.destroy.volume',
|
||||
message: 'message.action.destroy.volume',
|
||||
dataView: true,
|
||||
@ -284,7 +285,7 @@ export default {
|
||||
{
|
||||
name: 'snapshot',
|
||||
title: 'label.snapshots',
|
||||
icon: 'build',
|
||||
icon: 'build-outlined',
|
||||
docHelp: 'adminguide/storage.html#working-with-volume-snapshots',
|
||||
permission: ['listSnapshots'],
|
||||
resourceType: 'Snapshot',
|
||||
@ -300,18 +301,18 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
searchFilters: ['name', 'domainid', 'account', 'tags'],
|
||||
actions: [
|
||||
{
|
||||
api: 'createTemplate',
|
||||
icon: 'picture',
|
||||
icon: 'picture-outlined',
|
||||
label: 'label.create.template',
|
||||
dataView: true,
|
||||
show: (record) => { return record.state === 'BackedUp' },
|
||||
@ -324,7 +325,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'createVolume',
|
||||
icon: 'hdd',
|
||||
icon: 'hdd-outlined',
|
||||
label: 'label.action.create.volume',
|
||||
dataView: true,
|
||||
show: (record) => { return record.state === 'BackedUp' },
|
||||
@ -343,7 +344,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'revertSnapshot',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
label: 'label.action.revert.snapshot',
|
||||
message: 'message.action.revert.snapshot',
|
||||
dataView: true,
|
||||
@ -351,7 +352,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteSnapshot',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.snapshot',
|
||||
message: 'message.action.delete.snapshot',
|
||||
dataView: true,
|
||||
@ -365,7 +366,7 @@ export default {
|
||||
{
|
||||
name: 'vmsnapshot',
|
||||
title: 'label.vm.snapshots',
|
||||
icon: 'camera',
|
||||
icon: 'camera-outlined',
|
||||
docHelp: 'adminguide/storage.html#working-with-volume-snapshots',
|
||||
permission: ['listVMSnapshot'],
|
||||
resourceType: 'VMSnapshot',
|
||||
@ -382,27 +383,27 @@ export default {
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: () => import('@/components/view/AnnotationsTab.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'createSnapshotFromVMSnapshot',
|
||||
icon: 'camera',
|
||||
icon: 'camera-outlined',
|
||||
label: 'label.action.create.snapshot.from.vmsnapshot',
|
||||
message: 'message.action.create.snapshot.from.vmsnapshot',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
show: (record) => { return (record.state === 'Ready' && record.hypervisor === 'KVM') },
|
||||
component: () => import('@/views/storage/CreateSnapshotFromVMSnapshot.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/CreateSnapshotFromVMSnapshot.vue')))
|
||||
},
|
||||
{
|
||||
api: 'revertToVMSnapshot',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
label: 'label.action.vmsnapshot.revert',
|
||||
message: 'label.action.vmsnapshot.revert',
|
||||
dataView: true,
|
||||
@ -416,7 +417,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteVMSnapshot',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.vmsnapshot.delete',
|
||||
message: 'message.action.vmsnapshot.delete',
|
||||
dataView: true,
|
||||
@ -436,14 +437,14 @@ export default {
|
||||
{
|
||||
name: 'backup',
|
||||
title: 'label.backup',
|
||||
icon: 'cloud-upload',
|
||||
icon: 'cloud-upload-outlined',
|
||||
permission: ['listBackups'],
|
||||
columns: [{ name: (record) => { return record.virtualmachinename } }, 'virtualmachinename', 'status', 'type', 'created', 'account', 'zone'],
|
||||
details: ['virtualmachinename', 'id', 'type', 'externalid', 'size', 'virtualsize', 'volumes', 'backupofferingname', 'zone', 'account', 'domain', 'created'],
|
||||
actions: [
|
||||
{
|
||||
api: 'restoreBackup',
|
||||
icon: 'sync',
|
||||
icon: 'sync-outlined',
|
||||
docHelp: 'adminguide/virtual_machines.html#restoring-vm-backups',
|
||||
label: 'label.backup.restore',
|
||||
message: 'message.backup.restore',
|
||||
@ -452,17 +453,17 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'restoreVolumeFromBackupAndAttachToVM',
|
||||
icon: 'paper-clip',
|
||||
icon: 'paper-clip-outlined',
|
||||
label: 'label.backup.attach.restore',
|
||||
message: 'message.backup.attach.restore',
|
||||
dataView: true,
|
||||
show: (record) => { return record.state !== 'Destroyed' },
|
||||
popup: true,
|
||||
component: () => import('@/views/storage/RestoreAttachBackupVolume.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/RestoreAttachBackupVolume.vue')))
|
||||
},
|
||||
{
|
||||
api: 'removeVirtualMachineFromBackupOffering',
|
||||
icon: 'scissor',
|
||||
icon: 'scissor-outlined',
|
||||
label: 'label.backup.offering.remove',
|
||||
message: 'message.backup.offering.remove',
|
||||
dataView: true,
|
||||
@ -479,7 +480,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'deleteBackup',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.backup',
|
||||
message: 'message.delete.backup',
|
||||
dataView: true,
|
||||
|
||||
@ -19,12 +19,12 @@ import store from '@/store'
|
||||
export default {
|
||||
name: 'tools',
|
||||
title: 'label.tools',
|
||||
icon: 'tool',
|
||||
icon: 'tool-outlined',
|
||||
children: [
|
||||
{
|
||||
name: 'comment',
|
||||
title: 'label.comments',
|
||||
icon: 'message',
|
||||
icon: 'message-outlined',
|
||||
docHelp: 'adminguide/events.html',
|
||||
permission: ['listAnnotations'],
|
||||
columns: () => {
|
||||
@ -43,7 +43,7 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'removeAnnotation',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.remove.annotation',
|
||||
message: 'message.remove.annotation',
|
||||
dataView: false,
|
||||
@ -63,7 +63,7 @@ export default {
|
||||
{
|
||||
name: 'manageinstances',
|
||||
title: 'label.action.import.export.instances',
|
||||
icon: 'interaction',
|
||||
icon: 'interaction-outlined',
|
||||
docHelp: 'adminguide/virtual_machines.html#importing-and-unmanaging-virtual-machine',
|
||||
resourceType: 'UserVm',
|
||||
permission: ['listInfrastructure', 'listUnmanagedInstances'],
|
||||
|
||||
@ -15,10 +15,12 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { shallowRef, defineAsyncComponent } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'accountuser',
|
||||
title: 'label.users',
|
||||
icon: 'user',
|
||||
icon: 'user-outlined',
|
||||
docHelp: 'adminguide/accounts.html#users',
|
||||
hidden: true,
|
||||
permission: ['listUsers'],
|
||||
@ -27,38 +29,38 @@ export default {
|
||||
actions: [
|
||||
{
|
||||
api: 'createUser',
|
||||
icon: 'plus',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.add.user',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/iam/AddUser.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/AddUser.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateUser',
|
||||
icon: 'edit',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/iam/EditUser.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/EditUser.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateUser',
|
||||
icon: 'key',
|
||||
icon: 'key-outlined',
|
||||
label: 'label.action.change.password',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
component: () => import('@/views/iam/ChangeUserPassword.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/ChangeUserPassword.vue')))
|
||||
},
|
||||
{
|
||||
api: 'registerUserKeys',
|
||||
icon: 'file-protect',
|
||||
icon: 'file-protect-outlined',
|
||||
label: 'label.action.generate.keys',
|
||||
message: 'message.generate.keys',
|
||||
dataView: true
|
||||
},
|
||||
{
|
||||
api: 'enableUser',
|
||||
icon: 'play-circle',
|
||||
icon: 'play-circle-outlined',
|
||||
label: 'label.action.enable.user',
|
||||
message: 'message.enable.user',
|
||||
dataView: true,
|
||||
@ -70,7 +72,7 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'disableUser',
|
||||
icon: 'pause-circle',
|
||||
icon: 'pause-circle-outlined',
|
||||
label: 'label.action.disable.user',
|
||||
message: 'message.disable.user',
|
||||
dataView: true,
|
||||
@ -82,18 +84,18 @@ export default {
|
||||
},
|
||||
{
|
||||
api: 'authorizeSamlSso',
|
||||
icon: 'form',
|
||||
icon: 'form-outlined',
|
||||
label: 'Configure SAML SSO Authorization',
|
||||
dataView: true,
|
||||
popup: true,
|
||||
show: (record, store) => {
|
||||
return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)
|
||||
},
|
||||
component: () => import('@/views/iam/ConfigureSamlSsoAuth.vue')
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/ConfigureSamlSsoAuth.vue')))
|
||||
},
|
||||
{
|
||||
api: 'deleteUser',
|
||||
icon: 'delete',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.action.delete.user',
|
||||
message: 'message.delete.user',
|
||||
dataView: true,
|
||||
|
||||
@ -26,9 +26,14 @@ export default {
|
||||
invertedMode: true,
|
||||
multiTab: false, // enable to have tab/route history stuff
|
||||
// vue-ls options
|
||||
// storageOptions: {
|
||||
// namespace: 'primate__', // key prefix
|
||||
// name: 'ls', // name variable Vue.[ls] or this.[$ls],
|
||||
// storage: 'local' // storage name session, local, memory
|
||||
// },
|
||||
// vue-ls options
|
||||
storageOptions: {
|
||||
namespace: 'primate__', // key prefix
|
||||
name: 'ls', // name variable Vue.[ls] or this.[$ls],
|
||||
storage: 'local' // storage name session, local, memory
|
||||
prefix: 'primate__', // key prefix
|
||||
drivers: ['local'] // storage name session, local, memory
|
||||
}
|
||||
}
|
||||
|
||||
42
ui/src/core/bootstrap.js
vendored
42
ui/src/core/bootstrap.js
vendored
@ -15,7 +15,7 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import Vue from 'vue'
|
||||
import { vueProps } from '@/vue-app'
|
||||
import config from '@/config/settings'
|
||||
import store from '@/store/'
|
||||
import {
|
||||
@ -31,21 +31,31 @@ import {
|
||||
DEFAULT_FIXED_SIDEMENU,
|
||||
DEFAULT_CONTENT_WIDTH_TYPE,
|
||||
DEFAULT_MULTI_TAB,
|
||||
HEADER_NOTICES
|
||||
HEADER_NOTICES,
|
||||
VUE_VERSION
|
||||
} from '@/store/mutation-types'
|
||||
|
||||
export default function Initializer () {
|
||||
store.commit('SET_SIDEBAR_TYPE', Vue.ls.get(SIDEBAR_TYPE, true))
|
||||
store.commit('TOGGLE_THEME', Vue.ls.get(DEFAULT_THEME, config.navTheme))
|
||||
store.commit('TOGGLE_LAYOUT_MODE', Vue.ls.get(DEFAULT_LAYOUT_MODE, config.layout))
|
||||
store.commit('TOGGLE_FIXED_HEADER', Vue.ls.get(DEFAULT_FIXED_HEADER, config.fixedHeader))
|
||||
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_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))
|
||||
store.commit('SET_PROJECT', Vue.ls.get(CURRENT_PROJECT))
|
||||
store.commit('SET_HEADER_NOTICES', Vue.ls.get(HEADER_NOTICES) || [])
|
||||
export default {
|
||||
install: (app) => {
|
||||
let vueVersion = vueProps.$localStorage.get(VUE_VERSION)
|
||||
if (vueVersion !== app.version) {
|
||||
vueVersion = app.version
|
||||
vueProps.$localStorage.clear()
|
||||
}
|
||||
|
||||
store.commit('SET_VUE_VERSION', vueVersion)
|
||||
store.commit('SET_SIDEBAR_TYPE', vueProps.$localStorage.get(SIDEBAR_TYPE, true))
|
||||
store.commit('TOGGLE_THEME', vueProps.$localStorage.get(DEFAULT_THEME, config.navTheme))
|
||||
store.commit('TOGGLE_LAYOUT_MODE', vueProps.$localStorage.get(DEFAULT_LAYOUT_MODE, config.layout))
|
||||
store.commit('TOGGLE_FIXED_HEADER', vueProps.$localStorage.get(DEFAULT_FIXED_HEADER, config.fixedHeader))
|
||||
store.commit('TOGGLE_FIXED_SIDERBAR', vueProps.$localStorage.get(DEFAULT_FIXED_SIDEMENU, config.fixSiderbar))
|
||||
store.commit('TOGGLE_CONTENT_WIDTH', vueProps.$localStorage.get(DEFAULT_CONTENT_WIDTH_TYPE, config.contentWidth))
|
||||
store.commit('TOGGLE_FIXED_HEADER_HIDDEN', vueProps.$localStorage.get(DEFAULT_FIXED_HEADER_HIDDEN, config.autoHideHeader))
|
||||
store.commit('TOGGLE_INVERTED', vueProps.$localStorage.get(DEFAULT_COLOR_INVERTED, config.invertedMode))
|
||||
store.commit('TOGGLE_COLOR', vueProps.$localStorage.get(DEFAULT_COLOR, config.primaryColor))
|
||||
store.commit('TOGGLE_MULTI_TAB', vueProps.$localStorage.get(DEFAULT_MULTI_TAB, config.multiTab))
|
||||
store.commit('SET_TOKEN', vueProps.$localStorage.get(ACCESS_TOKEN))
|
||||
store.commit('SET_PROJECT', vueProps.$localStorage.get(CURRENT_PROJECT))
|
||||
store.commit('SET_HEADER_NOTICES', vueProps.$localStorage.get(HEADER_NOTICES) || [])
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,8 +15,6 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
|
||||
@ -25,9 +23,13 @@ import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
// import { far } from '@fortawesome/free-regular-svg-icons'
|
||||
|
||||
import { faCentos, faUbuntu, faSuse, faRedhat, faFedora, faLinux, faFreebsd, faApple, faWindows, faJava } from '@fortawesome/free-brands-svg-icons'
|
||||
import { faLanguage, faCompactDisc, faCameraRetro } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faCompactDisc, faCameraRetro } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(faCentos, faUbuntu, faSuse, faRedhat, faFedora, faLinux, faFreebsd, faApple, faWindows, faJava)
|
||||
library.add(faLanguage, faCompactDisc, faCameraRetro)
|
||||
library.add(faCompactDisc, faCameraRetro)
|
||||
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon)
|
||||
export default {
|
||||
install: (app) => {
|
||||
app.component('font-awesome-icon', FontAwesomeIcon)
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,8 +15,6 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
/* eslint-disable */
|
||||
import Vue from 'vue'
|
||||
import {
|
||||
ConfigProvider,
|
||||
Layout,
|
||||
@ -34,7 +32,6 @@ import {
|
||||
Modal,
|
||||
Table,
|
||||
Tabs,
|
||||
Icon,
|
||||
Badge,
|
||||
Popover,
|
||||
Dropdown,
|
||||
@ -57,7 +54,6 @@ import {
|
||||
Popconfirm,
|
||||
Descriptions,
|
||||
message,
|
||||
notification,
|
||||
Affix,
|
||||
Timeline,
|
||||
Pagination,
|
||||
@ -68,61 +64,66 @@ import {
|
||||
AutoComplete,
|
||||
Collapse
|
||||
} from 'ant-design-vue'
|
||||
import VueClipboard from 'vue3-clipboard'
|
||||
import VueCropper from 'vue-cropper'
|
||||
|
||||
Vue.use(ConfigProvider)
|
||||
Vue.use(Layout)
|
||||
Vue.use(Input)
|
||||
Vue.use(InputNumber)
|
||||
Vue.use(Button)
|
||||
Vue.use(Switch)
|
||||
Vue.use(Radio)
|
||||
Vue.use(Checkbox)
|
||||
Vue.use(Select)
|
||||
Vue.use(Card)
|
||||
Vue.use(Form)
|
||||
Vue.use(Row)
|
||||
Vue.use(Col)
|
||||
Vue.use(Modal)
|
||||
Vue.use(Table)
|
||||
Vue.use(Tabs)
|
||||
Vue.use(Icon)
|
||||
Vue.use(Badge)
|
||||
Vue.use(Popover)
|
||||
Vue.use(Dropdown)
|
||||
Vue.use(Descriptions)
|
||||
Vue.use(List)
|
||||
Vue.use(Avatar)
|
||||
Vue.use(Breadcrumb)
|
||||
Vue.use(Steps)
|
||||
Vue.use(Spin)
|
||||
Vue.use(Menu)
|
||||
Vue.use(Drawer)
|
||||
Vue.use(Tooltip)
|
||||
Vue.use(Alert)
|
||||
Vue.use(Tag)
|
||||
Vue.use(Divider)
|
||||
Vue.use(DatePicker)
|
||||
Vue.use(TimePicker)
|
||||
Vue.use(Upload)
|
||||
Vue.use(Progress)
|
||||
Vue.use(Skeleton)
|
||||
Vue.use(Popconfirm)
|
||||
Vue.use(notification)
|
||||
Vue.use(Affix)
|
||||
Vue.use(Timeline)
|
||||
Vue.use(Pagination)
|
||||
Vue.use(Comment)
|
||||
Vue.use(Tree)
|
||||
Vue.use(Calendar)
|
||||
Vue.use(Slider)
|
||||
Vue.use(AutoComplete)
|
||||
Vue.use(Collapse)
|
||||
Vue.use(VueCropper)
|
||||
export default {
|
||||
install: (app) => {
|
||||
app.config.globalProperties.$confirm = Modal.confirm
|
||||
app.config.globalProperties.$message = message
|
||||
app.config.globalProperties.$info = Modal.info
|
||||
app.config.globalProperties.$success = Modal.success
|
||||
app.config.globalProperties.$error = Modal.error
|
||||
app.config.globalProperties.$warning = Modal.warning
|
||||
|
||||
Vue.prototype.$confirm = Modal.confirm
|
||||
Vue.prototype.$message = message
|
||||
Vue.prototype.$info = Modal.info
|
||||
Vue.prototype.$success = Modal.success
|
||||
Vue.prototype.$error = Modal.error
|
||||
Vue.prototype.$warning = Modal.warning
|
||||
app.use(VueClipboard, { autoSetContainer: true })
|
||||
app.use(VueCropper)
|
||||
app.use(ConfigProvider)
|
||||
app.use(Layout)
|
||||
app.use(Input)
|
||||
app.use(InputNumber)
|
||||
app.use(Button)
|
||||
app.use(Switch)
|
||||
app.use(Radio)
|
||||
app.use(Checkbox)
|
||||
app.use(Select)
|
||||
app.use(Card)
|
||||
app.use(Form)
|
||||
app.use(Row)
|
||||
app.use(Col)
|
||||
app.use(Modal)
|
||||
app.use(Table)
|
||||
app.use(Tabs)
|
||||
app.use(Badge)
|
||||
app.use(Popover)
|
||||
app.use(Dropdown)
|
||||
app.use(List)
|
||||
app.use(Avatar)
|
||||
app.use(Breadcrumb)
|
||||
app.use(Steps)
|
||||
app.use(Spin)
|
||||
app.use(Menu)
|
||||
app.use(Drawer)
|
||||
app.use(Tooltip)
|
||||
app.use(Alert)
|
||||
app.use(Tag)
|
||||
app.use(Divider)
|
||||
app.use(DatePicker)
|
||||
app.use(TimePicker)
|
||||
app.use(Upload)
|
||||
app.use(Progress)
|
||||
app.use(Skeleton)
|
||||
app.use(Popconfirm)
|
||||
// app.use(Notification)
|
||||
app.use(Affix)
|
||||
app.use(Timeline)
|
||||
app.use(Pagination)
|
||||
app.use(Comment)
|
||||
app.use(Tree)
|
||||
app.use(Calendar)
|
||||
app.use(Slider)
|
||||
app.use(AutoComplete)
|
||||
app.use(Collapse)
|
||||
app.use(Descriptions)
|
||||
}
|
||||
}
|
||||
|
||||
294
ui/src/core/lazy_lib/icons_use.js
Normal file
294
ui/src/core/lazy_lib/icons_use.js
Normal file
@ -0,0 +1,294 @@
|
||||
// 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.
|
||||
|
||||
import {
|
||||
ApartmentOutlined,
|
||||
ApiOutlined,
|
||||
AppstoreOutlined,
|
||||
ArrowDownOutlined,
|
||||
ArrowUpOutlined,
|
||||
ArrowsAltOutlined,
|
||||
AuditOutlined,
|
||||
BankOutlined,
|
||||
BarcodeOutlined,
|
||||
BarsOutlined,
|
||||
BellOutlined,
|
||||
BlockOutlined,
|
||||
BranchesOutlined,
|
||||
BookOutlined,
|
||||
BuildOutlined,
|
||||
BulbOutlined,
|
||||
BugOutlined,
|
||||
CalendarOutlined,
|
||||
CameraOutlined,
|
||||
CaretDownOutlined,
|
||||
CaretRightOutlined,
|
||||
CaretUpOutlined,
|
||||
CheckCircleOutlined,
|
||||
CheckCircleTwoTone,
|
||||
CheckOutlined,
|
||||
CheckSquareOutlined,
|
||||
ClockCircleOutlined,
|
||||
CloseCircleOutlined,
|
||||
CloseCircleTwoTone,
|
||||
CloseOutlined,
|
||||
CloudDownloadOutlined,
|
||||
CloudOutlined,
|
||||
CloudUploadOutlined,
|
||||
ClusterOutlined,
|
||||
CodeOutlined,
|
||||
CompassOutlined,
|
||||
CopyOutlined,
|
||||
CreditCardOutlined,
|
||||
DashboardOutlined,
|
||||
DatabaseOutlined,
|
||||
DeleteOutlined,
|
||||
DeleteTwoTone,
|
||||
DeploymentUnitOutlined,
|
||||
DesktopOutlined,
|
||||
DisconnectOutlined,
|
||||
DoubleLeftOutlined,
|
||||
DoubleRightOutlined,
|
||||
DownOutlined,
|
||||
DownloadOutlined,
|
||||
DragOutlined,
|
||||
EditOutlined,
|
||||
EnvironmentOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
EyeInvisibleOutlined,
|
||||
EyeOutlined,
|
||||
FileProtectOutlined,
|
||||
FilterOutlined,
|
||||
FilterTwoTone,
|
||||
FireOutlined,
|
||||
FlagOutlined,
|
||||
FolderAddOutlined,
|
||||
FolderOutlined,
|
||||
ForkOutlined,
|
||||
FormOutlined,
|
||||
ForwardOutlined,
|
||||
FullscreenOutlined,
|
||||
GatewayOutlined,
|
||||
GithubOutlined,
|
||||
GlobalOutlined,
|
||||
GoldOutlined,
|
||||
HddOutlined,
|
||||
HomeOutlined,
|
||||
IdcardOutlined,
|
||||
ImportOutlined,
|
||||
InboxOutlined,
|
||||
InfoCircleOutlined,
|
||||
InteractionOutlined,
|
||||
KeyOutlined,
|
||||
LinkOutlined,
|
||||
LoadingOutlined,
|
||||
LockOutlined,
|
||||
LoginOutlined,
|
||||
LogoutOutlined,
|
||||
MailOutlined,
|
||||
MedicineBoxOutlined,
|
||||
MenuFoldOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
MessageFilled,
|
||||
MessageOutlined,
|
||||
MinusCircleOutlined,
|
||||
MinusOutlined,
|
||||
MinusSquareOutlined,
|
||||
MoreOutlined,
|
||||
NotificationOutlined,
|
||||
NumberOutlined,
|
||||
PaperClipOutlined,
|
||||
PauseCircleOutlined,
|
||||
PictureOutlined,
|
||||
PieChartOutlined,
|
||||
PlayCircleOutlined,
|
||||
PlusCircleOutlined,
|
||||
PlusOutlined,
|
||||
PlusSquareOutlined,
|
||||
PoweroffOutlined,
|
||||
ProjectOutlined,
|
||||
QuestionCircleOutlined,
|
||||
ReadOutlined,
|
||||
ReconciliationOutlined,
|
||||
RedoOutlined,
|
||||
ReloadOutlined,
|
||||
RightCircleOutlined,
|
||||
RocketOutlined,
|
||||
SafetyCertificateOutlined,
|
||||
SafetyOutlined,
|
||||
SaveOutlined,
|
||||
ScheduleOutlined,
|
||||
ScissorOutlined,
|
||||
SearchOutlined,
|
||||
SettingOutlined,
|
||||
ShareAltOutlined,
|
||||
ShoppingOutlined,
|
||||
StopOutlined,
|
||||
SwapOutlined,
|
||||
SyncOutlined,
|
||||
TagOutlined,
|
||||
TeamOutlined,
|
||||
ThunderboltOutlined,
|
||||
ToolOutlined,
|
||||
TranslationOutlined,
|
||||
UndoOutlined,
|
||||
UsbOutlined,
|
||||
UserAddOutlined,
|
||||
UserOutlined,
|
||||
UploadOutlined,
|
||||
WifiOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
|
||||
export default {
|
||||
install: (app) => {
|
||||
app.component('ApartmentOutlined', ApartmentOutlined)
|
||||
app.component('ApiOutlined', ApiOutlined)
|
||||
app.component('AppstoreOutlined', AppstoreOutlined)
|
||||
app.component('ArrowDownOutlined', ArrowDownOutlined)
|
||||
app.component('ArrowUpOutlined', ArrowUpOutlined)
|
||||
app.component('ArrowsAltOutlined', ArrowsAltOutlined)
|
||||
app.component('AuditOutlined', AuditOutlined)
|
||||
app.component('BankOutlined', BankOutlined)
|
||||
app.component('BarcodeOutlined', BarcodeOutlined)
|
||||
app.component('BarsOutlined', BarsOutlined)
|
||||
app.component('BellOutlined', BellOutlined)
|
||||
app.component('BlockOutlined', BlockOutlined)
|
||||
app.component('BranchesOutlined', BranchesOutlined)
|
||||
app.component('BookOutlined', BookOutlined)
|
||||
app.component('BuildOutlined', BuildOutlined)
|
||||
app.component('BulbOutlined', BulbOutlined)
|
||||
app.component('BugOutlined', BugOutlined)
|
||||
app.component('CalendarOutlined', CalendarOutlined)
|
||||
app.component('CameraOutlined', CameraOutlined)
|
||||
app.component('CaretDownOutlined', CaretDownOutlined)
|
||||
app.component('CaretRightOutlined', CaretRightOutlined)
|
||||
app.component('CaretUpOutlined', CaretUpOutlined)
|
||||
app.component('CheckCircleOutlined', CheckCircleOutlined)
|
||||
app.component('CheckCircleTwoTone', CheckCircleTwoTone)
|
||||
app.component('CheckOutlined', CheckOutlined)
|
||||
app.component('CheckSquareOutlined', CheckSquareOutlined)
|
||||
app.component('ClockCircleOutlined', ClockCircleOutlined)
|
||||
app.component('CloseCircleOutlined', CloseCircleOutlined)
|
||||
app.component('CloseCircleTwoTone', CloseCircleTwoTone)
|
||||
app.component('CloseOutlined', CloseOutlined)
|
||||
app.component('CloudDownloadOutlined', CloudDownloadOutlined)
|
||||
app.component('CloudOutlined', CloudOutlined)
|
||||
app.component('CloudUploadOutlined', CloudUploadOutlined)
|
||||
app.component('ClusterOutlined', ClusterOutlined)
|
||||
app.component('CodeOutlined', CodeOutlined)
|
||||
app.component('CompassOutlined', CompassOutlined)
|
||||
app.component('CopyOutlined', CopyOutlined)
|
||||
app.component('CreditCardOutlined', CreditCardOutlined)
|
||||
app.component('DashboardOutlined', DashboardOutlined)
|
||||
app.component('DatabaseOutlined', DatabaseOutlined)
|
||||
app.component('DeleteOutlined', DeleteOutlined)
|
||||
app.component('DeleteTwoTone', DeleteTwoTone)
|
||||
app.component('DeploymentUnitOutlined', DeploymentUnitOutlined)
|
||||
app.component('DesktopOutlined', DesktopOutlined)
|
||||
app.component('DisconnectOutlined', DisconnectOutlined)
|
||||
app.component('DoubleLeftOutlined', DoubleLeftOutlined)
|
||||
app.component('DoubleRightOutlined', DoubleRightOutlined)
|
||||
app.component('DownOutlined', DownOutlined)
|
||||
app.component('DownloadOutlined', DownloadOutlined)
|
||||
app.component('DragOutlined', DragOutlined)
|
||||
app.component('EditOutlined', EditOutlined)
|
||||
app.component('EnvironmentOutlined', EnvironmentOutlined)
|
||||
app.component('ExclamationCircleOutlined', ExclamationCircleOutlined)
|
||||
app.component('EyeInvisibleOutlined', EyeInvisibleOutlined)
|
||||
app.component('EyeOutlined', EyeOutlined)
|
||||
app.component('FileProtectOutlined', FileProtectOutlined)
|
||||
app.component('FilterOutlined', FilterOutlined)
|
||||
app.component('FilterTwoTone', FilterTwoTone)
|
||||
app.component('FireOutlined', FireOutlined)
|
||||
app.component('FlagOutlined', FlagOutlined)
|
||||
app.component('FolderAddOutlined', FolderAddOutlined)
|
||||
app.component('FolderOutlined', FolderOutlined)
|
||||
app.component('ForkOutlined', ForkOutlined)
|
||||
app.component('FormOutlined', FormOutlined)
|
||||
app.component('ForwardOutlined', ForwardOutlined)
|
||||
app.component('FullscreenOutlined', FullscreenOutlined)
|
||||
app.component('GatewayOutlined', GatewayOutlined)
|
||||
app.component('GithubOutlined', GithubOutlined)
|
||||
app.component('GlobalOutlined', GlobalOutlined)
|
||||
app.component('GoldOutlined', GoldOutlined)
|
||||
app.component('HddOutlined', HddOutlined)
|
||||
app.component('HomeOutlined', HomeOutlined)
|
||||
app.component('IdcardOutlined', IdcardOutlined)
|
||||
app.component('ImportOutlined', ImportOutlined)
|
||||
app.component('InboxOutlined', InboxOutlined)
|
||||
app.component('InfoCircleOutlined', InfoCircleOutlined)
|
||||
app.component('InteractionOutlined', InteractionOutlined)
|
||||
app.component('KeyOutlined', KeyOutlined)
|
||||
app.component('LinkOutlined', LinkOutlined)
|
||||
app.component('LoadingOutlined', LoadingOutlined)
|
||||
app.component('LockOutlined', LockOutlined)
|
||||
app.component('LoginOutlined', LoginOutlined)
|
||||
app.component('LogoutOutlined', LogoutOutlined)
|
||||
app.component('MailOutlined', MailOutlined)
|
||||
app.component('MedicineBoxOutlined', MedicineBoxOutlined)
|
||||
app.component('MenuFoldOutlined', MenuFoldOutlined)
|
||||
app.component('MenuUnfoldOutlined', MenuUnfoldOutlined)
|
||||
app.component('MessageFilled', MessageFilled)
|
||||
app.component('MessageOutlined', MessageOutlined)
|
||||
app.component('MinusCircleOutlined', MinusCircleOutlined)
|
||||
app.component('MinusOutlined', MinusOutlined)
|
||||
app.component('MinusSquareOutlined', MinusSquareOutlined)
|
||||
app.component('MoreOutlined', MoreOutlined)
|
||||
app.component('NotificationOutlined', NotificationOutlined)
|
||||
app.component('NumberOutlined', NumberOutlined)
|
||||
app.component('PaperClipOutlined', PaperClipOutlined)
|
||||
app.component('PauseCircleOutlined', PauseCircleOutlined)
|
||||
app.component('PictureOutlined', PictureOutlined)
|
||||
app.component('PieChartOutlined', PieChartOutlined)
|
||||
app.component('PlayCircleOutlined', PlayCircleOutlined)
|
||||
app.component('PlusCircleOutlined', PlusCircleOutlined)
|
||||
app.component('PlusOutlined', PlusOutlined)
|
||||
app.component('PlusSquareOutlined', PlusSquareOutlined)
|
||||
app.component('PoweroffOutlined', PoweroffOutlined)
|
||||
app.component('ProjectOutlined', ProjectOutlined)
|
||||
app.component('QuestionCircleOutlined', QuestionCircleOutlined)
|
||||
app.component('ReadOutlined', ReadOutlined)
|
||||
app.component('ReconciliationOutlined', ReconciliationOutlined)
|
||||
app.component('RedoOutlined', RedoOutlined)
|
||||
app.component('ReloadOutlined', ReloadOutlined)
|
||||
app.component('RightCircleOutlined', RightCircleOutlined)
|
||||
app.component('RocketOutlined', RocketOutlined)
|
||||
app.component('SafetyCertificateOutlined', SafetyCertificateOutlined)
|
||||
app.component('SafetyOutlined', SafetyOutlined)
|
||||
app.component('SaveOutlined', SaveOutlined)
|
||||
app.component('ScheduleOutlined', ScheduleOutlined)
|
||||
app.component('ScissorOutlined', ScissorOutlined)
|
||||
app.component('SearchOutlined', SearchOutlined)
|
||||
app.component('SettingOutlined', SettingOutlined)
|
||||
app.component('ShareAltOutlined', ShareAltOutlined)
|
||||
app.component('ShoppingOutlined', ShoppingOutlined)
|
||||
app.component('StopOutlined', StopOutlined)
|
||||
app.component('SwapOutlined', SwapOutlined)
|
||||
app.component('SyncOutlined', SyncOutlined)
|
||||
app.component('TagOutlined', TagOutlined)
|
||||
app.component('TeamOutlined', TeamOutlined)
|
||||
app.component('ThunderboltOutlined', ThunderboltOutlined)
|
||||
app.component('ToolOutlined', ToolOutlined)
|
||||
app.component('TranslationOutlined', TranslationOutlined)
|
||||
app.component('UndoOutlined', UndoOutlined)
|
||||
app.component('UsbOutlined', UsbOutlined)
|
||||
app.component('UserAddOutlined', UserAddOutlined)
|
||||
app.component('UserOutlined', UserOutlined)
|
||||
app.component('UploadOutlined', UploadOutlined)
|
||||
app.component('WifiOutlined', WifiOutlined)
|
||||
}
|
||||
}
|
||||
@ -15,36 +15,31 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import Vue from 'vue'
|
||||
import VueStorage from 'vue-ls'
|
||||
import { vueApp } from '@/vue-app'
|
||||
import StoragePlugin from 'vue-web-storage'
|
||||
import config from '@/config/settings'
|
||||
|
||||
// base library'
|
||||
// import Viser from 'viser-vue'
|
||||
import VueCropper from 'vue-cropper'
|
||||
import '@/core/lazy_lib/components_use'
|
||||
import componentsUse from '@/core/lazy_lib/components_use'
|
||||
import iconsUse from '@/core/lazy_lib/icons_use'
|
||||
|
||||
import 'ant-design-vue/dist/antd.min.css'
|
||||
import 'vue-cropper/dist/index.css'
|
||||
import '@/style/vars.less'
|
||||
|
||||
// ext library
|
||||
import VueClipboard from 'vue-clipboard2'
|
||||
import PermissionHelper from '@/utils/helper/permission'
|
||||
|
||||
// customisation
|
||||
import Spin from 'ant-design-vue/es/spin/Spin'
|
||||
import { Spin } from 'ant-design-vue'
|
||||
|
||||
VueClipboard.config.autoSetContainer = true
|
||||
|
||||
// Vue.use(Viser)
|
||||
|
||||
Vue.use(VueStorage, config.storageOptions)
|
||||
Vue.use(VueClipboard)
|
||||
Vue.use(PermissionHelper)
|
||||
Vue.use(VueCropper)
|
||||
vueApp.use(StoragePlugin, config.storageOptions)
|
||||
vueApp.use(PermissionHelper)
|
||||
vueApp.use(componentsUse)
|
||||
vueApp.use(iconsUse)
|
||||
|
||||
Spin.setDefaultIndicator({
|
||||
indicator: (h) => {
|
||||
return <a-icon type="loading" style="font-size: 30px" spin />
|
||||
indicator: () => {
|
||||
return <loading-outlined style="font-size: 30px" spin />
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
// 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.
|
||||
|
||||
import Vue from 'vue'
|
||||
import VueStorage from 'vue-ls'
|
||||
import config from '@/config/settings'
|
||||
|
||||
// base library
|
||||
import Antd from 'ant-design-vue'
|
||||
import Viser from 'viser-vue'
|
||||
import VueCropper from 'vue-cropper'
|
||||
import 'ant-design-vue/dist/antd.less'
|
||||
import '@/style/vars.less'
|
||||
|
||||
// ext library
|
||||
import VueClipboard from 'vue-clipboard2'
|
||||
import PermissionHelper from '@/utils/helper/permission'
|
||||
// import '@/components/use'
|
||||
|
||||
// customisation
|
||||
import Spin from 'ant-design-vue/es/spin/Spin'
|
||||
|
||||
VueClipboard.config.autoSetContainer = true
|
||||
|
||||
Vue.use(Antd)
|
||||
Vue.use(Viser)
|
||||
Vue.use(VueStorage, config.storageOptions)
|
||||
Vue.use(VueClipboard)
|
||||
Vue.use(PermissionHelper)
|
||||
Vue.use(VueCropper)
|
||||
|
||||
Spin.setDefaultIndicator({
|
||||
indicator: (h) => {
|
||||
return <a-icon type="loading" style="font-size: 30px" spin />
|
||||
}
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user