From 24fd8e43e56df4e12bfb6d714860379361ce8840 Mon Sep 17 00:00:00 2001 From: utchoang Date: Thu, 24 Jun 2021 12:00:39 +0700 Subject: [PATCH 01/94] add new vue 3 library & and 2.x (beta) --- ui/.babelrc | 3 +++ ui/package.json | 53 +++++++++++++++++++++++------------------------- ui/vue.config.js | 29 -------------------------- 3 files changed, 28 insertions(+), 57 deletions(-) diff --git a/ui/.babelrc b/ui/.babelrc index 39fd99967510..7804579452ac 100644 --- a/ui/.babelrc +++ b/ui/.babelrc @@ -1,4 +1,7 @@ { + "plugins": [ + ["import", { "libraryName": "ant-design-vue", "libraryDirectory": "lib"}, "ant-design-vue"] + ], "env": { "test": { "plugins": ["require-context-hook"] diff --git a/ui/package.json b/ui/package.json index 3879ee92a6cf..f3d7102374d3 100644 --- a/ui/package.json +++ b/ui/package.json @@ -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.0-beta.3", "antd-theme-webpack-plugin": "^1.3.9", "axios": "^0.21.1", "babel-plugin-require-context-hook": "^1.0.0", @@ -47,48 +47,45 @@ "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.1.1", "vue-clipboard2": "^0.3.1", "vue-cropper": "0.5.6", - "vue-i18n": "^8.22.4", + "vue-i18n": "^9.1.6", "vue-ls": "^3.2.2", - "vue-router": "^3.5.1", - "vue-svg-component-runtime": "^1.0.1", + "vue-router": "^4.0.0-0", + "vue-web-storage": "^6.1.0", + "vue3-clipboard": "^1.0.0", "vuedraggable": "^2.24.3", - "vuex": "^3.6.2" + "vuex": "^4.0.0-0" }, "devDependencies": { "@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-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", + "babel-eslint": "^10.1.0", + "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": "^6.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" + "webpack": "^4.46.0" }, "eslintConfig": { "root": true, @@ -96,7 +93,7 @@ "node": true }, "extends": [ - "plugin:vue/strongly-recommended", + "plugin:vue/vue3-essential", "@vue/standard" ], "parserOptions": { diff --git a/ui/vue.config.js b/ui/vue.config.js index b087d68794cd..d580d351c252 100644 --- a/ui/vue.config.js +++ b/ui/vue.config.js @@ -95,35 +95,6 @@ const vueConfig = { config.module.rule('eslint').use('eslint-loader').tap( opts => ({ ...opts, emitWarning: false }) ) - - const svgRule = config.module.rule('svg') - svgRule.uses.clear() - svgRule - .oneOf('inline') - .resourceQuery(/inline/) - .use('vue-svg-icon-loader') - .loader('vue-svg-icon-loader') - .end() - .end() - .oneOf('external') - .use('file-loader') - .loader('file-loader') - .options({ - name: 'assets/[name].[hash:8].[ext]' - }) - /* svgRule.oneOf('inline') - .resourceQuery(/inline/) - .use('vue-svg-loader') - .loader('vue-svg-loader') - .end() - .end() - .oneOf('external') - .use('file-loader') - .loader('file-loader') - .options({ - name: 'assets/[name].[hash:8].[ext]' - }) - */ }, css: { From 17ec7b0b20f985e3ad749292f09421aae7add755 Mon Sep 17 00:00:00 2001 From: utchoang Date: Thu, 24 Jun 2021 13:10:03 +0700 Subject: [PATCH 02/94] edit config files, settings, utils, store,... corresponding to Vue 3 --- ui/src/config/eventBus.js | 4 +- ui/src/config/router.js | 29 ++-- ui/src/config/settings.js | 11 +- ui/src/core/bootstrap.js | 33 ++-- ui/src/core/lazy_lib/components_use.js | 115 ++++++------- ui/src/core/lazy_lib/icons_use.js | 177 ++++++++++++++++++++ ui/src/core/lazy_use.js | 35 ++-- ui/src/core/use.js | 50 ------ ui/src/locales/index.js | 35 +--- ui/src/main.js | 52 +++--- ui/src/permission.js | 118 +++++++------ ui/src/router/index.js | 31 +--- ui/src/store/index.js | 24 +-- ui/src/store/modules/app.js | 27 ++- ui/src/store/modules/user.js | 51 +++--- ui/src/utils/axios.js | 6 +- ui/src/utils/filter.js | 33 ++-- ui/src/utils/helper/permission.js | 8 +- ui/src/utils/plugins.js | 38 ++--- ui/src/{core/ext.js => utils/renderIcon.js} | 36 ++-- ui/src/utils/request.js | 25 ++- 21 files changed, 523 insertions(+), 415 deletions(-) create mode 100644 ui/src/core/lazy_lib/icons_use.js delete mode 100644 ui/src/core/use.js rename ui/src/{core/ext.js => utils/renderIcon.js} (50%) diff --git a/ui/src/config/eventBus.js b/ui/src/config/eventBus.js index ed61648940bc..fc30d618f2d6 100644 --- a/ui/src/config/eventBus.js +++ b/ui/src/config/eventBus.js @@ -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() diff --git a/ui/src/config/router.js b/ui/src/config/router.js index a07f0d68bb59..91c8df853daf 100644 --- a/ui/src/config/router.js +++ b/ui/src/config/router.js @@ -16,10 +16,11 @@ // 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 } from 'vue' import compute from '@/config/section/compute' import storage from '@/config/section/storage' @@ -42,7 +43,7 @@ function generateRouterMap (section) { name: section.name, path: '/' + section.name, hidden: section.hidden, - meta: { title: section.title, icon: section.icon, docHelp: Vue.prototype.$applyDocHelpMappings(section.docHelp), searchFilters: section.searchFilters }, + meta: { title: section.title, icon: section.icon, docHelp: window.appPrototype.$applyDocHelpMappings(section.docHelp), searchFilters: section.searchFilters }, component: RouteView } @@ -54,7 +55,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, @@ -63,7 +64,7 @@ function generateRouterMap (section) { title: child.title, name: child.name, icon: child.icon, - docHelp: Vue.prototype.$applyDocHelpMappings(child.docHelp), + docHelp: window.appPrototype.$applyDocHelpMappings(child.docHelp), permission: child.permission, resourceType: child.resourceType, filters: child.filters, @@ -85,7 +86,7 @@ function generateRouterMap (section) { title: child.title, name: child.name, icon: child.icon, - docHelp: Vue.prototype.$applyDocHelpMappings(child.docHelp), + docHelp: window.appPrototype.$applyDocHelpMappings(child.docHelp), permission: child.permission, resourceType: child.resourceType, params: child.params ? child.params : {}, @@ -121,7 +122,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 @@ -140,7 +141,7 @@ function generateRouterMap (section) { title: section.title, name: section.name, icon: section.icon, - docHelp: Vue.prototype.$applyDocHelpMappings(section.docHelp), + docHelp: window.appPrototype.$applyDocHelpMappings(section.docHelp), hidden: section.hidden, permission: section.permission, resourceType: section.resourceType, @@ -151,7 +152,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) }] } @@ -178,8 +179,8 @@ export function asyncRouterMap () { const routerMap = [{ path: '/', name: 'index', - component: BasicLayout, - meta: { icon: 'home' }, + component: shallowRef(BasicLayout), + meta: { icon: 'HomeOutlined' }, redirect: '/dashboard', children: [ { @@ -187,7 +188,7 @@ export function asyncRouterMap () { name: 'dashboard', meta: { title: 'label.dashboard', - icon: 'dashboard', + icon: 'DashboardOutlined', tabs: [ { name: 'dashboard', @@ -261,10 +262,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 = window.appPrototype.$config.plugins if (plugins && plugins.length > 0) { plugins.map(plugin => { routerMap[0].children.push({ diff --git a/ui/src/config/settings.js b/ui/src/config/settings.js index 6e599e7ca0b1..7d408cfd175e 100644 --- a/ui/src/config/settings.js +++ b/ui/src/config/settings.js @@ -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 } } diff --git a/ui/src/core/bootstrap.js b/ui/src/core/bootstrap.js index ceefe3fa6c88..475a519b2769 100644 --- a/ui/src/core/bootstrap.js +++ b/ui/src/core/bootstrap.js @@ -15,7 +15,6 @@ // specific language governing permissions and limitations // under the License. -import Vue from 'vue' import config from '@/config/settings' import store from '@/store/' import { @@ -34,18 +33,22 @@ import { ASYNC_JOB_IDS } 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_ASYNC_JOB_IDS', Vue.ls.get(ASYNC_JOB_IDS) || []) +export default { + install: (app) => { + window.ls = app.config.globalProperties.$localStorage + + store.commit('SET_SIDEBAR_TYPE', window.ls.get(SIDEBAR_TYPE, true)) + store.commit('TOGGLE_THEME', window.ls.get(DEFAULT_THEME, config.navTheme)) + store.commit('TOGGLE_LAYOUT_MODE', window.ls.get(DEFAULT_LAYOUT_MODE, config.layout)) + store.commit('TOGGLE_FIXED_HEADER', window.ls.get(DEFAULT_FIXED_HEADER, config.fixedHeader)) + store.commit('TOGGLE_FIXED_SIDERBAR', window.ls.get(DEFAULT_FIXED_SIDEMENU, config.fixSiderbar)) + store.commit('TOGGLE_CONTENT_WIDTH', window.ls.get(DEFAULT_CONTENT_WIDTH_TYPE, config.contentWidth)) + store.commit('TOGGLE_FIXED_HEADER_HIDDEN', window.ls.get(DEFAULT_FIXED_HEADER_HIDDEN, config.autoHideHeader)) + store.commit('TOGGLE_INVERTED', window.ls.get(DEFAULT_COLOR_INVERTED, config.invertedMode)) + store.commit('TOGGLE_COLOR', window.ls.get(DEFAULT_COLOR, config.primaryColor)) + store.commit('TOGGLE_MULTI_TAB', window.ls.get(DEFAULT_MULTI_TAB, config.multiTab)) + store.commit('SET_TOKEN', window.ls.get(ACCESS_TOKEN)) + store.commit('SET_PROJECT', window.ls.get(CURRENT_PROJECT)) + store.commit('SET_ASYNC_JOB_IDS', window.ls.get(ASYNC_JOB_IDS) || []) + } } diff --git a/ui/src/core/lazy_lib/components_use.js b/ui/src/core/lazy_lib/components_use.js index 72a57b88ec7f..21476727fed0 100644 --- a/ui/src/core/lazy_lib/components_use.js +++ b/ui/src/core/lazy_lib/components_use.js @@ -15,8 +15,6 @@ // specific language governing permissions and limitations // under the License. -/* eslint-disable */ -import Vue from 'vue' import { ConfigProvider, Layout, @@ -69,58 +67,63 @@ import { Collapse } from 'ant-design-vue' -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(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) +export default { + install: (app) => { + app.config.globalProperties.$confirm = Modal.confirm + app.config.globalProperties.$message = message + app.config.globalProperties.$notification = notification + 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.$notification = notification -Vue.prototype.$info = Modal.info -Vue.prototype.$success = Modal.success -Vue.prototype.$error = Modal.error -Vue.prototype.$warning = Modal.warning + 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(Icon) + 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) + } +} diff --git a/ui/src/core/lazy_lib/icons_use.js b/ui/src/core/lazy_lib/icons_use.js new file mode 100644 index 000000000000..7f61fb6bfcf0 --- /dev/null +++ b/ui/src/core/lazy_lib/icons_use.js @@ -0,0 +1,177 @@ +// 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 { + SafetyOutlined, + UserOutlined, + LockOutlined, + BlockOutlined, + AuditOutlined, + TranslationOutlined, + MenuFoldOutlined, + MenuUnfoldOutlined, + LogoutOutlined, + QuestionCircleOutlined, + ClockCircleOutlined, + ProjectOutlined, + LoadingOutlined, + BellOutlined, + GithubOutlined, + DashboardOutlined, + TeamOutlined, + ScheduleOutlined, + FlagOutlined, + DesktopOutlined, + BankOutlined, + ReadOutlined, + FilterOutlined, + HomeOutlined, + UserAddOutlined, + SyncOutlined, + EditOutlined, + PlusOutlined, + MoreOutlined, + SafetyCertificateOutlined, + DeleteOutlined, + PauseCircleOutlined, + AppstoreOutlined, + CalendarOutlined, + RocketOutlined, + BulbOutlined, + IdcardOutlined, + GlobalOutlined, + ClusterOutlined, + DeploymentUnitOutlined, + GatewayOutlined, + WifiOutlined, + DatabaseOutlined, + HddOutlined, + BarcodeOutlined, + CloudUploadOutlined, + CloudOutlined, + PictureOutlined, + SwapOutlined, + KeyOutlined, + GoldOutlined, + EnvironmentOutlined, + ApiOutlined, + ArrowUpOutlined, + ArrowDownOutlined, + ReloadOutlined, + CheckCircleOutlined, + CloseCircleOutlined, + CloseCircleTwoTone, + CheckCircleTwoTone, + DoubleLeftOutlined, + DoubleRightOutlined, + CaretUpOutlined, + CaretDownOutlined, + ShareAltOutlined, + FilterTwoTone, + SearchOutlined, + StopOutlined, + InfoCircleOutlined, + FolderOutlined, + LinkOutlined +} from '@ant-design/icons-vue' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' + +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' + +library.add(faCentos, faUbuntu, faSuse, faRedhat, faFedora, faLinux, faFreebsd, faApple, faWindows, faJava) +library.add(faLanguage, faCompactDisc, faCameraRetro) + +export default { + install: (app) => { + app.component('font-awesome-icon', FontAwesomeIcon) + + app.component('SafetyOutlined', SafetyOutlined) + app.component('UserOutlined', UserOutlined) + app.component('LockOutlined', LockOutlined) + app.component('BlockOutlined', BlockOutlined) + app.component('AuditOutlined', AuditOutlined) + app.component('TranslationOutlined', TranslationOutlined) + app.component('MenuFoldOutlined', MenuFoldOutlined) + app.component('MenuUnfoldOutlined', MenuUnfoldOutlined) + app.component('LogoutOutlined', LogoutOutlined) + app.component('QuestionCircleOutlined', QuestionCircleOutlined) + app.component('ClockCircleOutlined', ClockCircleOutlined) + app.component('ProjectOutlined', ProjectOutlined) + app.component('LoadingOutlined', LoadingOutlined) + app.component('BellOutlined', BellOutlined) + app.component('GithubOutlined', GithubOutlined) + app.component('DashboardOutlined', DashboardOutlined) + app.component('TeamOutlined', TeamOutlined) + app.component('ScheduleOutlined', ScheduleOutlined) + app.component('FlagOutlined', FlagOutlined) + app.component('DesktopOutlined', DesktopOutlined) + app.component('BankOutlined', BankOutlined) + app.component('ReadOutlined', ReadOutlined) + app.component('FilterOutlined', FilterOutlined) + app.component('HomeOutlined', HomeOutlined) + app.component('UserAddOutlined', UserAddOutlined) + app.component('SyncOutlined', SyncOutlined) + app.component('EditOutlined', EditOutlined) + app.component('PlusOutlined', PlusOutlined) + app.component('MoreOutlined', MoreOutlined) + app.component('SafetyCertificateOutlined', SafetyCertificateOutlined) + app.component('DeleteOutlined', DeleteOutlined) + app.component('PauseCircleOutlined', PauseCircleOutlined) + app.component('AppstoreOutlined', AppstoreOutlined) + app.component('BulbOutlined', BulbOutlined) + app.component('CalendarOutlined', CalendarOutlined) + app.component('RocketOutlined', RocketOutlined) + app.component('IdcardOutlined', IdcardOutlined) + app.component('GlobalOutlined', GlobalOutlined) + app.component('ClusterOutlined', ClusterOutlined) + app.component('DeploymentUnitOutlined', DeploymentUnitOutlined) + app.component('GatewayOutlined', GatewayOutlined) + app.component('WifiOutlined', WifiOutlined) + app.component('DatabaseOutlined', DatabaseOutlined) + app.component('HddOutlined', HddOutlined) + app.component('BarcodeOutlined', BarcodeOutlined) + app.component('CloudUploadOutlined', CloudUploadOutlined) + app.component('CloudOutlined', CloudOutlined) + app.component('PictureOutlined', PictureOutlined) + app.component('SwapOutlined', SwapOutlined) + app.component('KeyOutlined', KeyOutlined) + app.component('GoldOutlined', GoldOutlined) + app.component('EnvironmentOutlined', EnvironmentOutlined) + app.component('ApiOutlined', ApiOutlined) + app.component('ArrowUpOutlined', ArrowUpOutlined) + app.component('ArrowDownOutlined', ArrowDownOutlined) + app.component('ReloadOutlined', ReloadOutlined) + app.component('CheckCircleOutlined', CheckCircleOutlined) + app.component('CloseCircleOutlined', CloseCircleOutlined) + app.component('CloseCircleTwoTone', CloseCircleTwoTone) + app.component('CheckCircleTwoTone', CheckCircleTwoTone) + app.component('DoubleLeftOutlined', DoubleLeftOutlined) + app.component('DoubleRightOutlined', DoubleRightOutlined) + app.component('CaretUpOutlined', CaretUpOutlined) + app.component('CaretDownOutlined', CaretDownOutlined) + app.component('ShareAltOutlined', ShareAltOutlined) + app.component('FilterTwoTone', FilterTwoTone) + app.component('SearchOutlined', SearchOutlined) + app.component('StopOutlined', StopOutlined) + app.component('InfoCircleOutlined', InfoCircleOutlined) + app.component('FolderOutlined', FolderOutlined) + app.component('LinkOutlined', LinkOutlined) + } +} diff --git a/ui/src/core/lazy_use.js b/ui/src/core/lazy_use.js index e6a2067cb159..994b38641247 100644 --- a/ui/src/core/lazy_use.js +++ b/ui/src/core/lazy_use.js @@ -15,36 +15,33 @@ // 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 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 '@/style/vars.less' // ext library -import VueClipboard from 'vue-clipboard2' +import VueClipboard from 'vue3-clipboard' import PermissionHelper from '@/utils/helper/permission' // customisation -import Spin from 'ant-design-vue/es/spin/Spin' - -VueClipboard.config.autoSetContainer = true - -// Vue.use(Viser) - -Vue.use(VueStorage, config.storageOptions) -Vue.use(VueClipboard) -Vue.use(PermissionHelper) -Vue.use(VueCropper) +import { Spin } from 'ant-design-vue' Spin.setDefaultIndicator({ - indicator: (h) => { - return + indicator: () => { + return } }) + +export default { + install: (app) => { + app.use(VueClipboard, { autoSetContainer: true }) + app.use(PermissionHelper) + app.use(VueCropper) + app.use(componentsUse) + app.use(iconsUse) + } +} diff --git a/ui/src/core/use.js b/ui/src/core/use.js deleted file mode 100644 index 89c4f2e7b216..000000000000 --- a/ui/src/core/use.js +++ /dev/null @@ -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 - } -}) diff --git a/ui/src/locales/index.js b/ui/src/locales/index.js index f7a98aac9af5..542bb56e9744 100644 --- a/ui/src/locales/index.js +++ b/ui/src/locales/index.js @@ -1,38 +1,19 @@ -// 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 VueI18n from 'vue-i18n' +import { createI18n } from 'vue-i18n' const loadedLanguage = [] const messages = {} -Vue.use(VueI18n) - -export const i18n = new VueI18n({ - locale: Vue.ls ? Vue.ls.get('LOCALE') || 'en' : 'en', +export const i18n = createI18n({ + locale: 'en', fallbackLocale: 'en', silentTranslationWarn: true, - messages: messages + messages: messages, + silentFallbackWarn: true }) export function loadLanguageAsync (lang) { if (!lang) { - lang = Vue.ls ? Vue.ls.get('LOCALE') || 'en' : 'en' + lang = Window.ls ? Window.ls.get('LOCALE') || 'en' : 'en' } if (loadedLanguage.includes(lang)) { return Promise.resolve(setLanguage(lang)) @@ -45,10 +26,10 @@ export function loadLanguageAsync (lang) { function setLanguage (lang, message) { if (i18n) { - i18n.locale = lang + i18n.global.locale = lang if (message && Object.keys(message).length > 0) { - i18n.setLocaleMessage(lang, message) + i18n.global.setLocaleMessage(lang, message) } } diff --git a/ui/src/main.js b/ui/src/main.js index 064314b98de8..c88d885ffd3f 100644 --- a/ui/src/main.js +++ b/ui/src/main.js @@ -15,39 +15,49 @@ // specific language governing permissions and limitations // under the License. -import Vue from 'vue' +import { createApp } from 'vue' +import StoragePlugin from 'vue-web-storage' + import App from './App.vue' import router from './router' import store from './store' import { i18n, loadLanguageAsync } from './locales' import bootstrap from './core/bootstrap' -import './core/lazy_use' -import './core/ext' -import './permission' // permission control -import './utils/filter' // global filter +import lazyUsePlugs from './core/lazy_use' +import permission from './permission' // permission control +import filter from './utils/filter' // global filter + import { pollJobPlugin, notifierPlugin, toLocaleDatePlugin, configUtilPlugin } from './utils/plugins' import { VueAxios } from './utils/request' +import setting from '@/config/settings' + +const app = createApp(App) -Vue.config.productionTip = false -Vue.use(VueAxios, router) -Vue.use(pollJobPlugin) -Vue.use(notifierPlugin) -Vue.use(toLocaleDatePlugin) +app.config.productionTip = false +app.use(VueAxios, router) +app.use(pollJobPlugin) +app.use(permission) +app.use(notifierPlugin) +app.use(toLocaleDatePlugin) +app.use(configUtilPlugin) +app.use(filter) fetch('config.json').then(response => response.json()).then(config => { - Vue.prototype.$config = config - Vue.axios.defaults.baseURL = config.apiBase + app.config.globalProperties.$config = config + app.use(StoragePlugin, setting.storageOptions) + // set global localStorage for using + window.ls = app.config.globalProperties.$localStorage + window.appPrototype = app.config.globalProperties loadLanguageAsync().then(() => { - new Vue({ - router, - store, - i18n, - created: bootstrap, - render: h => h(App) - }).$mount('#app') + app.use(store) + .use(lazyUsePlugs) + .use(router) + .use(i18n) + .use(bootstrap) + .mount('#app') + + app.config.globalProperties.axios.defaults.baseURL = config.apiBase }) }) - -Vue.use(configUtilPlugin) diff --git a/ui/src/permission.js b/ui/src/permission.js index 8e975118611e..867344ab4055 100644 --- a/ui/src/permission.js +++ b/ui/src/permission.js @@ -16,7 +16,6 @@ // under the License. import Cookies from 'js-cookie' -import Vue from 'vue' import { i18n } from './locales' import router from './router' import store from './store' @@ -32,61 +31,70 @@ NProgress.configure({ showSpinner: false }) // NProgress Configuration const whiteList = ['login'] // no redirect whitelist -router.beforeEach((to, from, next) => { - // start progress bar - NProgress.start() - if (to.meta && typeof to.meta.title !== 'undefined') { - const title = i18n.t(to.meta.title) + ' - ' + Vue.prototype.$config.appTitle - setDocumentTitle(title) - } - const validLogin = Vue.ls.get(ACCESS_TOKEN) || Cookies.get('userid') || Cookies.get('userid', { path: '/client' }) - if (validLogin) { - if (to.path === '/user/login') { - next({ path: '/dashboard' }) - NProgress.done() - } else { - if (Object.keys(store.getters.apis).length === 0) { - const cachedApis = Vue.ls.get(APIS, {}) - if (Object.keys(cachedApis).length > 0) { - message.loading(`${i18n.t('label.loading')}...`, 1.5) +export default { + install: (app) => { + router.beforeEach((to, from, next) => { + // start progress bar + NProgress.start() + + if (to.meta && typeof to.meta.title !== 'undefined') { + const title = i18n.global.t(to.meta.title) + ' - ' + app.config.globalProperties.$config.appTitle + setDocumentTitle(title) + } + + const ls = app.config.globalProperties.$localStorage + const validLogin = ls.get(ACCESS_TOKEN) || Cookies.get('userid') || Cookies.get('userid', { path: '/client' }) + if (validLogin) { + if (to.path === '/user/login') { + next({ path: '/dashboard' }) + NProgress.done() + } else { + if (Object.keys(store.getters.apis).length === 0) { + const cachedApis = ls.get(APIS, {}) + if (Object.keys(cachedApis).length > 0) { + message.loading(`${i18n.global.t('label.loading')}...`, 1.5) + } + store + .dispatch('GetInfo') + .then(apis => { + store.dispatch('GenerateRoutes', { apis }).then(() => { + store.getters.addRouters.map(route => { + router.addRoute(route) + }) + const redirect = decodeURIComponent(from.query.redirect || to.path) + if (to.path === redirect) { + next({ ...to, replace: true }) + } else { + next({ path: redirect }) + } + }) + }) + .catch(() => { + notification.error({ + message: 'Error', + description: i18n.global.t('message.error.discovering.feature'), + duration: 0 + }) + store.dispatch('Logout').then(() => { + next({ path: '/user/login', query: { redirect: to.fullPath } }) + }) + }) + } else { + next() + } } - store - .dispatch('GetInfo') - .then(apis => { - store.dispatch('GenerateRoutes', { apis }).then(() => { - router.addRoutes(store.getters.addRouters) - const redirect = decodeURIComponent(from.query.redirect || to.path) - if (to.path === redirect) { - next({ ...to, replace: true }) - } else { - next({ path: redirect }) - } - }) - }) - .catch(() => { - notification.error({ - message: 'Error', - description: i18n.t('message.error.discovering.feature'), - duration: 0 - }) - store.dispatch('Logout').then(() => { - next({ path: '/user/login', query: { redirect: to.fullPath } }) - }) - }) } else { - next() + if (whiteList.includes(to.name)) { + next() + } else { + next({ path: '/user/login', query: { redirect: to.fullPath } }) + NProgress.done() + } } - } - } else { - if (whiteList.includes(to.name)) { - next() - } else { - next({ path: '/user/login', query: { redirect: to.fullPath } }) - NProgress.done() - } - } -}) + }) -router.afterEach(() => { - NProgress.done() // finish progress bar -}) + router.afterEach(() => { + NProgress.done() // finish progress bar + }) + } +} diff --git a/ui/src/router/index.js b/ui/src/router/index.js index 73bb1c8285e2..15f3b846397b 100644 --- a/ui/src/router/index.js +++ b/ui/src/router/index.js @@ -1,29 +1,10 @@ -// 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 Router from 'vue-router' +import { createRouter, createWebHashHistory } from 'vue-router' import { constantRouterMap } from '@/config/router' -Vue.use(Router) - -export default new Router({ - mode: 'hash', - base: process.env.BASE_URL, - scrollBehavior: () => ({ y: 0 }), +const router = createRouter({ + history: createWebHashHistory(process.env.BASE_URL), + scrollBehavior: () => ({ top: 0 }), routes: constantRouterMap }) + +export default router diff --git a/ui/src/store/index.js b/ui/src/store/index.js index e8c00f2d58c1..7fd936092dc3 100644 --- a/ui/src/store/index.js +++ b/ui/src/store/index.js @@ -1,31 +1,11 @@ -// 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 Vuex from 'vuex' +import { createStore } from 'vuex' import app from './modules/app' import user from './modules/user' import permission from './modules/permission' import getters from './getters' -Vue.use(Vuex) - -export default new Vuex.Store({ +export default createStore({ modules: { app, user, diff --git a/ui/src/store/modules/app.js b/ui/src/store/modules/app.js index a03fc63b2ef4..96c81fab15c7 100644 --- a/ui/src/store/modules/app.js +++ b/ui/src/store/modules/app.js @@ -15,7 +15,6 @@ // specific language governing permissions and limitations // under the License. -import Vue from 'vue' import { SIDEBAR_TYPE, DEFAULT_THEME, @@ -49,56 +48,56 @@ const app = { mutations: { SET_SIDEBAR_TYPE: (state, type) => { state.sidebar = type - Vue.ls.set(SIDEBAR_TYPE, type) + window.ls.set(SIDEBAR_TYPE, type) }, - CLOSE_SIDEBAR: (state) => { - Vue.ls.set(SIDEBAR_TYPE, true) + CLOSE_SIDEBAR: (state, ls) => { + window.ls.set(SIDEBAR_TYPE, true) state.sidebar = false }, TOGGLE_DEVICE: (state, device) => { state.device = device }, TOGGLE_THEME: (state, theme) => { - Vue.ls.set(DEFAULT_THEME, theme) + window.ls.set(DEFAULT_THEME, theme) state.theme = theme }, TOGGLE_LAYOUT_MODE: (state, layout) => { - Vue.ls.set(DEFAULT_LAYOUT_MODE, layout) + window.ls.set(DEFAULT_LAYOUT_MODE, layout) state.layout = layout }, TOGGLE_FIXED_HEADER: (state, fixed) => { - Vue.ls.set(DEFAULT_FIXED_HEADER, fixed) + window.ls.set(DEFAULT_FIXED_HEADER, fixed) state.fixedHeader = fixed }, TOGGLE_FIXED_SIDERBAR: (state, fixed) => { - Vue.ls.set(DEFAULT_FIXED_SIDEMENU, fixed) + window.ls.set(DEFAULT_FIXED_SIDEMENU, fixed) state.fixSiderbar = fixed }, TOGGLE_FIXED_HEADER_HIDDEN: (state, show) => { - Vue.ls.set(DEFAULT_FIXED_HEADER_HIDDEN, show) + window.ls.set(DEFAULT_FIXED_HEADER_HIDDEN, show) state.autoHideHeader = show }, TOGGLE_CONTENT_WIDTH: (state, type) => { - Vue.ls.set(DEFAULT_CONTENT_WIDTH_TYPE, type) + window.ls.set(DEFAULT_CONTENT_WIDTH_TYPE, type) state.contentWidth = type }, TOGGLE_COLOR: (state, color) => { - Vue.ls.set(DEFAULT_COLOR, color) + window.ls.set(DEFAULT_COLOR, color) state.color = color }, TOGGLE_INVERTED: (state, flag) => { - Vue.ls.set(DEFAULT_COLOR_INVERTED, flag) + window.ls.set(DEFAULT_COLOR_INVERTED, flag) state.inverted = flag }, TOGGLE_MULTI_TAB: (state, bool) => { - Vue.ls.set(DEFAULT_MULTI_TAB, bool) + window.ls.set(DEFAULT_MULTI_TAB, bool) state.multiTab = bool }, SET_METRICS: (state, bool) => { state.metrics = bool }, SET_USE_BROWSER_TIMEZONE: (state, bool) => { - Vue.ls.set(USE_BROWSER_TIMEZONE, bool) + window.ls.set(USE_BROWSER_TIMEZONE, bool) state.usebrowsertimezone = bool } }, diff --git a/ui/src/store/modules/user.js b/ui/src/store/modules/user.js index d764ae40ad68..d551403692a3 100644 --- a/ui/src/store/modules/user.js +++ b/ui/src/store/modules/user.js @@ -16,7 +16,6 @@ // under the License. import Cookies from 'js-cookie' -import Vue from 'vue' import md5 from 'md5' import message from 'ant-design-vue/es/message' import notification from 'ant-design-vue/es/notification' @@ -59,15 +58,15 @@ const user = { state.token = token }, SET_TIMEZONE_OFFSET: (state, timezoneoffset) => { - Vue.ls.set(TIMEZONE_OFFSET, timezoneoffset) + window.ls.set(TIMEZONE_OFFSET, timezoneoffset) state.timezoneoffset = timezoneoffset }, SET_USE_BROWSER_TIMEZONE: (state, bool) => { - Vue.ls.set(USE_BROWSER_TIMEZONE, bool) + window.ls.set(USE_BROWSER_TIMEZONE, bool) state.usebrowsertimezone = bool }, SET_PROJECT: (state, project = {}) => { - Vue.ls.set(CURRENT_PROJECT, project) + window.ls.set(CURRENT_PROJECT, project) state.project = project }, SET_NAME: (state, name) => { @@ -81,13 +80,13 @@ const user = { }, SET_APIS: (state, apis) => { state.apis = apis - Vue.ls.set(APIS, apis) + window.ls.set(APIS, apis) }, SET_FEATURES: (state, features) => { state.features = features }, SET_ASYNC_JOB_IDS: (state, jobsJsonArray) => { - Vue.ls.set(ASYNC_JOB_IDS, jobsJsonArray) + window.ls.set(ASYNC_JOB_IDS, jobsJsonArray) state.asyncJobIds = jobsJsonArray }, SET_LDAP: (state, isLdapEnabled) => { @@ -97,15 +96,15 @@ const user = { state.cloudian = cloudian }, RESET_THEME: (state) => { - Vue.ls.set(DEFAULT_THEME, 'light') + window.ls.set(DEFAULT_THEME, 'light') }, SET_ZONES: (state, zones) => { state.zones = zones - Vue.ls.set(ZONES, zones) + window.ls.set(ZONES, zones) }, SET_DOMAIN_STORE (state, domainStore) { state.domainStore = domainStore - Vue.ls.set(DOMAIN_STORE, domainStore) + window.ls.set(DOMAIN_STORE, domainStore) } }, @@ -125,11 +124,11 @@ const user = { Cookies.set('userfullname', result.firstname + ' ' + result.lastname, { expires: 1 }) Cookies.set('userid', result.userid, { expires: 1 }) Cookies.set('username', result.username, { expires: 1 }) - Vue.ls.set(ACCESS_TOKEN, result.sessionkey, 24 * 60 * 60 * 1000) + window.ls.set(ACCESS_TOKEN, result.sessionkey, 24 * 60 * 60 * 1000) commit('SET_TOKEN', result.sessionkey) commit('SET_TIMEZONE_OFFSET', result.timezoneoffset) - const cachedUseBrowserTimezone = Vue.ls.get(USE_BROWSER_TIMEZONE, false) + const cachedUseBrowserTimezone = window.ls.get(USE_BROWSER_TIMEZONE, false) commit('SET_USE_BROWSER_TIMEZONE', cachedUseBrowserTimezone) commit('SET_APIS', {}) @@ -154,11 +153,11 @@ const user = { GetInfo ({ commit }) { return new Promise((resolve, reject) => { - const cachedApis = Vue.ls.get(APIS, {}) - const cachedZones = Vue.ls.get(ZONES, []) - const cachedTimezoneOffset = Vue.ls.get(TIMEZONE_OFFSET, 0.0) - const cachedUseBrowserTimezone = Vue.ls.get(USE_BROWSER_TIMEZONE, false) - const domainStore = Vue.ls.get(DOMAIN_STORE, {}) + const cachedApis = window.ls.get(APIS, {}) + const cachedZones = window.ls.get(ZONES, []) + const cachedTimezoneOffset = window.ls.get(TIMEZONE_OFFSET, 0.0) + const cachedUseBrowserTimezone = window.ls.get(USE_BROWSER_TIMEZONE, false) + const domainStore = window.ls.get(DOMAIN_STORE, {}) const hasAuth = Object.keys(cachedApis).length > 0 commit('SET_DOMAIN_STORE', domainStore) @@ -184,7 +183,7 @@ const user = { reject(error) }) } else { - const hide = message.loading(i18n.t('message.discovering.feature'), 0) + const hide = message.loading(i18n.global.t('message.discovering.feature'), 0) api('listZones', { listall: true }).then(json => { const zones = json.listzonesresponse.zone || [] commit('SET_ZONES', zones) @@ -205,10 +204,12 @@ const user = { commit('SET_APIS', apis) resolve(apis) store.dispatch('GenerateRoutes', { apis }).then(() => { - router.addRoutes(store.getters.addRouters) + store.getters.addRouters.map(route => { + router.addRoute(route) + }) }) hide() - message.success(i18n.t('message.sussess.discovering.feature')) + message.success(i18n.global.t('message.sussess.discovering.feature')) }).catch(error => { reject(error) }) @@ -270,9 +271,9 @@ const user = { commit('SET_CLOUDIAN', {}) commit('RESET_THEME') commit('SET_DOMAIN_STORE', {}) - Vue.ls.remove(CURRENT_PROJECT) - Vue.ls.remove(ACCESS_TOKEN) - Vue.ls.remove(ASYNC_JOB_IDS) + window.ls.remove(CURRENT_PROJECT) + window.ls.remove(ACCESS_TOKEN) + window.ls.remove(ASYNC_JOB_IDS) logout(state.token).then(() => { message.destroy() @@ -287,7 +288,7 @@ const user = { }) }, AddAsyncJob ({ commit }, jobJson) { - var jobsArray = Vue.ls.get(ASYNC_JOB_IDS, []) + var jobsArray = window.ls.get(ASYNC_JOB_IDS, []) jobsArray.push(jobJson) commit('SET_ASYNC_JOB_IDS', jobsArray) }, @@ -307,7 +308,9 @@ const user = { commit('SET_APIS', apis) resolve(apis) store.dispatch('GenerateRoutes', { apis }).then(() => { - router.addRoutes(store.getters.addRouters) + store.getters.addRouters.map(route => { + router.addRoute(route) + }) }) }).catch(error => { reject(error) diff --git a/ui/src/utils/axios.js b/ui/src/utils/axios.js index 0583f93f29c4..ba3f6779db82 100644 --- a/ui/src/utils/axios.js +++ b/ui/src/utils/axios.js @@ -18,7 +18,7 @@ const VueAxios = { vm: {}, // eslint-disable-next-line no-unused-vars - install (Vue, instance) { + install (app, instance) { if (this.installed) { return } @@ -30,9 +30,9 @@ const VueAxios = { return } - Vue.axios = instance + app.config.globalProperties.axios = instance - Object.defineProperties(Vue.prototype, { + Object.defineProperties(app.config.globalProperties, { axios: { get: function get () { return instance diff --git a/ui/src/utils/filter.js b/ui/src/utils/filter.js index e91340a6680a..0253576ab6d4 100644 --- a/ui/src/utils/filter.js +++ b/ui/src/utils/filter.js @@ -15,23 +15,28 @@ // specific language governing permissions and limitations // under the License. -import Vue from 'vue' import moment from 'moment' import 'moment/locale/en-gb' moment.locale('en-gb') -Vue.filter('NumberFormat', function (value) { - if (!value) { - return '0' - } - const intPartFormat = value.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') - return intPartFormat -}) +export default { + install: (app) => { + app.config.globalProperties.$filters = { + NumberFormat: (value) => { + if (!value) { + return '0' + } + const intPartFormat = value.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') + return intPartFormat + }, -Vue.filter('dayjs', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') { - return moment(dataStr).format(pattern) -}) + dayjs: (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') => { + return moment(dataStr).format(pattern) + }, -Vue.filter('moment', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') { - return moment(dataStr).format(pattern) -}) + moment: (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') => { + return moment(dataStr).format(pattern) + } + } + } +} diff --git a/ui/src/utils/helper/permission.js b/ui/src/utils/helper/permission.js index f8925521b88d..78c90b496a8d 100644 --- a/ui/src/utils/helper/permission.js +++ b/ui/src/utils/helper/permission.js @@ -18,12 +18,12 @@ const PERMISSION_ENUM = { } -function plugin (Vue) { +function plugin (app) { if (plugin.installed) { return } - !Vue.prototype.$auth && Object.defineProperties(Vue.prototype, { + !app.config.globalProperties.$auth && Object.defineProperties(app.config.globalProperties, { $auth: { get () { const _this = this @@ -40,14 +40,14 @@ function plugin (Vue) { } }) - !Vue.prototype.$enum && Object.defineProperties(Vue.prototype, { + !app.config.globalProperties.$enum && Object.defineProperties(app.config.globalProperties, { $enum: { get () { // const _this = this; return (val) => { let result = PERMISSION_ENUM val && val.split('.').forEach(v => { - result = result && result[v] || null + result = (result && result[v]) || null }) return result } diff --git a/ui/src/utils/plugins.js b/ui/src/utils/plugins.js index 3276eea63e78..eb8adc85eb5f 100644 --- a/ui/src/utils/plugins.js +++ b/ui/src/utils/plugins.js @@ -22,8 +22,8 @@ import { message, notification } from 'ant-design-vue' import eventBus from '@/config/eventBus' export const pollJobPlugin = { - install (Vue) { - Vue.prototype.$pollJob = function (options) { + install (app) { + app.config.globalProperties.$pollJob = function (options) { /** * @param {String} jobId * @param {String} [name=''] @@ -40,13 +40,13 @@ export const pollJobPlugin = { const { jobId, name = '', - successMessage = i18n.t('label.success'), + successMessage = i18n.global.t('label.success'), successMethod = () => {}, - errorMessage = i18n.t('label.error'), + errorMessage = i18n.global.t('label.error'), errorMethod = () => {}, - loadingMessage = `${i18n.t('label.loading')}...`, + loadingMessage = `${i18n.global.t('label.loading')}...`, showLoading = true, - catchMessage = i18n.t('label.error.caught'), + catchMessage = i18n.global.t('label.error.caught'), catchMethod = () => {}, action = null } = options @@ -56,7 +56,7 @@ export const pollJobPlugin = { if (result.jobstatus === 1) { var content = successMessage if (successMessage === 'Success' && action && action.label) { - content = i18n.t(action.label) + content = i18n.global.t(action.label) } if (name) { content = content + ' - ' + name @@ -66,7 +66,7 @@ export const pollJobPlugin = { key: jobId, duration: 2 }) - eventBus.$emit('async-job-complete', action) + eventBus.emit('async-job-complete', action) successMethod(result) } else if (result.jobstatus === 2) { message.error({ @@ -76,7 +76,7 @@ export const pollJobPlugin = { }) var title = errorMessage if (action && action.label) { - title = i18n.t(action.label) + title = i18n.global.t(action.label) } var desc = result.jobresult.errortext if (name) { @@ -88,7 +88,7 @@ export const pollJobPlugin = { key: jobId, duration: 0 }) - eventBus.$emit('async-job-complete', action) + eventBus.emit('async-job-complete', action) errorMethod(result) } else if (result.jobstatus === 0) { if (showLoading) { @@ -105,7 +105,7 @@ export const pollJobPlugin = { }).catch(e => { console.error(`${catchMessage} - ${e}`) notification.error({ - message: i18n.t('label.error'), + message: i18n.global.t('label.error'), description: catchMessage, duration: 0 }) @@ -117,14 +117,14 @@ export const pollJobPlugin = { } export const notifierPlugin = { - install (Vue) { - Vue.prototype.$notifyError = function (error) { + install (app) { + app.config.globalProperties.$notifyError = function (error) { console.log(error) - var msg = i18n.t('message.request.failed') + var msg = i18n.global.t('message.request.failed') var desc = '' if (error && error.response) { if (error.response.status) { - msg = `${i18n.t('message.request.failed')} (${error.response.status})` + msg = `${i18n.global.t('message.request.failed')} (${error.response.status})` } if (error.message) { desc = error.message @@ -149,8 +149,8 @@ export const notifierPlugin = { } export const toLocaleDatePlugin = { - install (Vue) { - Vue.prototype.$toLocaleDate = function (date) { + install (app) { + app.config.globalProperties.$toLocaleDate = function (date) { var timezoneOffset = this.$store.getters.timezoneoffset if (this.$store.getters.usebrowsertimezone) { // Since GMT+530 is returned as -330 (mins to GMT) @@ -169,8 +169,8 @@ export const toLocaleDatePlugin = { } export const configUtilPlugin = { - install (Vue) { - Vue.prototype.$applyDocHelpMappings = function (docHelp) { + install (app) { + app.config.globalProperties.$applyDocHelpMappings = function (docHelp) { var docHelpMappings = this.$config.docHelpMappings if (docHelp && docHelpMappings && docHelpMappings.constructor === Object && Object.keys(docHelpMappings).length > 0) { diff --git a/ui/src/core/ext.js b/ui/src/utils/renderIcon.js similarity index 50% rename from ui/src/core/ext.js rename to ui/src/utils/renderIcon.js index ec418a2dd488..297e9ea9a828 100644 --- a/ui/src/core/ext.js +++ b/ui/src/utils/renderIcon.js @@ -15,19 +15,25 @@ // specific language governing permissions and limitations // under the License. -import Vue from 'vue' +import { h, resolveComponent } from 'vue' -import { library } from '@fortawesome/fontawesome-svg-core' -import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' - -// import { fab } from '@fortawesome/free-brands-svg-icons' -// import { fas } from '@fortawesome/free-solid-svg-icons' -// 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' - -library.add(faCentos, faUbuntu, faSuse, faRedhat, faFedora, faLinux, faFreebsd, faApple, faWindows, faJava) -library.add(faLanguage, faCompactDisc, faCameraRetro) - -Vue.component('font-awesome-icon', FontAwesomeIcon) +export default { + name: 'RenderIcon', + props: { + icon: { + type: String, + required: true + }, + props: { + type: Object, + default: {} + }, + event: { + type: Object, + default: {} + } + }, + render () { + return h(resolveComponent(this.icon), this.props, this.event) + } +} diff --git a/ui/src/utils/request.js b/ui/src/utils/request.js index 116a17117a6b..59169b47e91f 100644 --- a/ui/src/utils/request.js +++ b/ui/src/utils/request.js @@ -15,7 +15,6 @@ // specific language governing permissions and limitations // under the License. -import Vue from 'vue' import axios from 'axios' import router from '@/router' import { VueAxios } from './axios' @@ -34,7 +33,7 @@ const err = (error) => { console.log(response) if (response.status === 403) { const data = response.data - notification.error({ message: i18n.t('label.forbidden'), description: data.message }) + notification.error({ message: i18n.global.t('label.forbidden'), description: data.message }) } if (response.status === 401) { if (response.config && response.config.params && ['listIdps', 'cloudianIsEnabled'].includes(response.config.params.command)) { @@ -45,7 +44,7 @@ const err = (error) => { if (response.data[key].errortext.includes('not available for user')) { notification.error({ message: 'Error', - description: response.data[key].errortext + ' ' + i18n.t('error.unable.to.proceed'), + description: response.data[key].errortext + ' ' + i18n.global.t('error.unable.to.proceed'), duration: 0 }) return @@ -53,26 +52,26 @@ const err = (error) => { } } notification.error({ - message: i18n.t('label.unauthorized'), - description: i18n.t('message.authorization.failed'), + message: i18n.global.t('label.unauthorized'), + description: i18n.global.t('message.authorization.failed'), key: 'http-401', duration: 0 }) store.dispatch('Logout').then(() => { - if (router.history.current.path !== '/user/login') { - router.push({ path: '/user/login', query: { redirect: router.history.current.fullPath } }) + if (router.currentRoute.path !== '/user/login') { + router.push({ path: '/user/login', query: { redirect: router.currentRoute.fullPath } }) } }) } if (response.status === 404) { - notification.error({ message: i18n.t('label.not.found'), description: i18n.t('message.resource.not.found') }) + notification.error({ message: i18n.global.t('label.not.found'), description: i18n.global.t('message.resource.not.found') }) router.push({ path: '/exception/404' }) } } if (error.isAxiosError && !error.response) { notification.warn({ - message: error.message || i18n.t('message.network.error'), - description: i18n.t('message.network.error.description'), + message: error.message || i18n.global.t('message.network.error'), + description: i18n.global.t('message.network.error.description'), key: 'network-error' }) } @@ -83,7 +82,7 @@ const err = (error) => { service.interceptors.request.use(config => { if (config && config.params) { config.params.response = 'json' - const project = Vue.ls.get(CURRENT_PROJECT) + const project = window.ls.get(CURRENT_PROJECT) if (!config.params.projectid && project && project.id) { if (config.params.command === 'listTags') { config.params.projectid = '-1' @@ -102,8 +101,8 @@ service.interceptors.response.use((response) => { const installer = { vm: {}, - install (Vue) { - Vue.use(VueAxios, service) + install (app) { + app.use(VueAxios, service) } } From d238b5957d42613d4be257a822ad1fa14b75cb99 Mon Sep 17 00:00:00 2001 From: utchoang Date: Tue, 29 Jun 2021 11:41:39 +0700 Subject: [PATCH 03/94] edit layout and config to suit the new library --- ui/package.json | 2 + ui/src/assets/icons/kubernetes.svg | 9 --- ui/src/components/header/HeaderNotice.vue | 12 ++-- ui/src/components/header/ProjectMenu.vue | 20 ++++--- .../components/header/SamlDomainSwitcher.vue | 20 ++++--- ui/src/components/header/TranslationMenu.vue | 56 +++++++++--------- ui/src/components/header/UserMenu.vue | 59 ++++++++++--------- ui/src/components/page/GlobalFooter.vue | 2 +- ui/src/components/page/GlobalHeader.vue | 29 ++++----- ui/src/components/page/GlobalLayout.vue | 3 +- ui/src/components/page/PageHeader.vue | 6 +- ui/src/components/page/PageLayout.vue | 23 ++++---- ui/src/components/page/SHeaderNotice.vue | 4 +- ui/src/core/lazy_lib/icons_use.js | 24 +++++++- ui/src/layouts/RouteView.vue | 4 +- ui/src/layouts/UserLayout.vue | 2 +- ui/src/utils/renderIcon.js | 27 ++++++++- ui/vue.config.js | 24 ++++++++ 18 files changed, 193 insertions(+), 133 deletions(-) diff --git a/ui/package.json b/ui/package.json index f3d7102374d3..f64f1d1b2142 100644 --- a/ui/package.json +++ b/ui/package.json @@ -55,6 +55,7 @@ "vue-clipboard2": "^0.3.1", "vue-cropper": "0.5.6", "vue-i18n": "^9.1.6", + "vue-loader": "^16.2.0", "vue-ls": "^3.2.2", "vue-router": "^4.0.0-0", "vue-web-storage": "^6.1.0", @@ -85,6 +86,7 @@ "sass": "^1.35.1", "sass-loader": "^8.0.2", "uglifyjs-webpack-plugin": "^2.2.0", + "vue-svg-loader": "^0.17.0-beta.2", "webpack": "^4.46.0" }, "eslintConfig": { diff --git a/ui/src/assets/icons/kubernetes.svg b/ui/src/assets/icons/kubernetes.svg index e244023d9be4..f4115cb7dd80 100644 --- a/ui/src/assets/icons/kubernetes.svg +++ b/ui/src/assets/icons/kubernetes.svg @@ -41,15 +41,6 @@ inkscape:current-layer="layer1" /> - -