Merge pull request #1674 from jumpserver/dev

v2.21.0-rc5
This commit is contained in:
老广 2022-04-19 13:15:38 +08:00 committed by GitHub
commit ef5c1b2e23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 202 additions and 196 deletions

View File

@ -13,3 +13,9 @@ export function getCurrentOrg() {
method: 'get' method: 'get'
}) })
} }
export default {
getCurrentOrg,
getOrgDetail
}

View File

@ -69,3 +69,8 @@ export function logout() {
export function refreshSessionIdAge() { export function refreshSessionIdAge() {
return getProfile() return getProfile()
} }
export default {
getProfile,
getUserList
}

View File

@ -4,8 +4,7 @@ import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style import 'nprogress/nprogress.css' // progress bar style
import { startup } from '@/utils/startup' import { startup } from '@/utils/startup'
import store from '@/store' import store from '@/store'
import { getPropView, hasRouteViewPerm, isSameView } from '@/utils/jms' import { isSameView } from '@/utils/jms'
import Vue from 'vue'
NProgress.configure({ NProgress.configure({
showSpinner: false showSpinner: false
@ -30,20 +29,6 @@ function generateViewRoutesIfChange({ to, from }) {
} }
} }
async function changeCurrentViewIfNeed({ to, from, next }) {
if (!to.path || isSameView(to, from)) {
return
}
const hasPerm = hasRouteViewPerm(to)
Vue.$log.debug('Change has current view, has perm: ', hasPerm)
if (hasPerm) {
return
}
const view = getPropView()
Vue.$log.debug('Get prop view and goto: ', view)
next(`/${view}`)
}
function setPageTitle() { function setPageTitle() {
const currentRoute = router.currentRoute const currentRoute = router.currentRoute
const loginTitle = store.getters.publicSettings['LOGIN_TITLE'] const loginTitle = store.getters.publicSettings['LOGIN_TITLE']
@ -53,12 +38,6 @@ function setPageTitle() {
} }
} }
router.beforeResolve(async(to, from, next) => {
/* must call `next` */
await changeCurrentViewIfNeed({ to, from, next })
next()
})
router.afterEach(async(to, from) => { router.afterEach(async(to, from) => {
// finish progress bar // finish progress bar
await setPageTitle() await setPageTitle()

View File

@ -1274,6 +1274,7 @@
"Sender": "Sender", "Sender": "Sender",
"MarkAsRead": "Mark as read", "MarkAsRead": "Mark as read",
"OneClickRead": "Currently read", "OneClickRead": "Currently read",
"AllClickRead": "All read",
"OneClickReadMsg": "Are you sure you want to mark the current information as read?", "OneClickReadMsg": "Are you sure you want to mark the current information as read?",
"NoUnreadMsg": "No unread messages", "NoUnreadMsg": "No unread messages",
"SiteMessage": "Site messages", "SiteMessage": "Site messages",

View File

@ -1314,6 +1314,7 @@
"Sender": "送信者", "Sender": "送信者",
"MarkAsRead": "マークはすでに読みました。", "MarkAsRead": "マークはすでに読みました。",
"OneClickRead": "現在の既読", "OneClickRead": "現在の既読",
"AllClickRead": "すべて既読",
"OneClickReadMsg": "本当に現在の情報を既読としてマークしますか?", "OneClickReadMsg": "本当に現在の情報を既読としてマークしますか?",
"NoUnreadMsg": "未読メッセージはありません", "NoUnreadMsg": "未読メッセージはありません",
"SiteMessage": "駅内の手紙", "SiteMessage": "駅内の手紙",

View File

@ -1315,6 +1315,7 @@
"Sender": "发送人", "Sender": "发送人",
"MarkAsRead": "标记已读", "MarkAsRead": "标记已读",
"OneClickRead": "当前已读", "OneClickRead": "当前已读",
"AllClickRead": "全部已读",
"OneClickReadMsg": "你确定要将当前信息标记为已读吗?", "OneClickReadMsg": "你确定要将当前信息标记为已读吗?",
"NoUnreadMsg": "暂无未读消息", "NoUnreadMsg": "暂无未读消息",
"SiteMessage": "站内信", "SiteMessage": "站内信",

View File

@ -7,10 +7,18 @@
<i class="el-icon-arrow-down el-icon--right" /> <i class="el-icon-arrow-down el-icon--right" />
</span> </span>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item icon="el-icon-user" command="profile">{{ $t('common.nav.Profile') }}</el-dropdown-item> <el-dropdown-item icon="el-icon-user" command="profile">
<el-dropdown-item v-if="$hasPerm('authentication.view_accesskey')" icon="el-icon-key" command="apiKey">{{ $t('common.nav.APIKey') }}</el-dropdown-item> {{ $t('common.nav.Profile') }}
<el-dropdown-item v-if="$store.getters.publicSettings.AUTH_TEMP_TOKEN" icon="el-icon-magic-stick" command="tempPassword">{{ $t('common.nav.TempPassword') }}</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item divided command="logout"><svg-icon icon-class="logout" style="margin-right: 4px" />{{ $t('common.nav.Logout') }}</el-dropdown-item> <el-dropdown-item v-if="$hasPerm('authentication.view_accesskey')" icon="el-icon-key" command="apiKey">
{{ $t('common.nav.APIKey') }}
</el-dropdown-item>
<el-dropdown-item v-if="$store.getters.publicSettings.AUTH_TEMP_TOKEN" icon="el-icon-magic-stick" command="tempPassword">
{{ $t('common.nav.TempPassword') }}
</el-dropdown-item>
<el-dropdown-item divided command="logout"><svg-icon icon-class="logout" style="margin-right: 4px" />
{{ $t('common.nav.Logout') }}
</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</div> </div>
@ -29,11 +37,7 @@ export default {
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
'currentUser', 'currentUser'
'currentRole',
'currentOrgRoles',
'orgs',
'currentOrgPerms'
]) ])
}, },
created() { created() {
@ -52,7 +56,7 @@ export default {
this.$router.push('/profile/key') this.$router.push('/profile/key')
break break
case 'tempPassword': case 'tempPassword':
this.$router.push('/profile/tempPassword') this.$router.push('/profile/temp-password')
} }
}, },
logout() { logout() {

View File

@ -11,7 +11,7 @@
</template> </template>
<el-option-group <el-option-group
v-for="group in orgOption" v-for="group in orgGroups"
:key="group.label" :key="group.label"
:label="group.label" :label="group.label"
class="option-group" class="option-group"
@ -29,7 +29,6 @@
</span> </span>
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
</el-option> </el-option>
</el-option-group> </el-option-group>
</el-select> </el-select>
</template> </template>
@ -55,15 +54,10 @@ export default {
computed: { computed: {
...mapGetters([ ...mapGetters([
'currentOrg', 'currentOrg',
'currentRole', 'usingOrgs',
'orgs' 'currentViewRoute'
]) ]),
}, orgActionsGroup() {
created() {
this.init()
},
methods: {
init() {
const orgActions = { const orgActions = {
label: this.$t('xpack.Organization.OrganizationList'), label: this.$t('xpack.Organization.OrganizationList'),
options: [ options: [
@ -82,14 +76,25 @@ export default {
] ]
} }
const hasPerms = this.$hasPerm('orgs.view_organization | orgs.add_organization') const hasPerms = this.$hasPerm('orgs.view_organization | orgs.add_organization')
this.orgOption = [ const isConsole = this.currentViewRoute.name === 'console'
(hasPerms && orgActions), return hasPerms && isConsole ? orgActions : {}
{
label: this.$t('xpack.Organization.AllOrganization'),
options: this.orgs
}
]
}, },
orgChoicesGroup() {
return {
label: this.$t('xpack.Organization.AllOrganization'),
options: this.usingOrgs
}
},
orgGroups() {
return [
this.orgActionsGroup,
this.orgChoicesGroup
]
}
},
created() {
},
methods: {
changeOrg(orgId) { changeOrg(orgId) {
if (orgId === 'create') { if (orgId === 'create') {
this.$router.push({ name: 'OrganizationCreate' }) this.$router.push({ name: 'OrganizationCreate' })

View File

@ -6,6 +6,7 @@
</el-link> </el-link>
</el-badge> </el-badge>
<el-drawer <el-drawer
class="drawer"
:visible.sync="show" :visible.sync="show"
:before-close="handleClose" :before-close="handleClose"
:modal="false" :modal="false"
@ -17,7 +18,7 @@
<div slot="title"> <div slot="title">
<span>{{ $t('notifications.SiteMessage') }}</span> <span>{{ $t('notifications.SiteMessage') }}</span>
<div v-if="unreadMsgCount !== 0" class="msg-list-all-read-btn" @click.stop="oneClickRead(messages)"> <div v-if="unreadMsgCount !== 0" class="msg-list-all-read-btn" @click.stop="oneClickRead(messages)">
<a> {{ $t('notifications.OneClickRead') }}</a> <a style="vertical-align: sub;"> {{ $t('notifications.AllClickRead') }}</a>
</div> </div>
</div> </div>
<div v-if="unreadMsgCount !== 0" class="msg-list"> <div v-if="unreadMsgCount !== 0" class="msg-list">
@ -201,6 +202,9 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.drawer {
height: calc(100% - 40px);
}
.el-badge ::v-deep .el-badge__content.is-fixed{ .el-badge ::v-deep .el-badge__content.is-fixed{
top:10px; top:10px;
} }

View File

@ -19,7 +19,6 @@
<el-menu-item <el-menu-item
v-for="view of views" v-for="view of views"
:key="view.name" :key="view.name"
v-perms="view.perms"
:index="view.name" :index="view.name"
> >
<i v-if="mode === 'horizontal'" class="icons" :class="view.meta.icon" /> <i v-if="mode === 'horizontal'" class="icons" :class="view.meta.icon" />
@ -31,6 +30,7 @@
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import store from '@/store'
export default { export default {
name: 'ViewSwitcher', name: 'ViewSwitcher',
@ -49,12 +49,17 @@ export default {
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
'currentViewRoute' 'currentViewRoute',
'viewRoutes'
]), ]),
views() { views() {
return this.$store.state.permission.addRoutes.filter( return this.viewRoutes.filter((item) => {
item => item.meta?.showNavSwitcher let show = item.meta?.showNavSwitcher
) if (typeof show === 'function') {
show = show()
}
return show
})
}, },
viewsMapper() { viewsMapper() {
const mapper = {} const mapper = {}
@ -67,11 +72,12 @@ export default {
return this.viewsMapper[this.currentViewRoute.name] return this.viewsMapper[this.currentViewRoute.name]
} }
}, },
created() {
},
methods: { methods: {
handleSelectView(key, keyPath) { async handleSelectView(key, keyPath) {
const routeName = this.viewsMapper[key] || '/' const routeName = this.viewsMapper[key] || '/'
localStorage.setItem('PreView', key)
// Next init
await store.dispatch('app/reset')
this.$router.push(routeName) this.$router.push(routeName)
} }
} }

View File

@ -4,6 +4,7 @@ import i18n from '@/i18n/i18n'
import SessionRoutes from './sessions' import SessionRoutes from './sessions'
import LogRoutes from './logs' import LogRoutes from './logs'
import empty from '@/layout/empty' import empty from '@/layout/empty'
import store from '@/store'
export default { export default {
path: '/audit/', path: '/audit/',
@ -13,8 +14,10 @@ export default {
meta: { meta: {
title: i18n.t('common.nav.Audits'), title: i18n.t('common.nav.Audits'),
icon: 'el-icon-s-claim', icon: 'el-icon-s-claim',
showNavSwitcher: true, showNavSwitcher: () => {
permissions: ['rbac.view_audit'], return store.getters.auditOrgs.length > 0
},
permissions: [],
view: 'audit' view: 'audit'
}, },
children: [ children: [

View File

@ -1,6 +1,7 @@
import Layout from '@/layout/index' import Layout from '@/layout/index'
import i18n from '@/i18n/i18n' import i18n from '@/i18n/i18n'
import empty from '@/layout/empty' import empty from '@/layout/empty'
import store from '@/store'
import UsersRoute from './users' import UsersRoute from './users'
import AssetsRoute from './assets' import AssetsRoute from './assets'
@ -20,8 +21,10 @@ export default {
icon: 'el-icon-s-operation', icon: 'el-icon-s-operation',
view: 'console', view: 'console',
type: 'view', type: 'view',
showNavSwitcher: true, showNavSwitcher: () => {
permissions: ['rbac.view_console'] return store.getters.consoleOrgs.length > 0
},
permissions: []
}, },
children: [ children: [
{ {

View File

@ -50,15 +50,15 @@ export const constantRoutes = [
icon: 'dashboard', icon: 'dashboard',
title: i18n.t('route.Overview') title: i18n.t('route.Overview')
}, },
beforeEnter: (to, from, next) => { beforeEnter: async(to, from, next) => {
console.log('Enter home view') const preferView = getPropView()
const preferView = getPermedPreferView()
if (preferView) { if (preferView) {
console.log('Go to preferView: ', preferView) await store.dispatch('app/reset')
next(`/${preferView}/`) next(`/${preferView}/`)
return false return false
} }
next() next()
return false
} }
} }
] ]
@ -83,7 +83,8 @@ import workbenchViewRoutes from './workbench'
import ticketsRoutes from './tickets' import ticketsRoutes from './tickets'
import settingsRoutes from './settings' import settingsRoutes from './settings'
import profileRoutes from './profile' import profileRoutes from './profile'
import { getPermedPreferView } from '@/utils/jms' import { getPropView } from '@/utils/jms'
import store from '@/store'
/** /**
* admin * admin

View File

@ -55,7 +55,7 @@ export default {
} }
}, },
{ {
path: '/profile/tempPassword', path: '/profile/temp-password',
component: () => import('@/views/profile/TempPassword'), component: () => import('@/views/profile/TempPassword'),
name: 'TempPassword', name: 'TempPassword',
meta: { meta: {

View File

@ -2,6 +2,7 @@ import Layout from '@/layout'
import i18n from '@/i18n/i18n' import i18n from '@/i18n/i18n'
import { BASE_URL } from '@/utils/common' import { BASE_URL } from '@/utils/common'
import empty from '@/layout/empty' import empty from '@/layout/empty'
import store from '@/store'
export default { export default {
path: '/workbench/', path: '/workbench/',
@ -13,9 +14,11 @@ export default {
type: 'view', type: 'view',
view: 'workbench', view: 'workbench',
icon: 'el-icon-user-solid', icon: 'el-icon-user-solid',
showNavSwitcher: true, showNavSwitcher: () => {
return store.getters.workbenchOrgs.length > 0
},
showOrganization: true, showOrganization: true,
permissions: ['rbac.view_workbench'] permissions: []
}, },
children: [ children: [
// 404 page must be placed at the end !!! // 404 page must be placed at the end !!!

View File

@ -1,8 +1,13 @@
const getters = { const getters = {
sidebar: state => state.app.sidebar, sidebar: state => state.app.sidebar,
device: state => state.app.device, device: state => state.app.device,
inited: state => state.app.inited,
isMobile: state => state.app.device === 'mobile', isMobile: state => state.app.device === 'mobile',
token: state => state.users.token, token: state => state.users.token,
consoleOrgs: state => state.users.consoleOrgs,
auditOrgs: state => state.users.auditOrgs,
workbenchOrgs: state => state.users.workbenchOrgs,
usingOrgs: state => state.users.usingOrgs,
currentOrg: state => state.users.currentOrg, currentOrg: state => state.users.currentOrg,
currentOrgIsDefault: state => state.users.currentOrg['is_default'], currentOrgIsDefault: state => state.users.currentOrg['is_default'],
currentOrgIsRoot: state => { currentOrgIsRoot: state => {
@ -11,6 +16,7 @@ const getters = {
currentRole: state => state.users.currentRole, currentRole: state => state.users.currentRole,
currentUser: state => state.users.profile, currentUser: state => state.users.profile,
currentViewRoute: state => state.permission.currentViewRoute, currentViewRoute: state => state.permission.currentViewRoute,
viewRoutes: state => state.permission.addRoutes,
publicSettings: state => state.settings.publicSettings, publicSettings: state => state.settings.publicSettings,
currentOrgRoles: state => state.users.roles, currentOrgRoles: state => state.users.roles,
currentOrgPerms: state => state.users.perms, currentOrgPerms: state => state.users.perms,
@ -19,7 +25,6 @@ const getters = {
tableConfig: state => state.table.tableConfig, tableConfig: state => state.table.tableConfig,
currentUserIsSuperAdmin: state => state.users.isSuperAdmin, currentUserIsSuperAdmin: state => state.users.isSuperAdmin,
currentUserIsAdmin: state => state.users.isAdmin, currentUserIsAdmin: state => state.users.isAdmin,
hasValidLicense: state => state.settings.hasValidLicense, hasValidLicense: state => state.settings.hasValidLicense
orgs: state => state.users.orgs
} }
export default getters export default getters

View File

@ -5,7 +5,8 @@ const state = {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false withoutAnimation: false
}, },
device: 'desktop' device: 'desktop',
inited: false
} }
const mutations = { const mutations = {
@ -25,6 +26,9 @@ const mutations = {
}, },
TOGGLE_DEVICE: (state, device) => { TOGGLE_DEVICE: (state, device) => {
state.device = device state.device = device
},
SET_INIT: (state, value) => {
state.inited = value
} }
} }
@ -37,6 +41,12 @@ const actions = {
}, },
toggleDevice({ commit }, device) { toggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device) commit('TOGGLE_DEVICE', device)
},
init({ commit }) {
commit('SET_INIT', true)
},
reset({ commit }) {
commit('SET_INIT', false)
} }
} }

View File

@ -193,9 +193,6 @@ const actions = {
break break
} }
} }
if (viewRoute.meta?.showNavSwitcher) {
localStorage.setItem('PreView', viewName)
}
commit('SET_VIEW_ROUTE', viewRoute) commit('SET_VIEW_ROUTE', viewRoute)
resolve(viewRoute) resolve(viewRoute)
}) })

View File

@ -1,12 +1,11 @@
import { logout, getProfile } from '@/api/users' import { logout, getProfile as apiGetProfile } from '@/api/users'
import { import {
getCurrentOrgLocal, getCurrentOrgLocal,
getCurrentRoleLocal,
getTokenFromCookie, getTokenFromCookie,
saveCurrentOrgLocal, saveCurrentOrgLocal
saveCurrentRoleLocal
} from '@/utils/auth' } from '@/utils/auth'
import { resetRouter } from '@/router' import { resetRouter } from '@/router'
import Vue from 'vue'
const getDefaultState = () => { const getDefaultState = () => {
return { return {
@ -14,10 +13,14 @@ const getDefaultState = () => {
currentOrg: '', currentOrg: '',
profile: {}, profile: {},
username: '', username: '',
orgs: [], auditOrgs: [],
consoleOrgs: [],
workbenchOrgs: [],
usingOrgs: [],
perms: [], perms: [],
MFAVerifyAt: null, MFAVerifyAt: null,
isSuperAdmin: false, isSuperAdmin: false,
isAdmin: false,
hasAdminPerm: false, hasAdminPerm: false,
hasAuditPerm: false hasAuditPerm: false
} }
@ -34,57 +37,37 @@ const mutations = {
}, },
SET_PROFILE: (state, profile) => { SET_PROFILE: (state, profile) => {
state.profile = profile state.profile = profile
const username = profile.username state.username = profile.username
state.username = username
state.currentOrg = getCurrentOrgLocal(username)
state.currentRole = getCurrentRoleLocal(username)
state.perms = profile.perms state.perms = profile.perms
state.orgs = profile.orgs state.consoleOrgs = profile['console_orgs']
state.workbenchOrgs = profile['workbench_orgs']
state.auditOrgs = profile['audit_orgs']
state.currentOrg = getCurrentOrgLocal(profile.username)
}, },
SET_ORGS: (state, orgs) => { SET_USING_ORGS: (state, orgs) => {
state.orgs = orgs state.usingOrgs = orgs
}, },
MODIFY_ORG: (state, org) => { MODIFY_ORG: (state, org) => {
state.orgs = state.orgs.map(oldOrg => { state.consoleOrgs = state.consoleOrgs.map(oldOrg => {
if (oldOrg.id === org.id) { if (oldOrg.id === org.id) {
oldOrg.name = org.name oldOrg.name = org.name
} }
return oldOrg return oldOrg
} })
)
}, },
ADD_ORG: (state, org) => { ADD_ORG: (state, org) => {
state.orgs.push(org) state.consoleOrgs.push(org)
}, },
SET_CURRENT_ORG(state, org) { SET_CURRENT_ORG(state, org) {
state.currentOrg = org state.currentOrg = org
saveCurrentOrgLocal(state.username, org) saveCurrentOrgLocal(state.username, org)
}, },
SET_CURRENT_ROLE(state, role) {
state.currentRole = role
saveCurrentRoleLocal(state.username, role)
},
SET_MFA_VERIFY(state) { SET_MFA_VERIFY(state) {
state.MFAVerifyAt = (new Date()).valueOf() state.MFAVerifyAt = (new Date()).valueOf()
} }
} }
const actions = { const actions = {
// user login
// login({ commit }, userInfo) {
// const { username, password } = userInfo
// return new Promise((resolve, reject) => {
// login({ username: username.trim(), password: password }).then(response => {
// const { data } = response
// commit('SET_TOKEN', data.token)
// setToken(data.token)
// resolve()
// }).catch(error => {
// reject(error)
// })
// })
// },
// get user Profile // get user Profile
getProfile({ commit, state }, refresh = false) { getProfile({ commit, state }, refresh = false) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -92,7 +75,7 @@ const actions = {
resolve(state.profile) resolve(state.profile)
return return
} }
getProfile().then(response => { apiGetProfile().then(response => {
if (!response) { if (!response) {
reject('Verification failed, please Login again.') reject('Verification failed, please Login again.')
} }
@ -104,24 +87,17 @@ const actions = {
}) })
}) })
}, },
getInOrgs({ commit, dispatch, state }, refresh) {
return new Promise((resolve, reject) => {
if (!refresh && state.role && state.role.length > 0) {
return resolve(state.roles)
}
dispatch('getProfile').then(profile => {
const { orgs } = profile
commit('SET_ORGS', orgs)
resolve(orgs)
}).catch((e) => reject(e))
})
},
addAdminOrg({ commit, state }, org) { addAdminOrg({ commit, state }, org) {
commit('ADD_ORG', org) commit('ADD_ORG', org)
}, },
modifyOrg({ commit, state }, org) { modifyOrg({ commit, state }, org) {
commit('MODIFY_ORG', org) commit('MODIFY_ORG', org)
}, },
setUsingOrgs({ commit, state, rootGetters }) {
const viewName = rootGetters.currentViewRoute.name
const usingOrgs = state[`${viewName}Orgs`] || []
commit('SET_USING_ORGS', usingOrgs)
},
// user logout // user logout
logout({ commit, state }) { logout({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -135,23 +111,16 @@ const actions = {
}) })
}) })
}, },
// remove token
resetToken({ commit }) {
return new Promise(resolve => {
// removeToken() // must remove token first
commit('RESET_STATE')
resolve()
})
},
setCurrentOrg({ commit }, data) { setCurrentOrg({ commit }, data) {
commit('SET_CURRENT_ORG', data) commit('SET_CURRENT_ORG', data)
}, },
setCurrentRole({ commit }, role) {
commit('SET_CURRENT_ROLE', role)
},
setMFAVerify({ commit }) { setMFAVerify({ commit }) {
commit('SET_MFA_VERIFY') commit('SET_MFA_VERIFY')
},
changeToView({ commit }, viewName) {
const usingOrgs = state[`${viewName}Orgs`] || []
Vue.$log.debug('Set using orgs: ', viewName, usingOrgs)
commit('SET_USING_ORGS', usingOrgs)
} }
} }

View File

@ -5,7 +5,10 @@ const CURRENT_ORG_KEY = 'jms_current_org'
const CURRENT_ROLE_KEY = 'jms_current_role' const CURRENT_ROLE_KEY = 'jms_current_role'
export function getTokenFromCookie() { export function getTokenFromCookie() {
const cookieNamePrefix = VueCookie.get('SESSION_COOKIE_NAME_PREFIX', '') let cookieNamePrefix = VueCookie.get('SESSION_COOKIE_NAME_PREFIX', '')
if (cookieNamePrefix === '""') {
cookieNamePrefix = ''
}
return VueCookie.get(cookieNamePrefix + TOKEN_KEY) return VueCookie.get(cookieNamePrefix + TOKEN_KEY)
} }

View File

@ -1,5 +1,4 @@
import store from '@/store' import store from '@/store'
import Vue from 'vue'
import { constantRoutes } from '@/router' import { constantRoutes } from '@/router'
export function openTaskPage(taskId) { export function openTaskPage(taskId) {
@ -80,24 +79,13 @@ export function hasActionPerm(route, action) {
return hasPermission(permsRequired) return hasPermission(permsRequired)
} }
const viewRequirePermsMapper = { export function getPermedViews() {
console: 'rbac.view_console', const viewShowMapper = [
audit: 'rbac.view_audit', ['console', store.getters.consoleOrgs.length > 0],
workbench: 'rbac.view_workbench' ['audit', store.getters.auditOrgs.length > 0],
} ['workbench', true]
]
export function getViewRequirePerms(view) { return viewShowMapper.filter(i => i[1]).map(i => i[0])
return viewRequirePermsMapper[view] || 'super'
}
export function getPermedPreferView() {
for (const [view, perms] of Object.entries(viewRequirePermsMapper)) {
const hasPerm = hasPermission(perms)
Vue.$log.debug('Has view perm: ', view, hasPerm)
if (hasPerm) {
return view
}
}
} }
export function isSameView(to, from) { export function isSameView(to, from) {
@ -107,13 +95,13 @@ export function isSameView(to, from) {
} }
export function getPropView() { export function getPropView() {
const hasPermedViews = getPermedViews()
const preView = localStorage.getItem('PreView') const preView = localStorage.getItem('PreView')
const preViewRequirePerms = getViewRequirePerms(preView) const hasPerm = hasPermedViews.indexOf(preView) > -1
const hasPerm = hasPermission(preViewRequirePerms)
if (hasPerm) { if (hasPerm) {
return preView return preView
} }
const preferView = getPermedPreferView() const preferView = getPermedViews()[0]
if (preferView) { if (preferView) {
return preferView return preferView
} }
@ -125,18 +113,8 @@ export function getApiUrlRequirePerms(url, action) {
return [`${app}.${action}_${resource}`] return [`${app}.${action}_${resource}`]
} }
export function getRouteViewRequirePerms(route) { export function isViewHasOrgs(viewName) {
const viewName = route.path.split('/')[1] return getPermedViews().indexOf(viewName) > -1
return getViewRequirePerms(viewName)
}
export function hasRouteViewPerm(route) {
if (route.name) {
return hasPermission(route.meta.permissions)
}
const viewName = route.path.split('/')[1]
const perms = getViewRequirePerms(viewName)
return hasPermission(perms)
} }
export function getConstRouteName() { export function getConstRouteName() {

View File

@ -3,10 +3,9 @@ import { getOrgDetail } from '@/api/orgs'
import store from '@/store' import store from '@/store'
export const DEFAULT_ORG_ID = '00000000-0000-0000-0000-000000000002' export const DEFAULT_ORG_ID = '00000000-0000-0000-0000-000000000002'
// const ROOT_ORG_ID = '00000000-0000-0000-0000-000000000000'
function getPropOrg() { function getPropOrg() {
const orgs = store.getters.orgs const orgs = store.getters.usingOrgs
const defaultOrg = orgs.find((item) => item.is_default) const defaultOrg = orgs.find((item) => item.is_default)
if (defaultOrg) { if (defaultOrg) {
return defaultOrg return defaultOrg
@ -22,7 +21,7 @@ function change2PropOrg() {
function hasCurrentOrgPermission() { function hasCurrentOrgPermission() {
const currentOrg = store.getters.currentOrg const currentOrg = store.getters.currentOrg
const currentOrgId = currentOrg.id const currentOrgId = currentOrg.id
const orgs = store.getters.orgs const orgs = store.getters.usingOrgs
return orgs.find((item) => item.id === currentOrgId) return orgs.find((item) => item.id === currentOrgId)
} }
@ -33,7 +32,6 @@ async function changeOrg(orgId) {
} else { } else {
console.debug('Change to org: ', org) console.debug('Change to org: ', org)
} }
localStorage.setItem('PreView', '')
store.dispatch('users/setCurrentOrg', org).then(() => { store.dispatch('users/setCurrentOrg', org).then(() => {
// console.log('Set current org to: ', org) // console.log('Set current org to: ', org)

View File

@ -1,15 +1,15 @@
// import getPageTitle from '@/utils/get-page-title' // import getPageTitle from '@/utils/get-page-title'
import store from '@/store' import store from '@/store'
import router from '@/router' import router, { resetRouter } from '@/router'
import Vue from 'vue' import Vue from 'vue'
import { Message } from 'element-ui' import { Message } from 'element-ui'
import 'nprogress/nprogress.css' // progress bar style import 'nprogress/nprogress.css' // progress bar style
import { getTokenFromCookie } from '@/utils/auth' import { getTokenFromCookie } from '@/utils/auth'
import orgUtil from '@/utils/org' import orgUtil from '@/utils/org'
import { getCurrentOrg } from '@/api/orgs' import orgs from '@/api/orgs'
import { getPropView, isViewHasOrgs } from '@/utils/jms'
const whiteList = ['/login', process.env.VUE_APP_LOGIN_PATH] // no redirect whitelist const whiteList = ['/login', process.env.VUE_APP_LOGIN_PATH] // no redirect whitelist
let initial = false
function reject(msg) { function reject(msg) {
return new Promise((resolve, reject) => reject(msg)) return new Promise((resolve, reject) => reject(msg))
@ -51,25 +51,28 @@ async function getPublicSetting({ to, from, next }) {
} }
async function refreshCurrentOrg() { async function refreshCurrentOrg() {
getCurrentOrg().then(org => { orgs.getCurrentOrg().then(org => {
store.dispatch('users/setCurrentOrg', org) store.dispatch('users/setCurrentOrg', org)
}) })
} }
async function changeCurrentOrgIfNeed({ to, from, next }) { async function changeCurrentOrgIfNeed({ to, from, next }) {
await store.dispatch('users/getInOrgs') await store.dispatch('users/getProfile')
const adminOrgs = store.getters.orgs
if (!adminOrgs || adminOrgs.length === 0) { const usingOrgs = store.getters.usingOrgs
if (!usingOrgs || usingOrgs.length === 0) {
Vue.$log.error('No using orgs, return: ', usingOrgs)
return return
} }
await refreshCurrentOrg() await refreshCurrentOrg()
const currentOrg = store.getters.currentOrg const currentOrg = store.getters.currentOrg
if (!currentOrg || typeof currentOrg !== 'object') { if (!currentOrg || typeof currentOrg !== 'object') {
Vue.$log.error('Current org is null or not a object')
orgUtil.change2PropOrg() orgUtil.change2PropOrg()
return reject('Change prop org') return reject('Change prop org')
} }
if (!orgUtil.hasCurrentOrgPermission()) { if (!orgUtil.hasCurrentOrgPermission()) {
console.error('Not has current org permission') Vue.$log.error('Not has current org permission')
orgUtil.change2PropOrg() orgUtil.change2PropOrg()
return reject('Change prop org') return reject('Change prop org')
} }
@ -77,6 +80,7 @@ async function changeCurrentOrgIfNeed({ to, from, next }) {
export async function generatePageRoutes({ to, from, next }) { export async function generatePageRoutes({ to, from, next }) {
// determine whether the user has obtained his permission roles through getProfile // determine whether the user has obtained his permission roles through getProfile
resetRouter()
try { try {
// try get user profile // try get user profile
@ -113,18 +117,38 @@ export async function checkUserFirstLogin({ to, from, next }) {
} }
} }
export async function startup({ to, from, next }) { export async function changeCurrentViewIfNeed({ to, from, next }) {
if (initial) { let viewName = to.path.split('/')[1]
return true // 这几个是需要检测的, 切换视图组织时,避免 404
if (['console', 'audit', 'workbench', ''].indexOf(viewName) === -1) {
Vue.$log.debug('Current view no need check', viewName)
return
} }
initial = true
const has = isViewHasOrgs(viewName)
Vue.$log.debug('Change has current view, has perm: ', has)
if (has) {
await store.dispatch('users/changeToView', viewName)
return
}
viewName = getPropView()
// Next 之前要重置 init 状态,否则这些路由守卫就不走了
await store.dispatch('app/reset')
next(`/${viewName}/`)
return new Promise((resolve, reject) => reject(''))
}
export async function startup({ to, from, next }) {
// if (store.getters.inited) { return true }
if (store.getters.inited) { return true }
await store.dispatch('app/init')
// set page title // set page title
await getPublicSetting({ to, from, next }) await getPublicSetting({ to, from, next })
// await setHeadTitle({ to, from, next })
await checkLogin({ to, from, next }) await checkLogin({ to, from, next })
await generatePageRoutes({ to, from, next }) await changeCurrentViewIfNeed({ to, from, next })
await changeCurrentOrgIfNeed({ to, from, next }) await changeCurrentOrgIfNeed({ to, from, next })
await generatePageRoutes({ to, from, next })
await checkUserFirstLogin({ to, from, next }) await checkUserFirstLogin({ to, from, next })
return true return true
} }

View File

@ -44,7 +44,7 @@ export default {
title: vm.$t('xpack.Execute'), title: vm.$t('xpack.Execute'),
name: 'execute', name: 'execute',
type: 'info', type: 'info',
can: () => vm.$hasPerm('xpack.change_syncinstancetask'), can: () => vm.$hasPerm('xpack.add_syncinstancetaskexecution'),
callback: function(data) { callback: function(data) {
this.$axios.get(`/api/v1/xpack/cloud/sync-instance-tasks/${data.row.id}/run/`).then(res => { this.$axios.get(`/api/v1/xpack/cloud/sync-instance-tasks/${data.row.id}/run/`).then(res => {
openTaskPage(res['task']) openTaskPage(res['task'])

View File

@ -1,6 +1,5 @@
<template> <template>
<div> <div>
<Announcement />
<GenericTreeListPage <GenericTreeListPage
:table-config="tableConfig" :table-config="tableConfig"
:header-actions="headerActions" :header-actions="headerActions"

View File

@ -9,6 +9,7 @@
<script> <script>
import { GenericListPage } from '@/layout/components' import { GenericListPage } from '@/layout/components'
import { ShowKeyFormatter } from '@/components/TableFormatters'
export default { export default {
components: { components: {
@ -26,7 +27,8 @@ export default {
], ],
columnsMeta: { columnsMeta: {
secret: { secret: {
label: this.$t('common.nav.TempPassword') label: this.$t('common.nav.TempPassword'),
formatter: ShowKeyFormatter
}, },
expire: { expire: {
label: this.$t('setting.Expired') + '( s )' label: this.$t('setting.Expired') + '( s )'

View File

@ -56,8 +56,8 @@ export default {
} }
}, },
mounted() { mounted() {
if (this.$store.state.users.profile.orgs?.length > 0) { if (this.$store.getters.consoleOrgs) {
this.initial.org_id = this.$store.state.users.profile.orgs[0].id this.initial.org_id = this.$store.getters.consoleOrgs[0].id
} }
this.loading = false this.loading = false
} }

View File

@ -84,7 +84,6 @@ export default {
}, },
methods: { methods: {
init() { init() {
console.log('this.object.state', this.object)
this.loading = true this.loading = true
const url = `/api/v1/tickets/tickets/${this.object.id}/session/` const url = `/api/v1/tickets/tickets/${this.object.id}/session/`
this.$axios({ this.$axios({