1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-16 22:50:10 +03:00

F OpenNebula/one#5422: Add sunstone views request

This commit is contained in:
Sergio Betanzos 2021-07-02 10:54:18 +02:00
parent 17b79abfff
commit b578aa0b2e
No known key found for this signature in database
GPG Key ID: E3E704F097737136
7 changed files with 113 additions and 5 deletions

View File

@ -28,14 +28,17 @@ const APP_NAME = _APPS.sunstone.name
const SunstoneApp = () => {
const { isLogged, jwt, firstRender } = useAuth()
const { getAuthUser, logout } = useAuthApi()
const { getAuthUser, logout, getSunstoneViews } = useAuthApi()
const { changeTitle } = useGeneralApi()
React.useEffect(() => {
(async () => {
try {
jwt && changeTitle(APP_NAME)
jwt && getAuthUser()
if (jwt) {
changeTitle(APP_NAME)
getAuthUser()
getSunstoneViews()
}
} catch {
logout()
}

View File

@ -0,0 +1,56 @@
import * as React from 'react'
import { Button } from '@material-ui/core'
import { ViewGrid as ViewIcon, VerifiedBadge as SelectIcon } from 'iconoir-react'
import { useAuth, useAuthApi } from 'client/features/Auth'
import Search from 'client/components/Search'
import HeaderPopover from 'client/components/Header/Popover'
import headerStyles from 'client/components/Header/styles'
const View = () => {
const classes = headerStyles()
const { view, views } = useAuth()
const { changeView } = useAuthApi()
const handleChangeView = newView => {
newView && newView !== view && changeView(newView)
}
const renderResult = (viewName, handleClose) => (
<Button
key={`view-${viewName}`}
fullWidth
className={classes.groupButton}
onClick={() => {
handleChangeView(viewName)
handleClose()
}}
>
{viewName}
{viewName === view && <SelectIcon size='1em' />}
</Button>
)
const viewNames = React.useMemo(() => Object.keys(views), [view])
return (
<HeaderPopover
id='view-list'
icon={<ViewIcon />}
buttonProps={{ 'data-cy': 'header-view-button', variant: 'outlined' }}
headerTitle='Switch view'
>
{({ handleClose }) => (
<Search
list={viewNames}
maxResults={5}
renderResult={item => renderResult(item, handleClose)}
/>
)}
</HeaderPopover>
)
}
export default View

View File

@ -31,6 +31,7 @@ import { useAuth } from 'client/features/Auth'
import { useGeneral, useGeneralApi } from 'client/features/General'
import User from 'client/components/Header/User'
import View from 'client/components/Header/View'
import Group from 'client/components/Header/Group'
import Zone from 'client/components/Header/Zone'
import headerStyles from 'client/components/Header/styles'
@ -75,6 +76,7 @@ const Header = ({ scrollContainer }) => {
)}
<Box flexGrow={isMobile ? 1 : 0} textAlign="end">
<User />
<View />
{!isOneAdmin && <Group />}
<Zone />
</Box>

View File

@ -0,0 +1,29 @@
import { createAsyncThunk, createAction } from '@reduxjs/toolkit'
import { authService } from 'client/features/Auth/services'
import { logout } from 'client/features/Auth/actions'
import { httpCodes } from 'server/utils/constants'
import { T } from 'client/constants'
export const getSunstoneViews = createAsyncThunk(
'sunstone/views',
async (_, { dispatch }) => {
try {
const views = await authService.getSunstoneViews() ?? {}
// const config = await authService.getSunstoneConfig()
return {
views,
view: Object.keys(views)[0]
}
} catch (error) {
status === httpCodes.unauthorized.id && dispatch(logout(T.SessionExpired))
}
}
)
export const changeView = createAction(
'sunstone/change-view',
view => ({ payload: { view } })
)

View File

@ -3,6 +3,7 @@ import { useDispatch, useSelector, shallowEqual } from 'react-redux'
import { unwrapResult } from '@reduxjs/toolkit'
import * as actions from 'client/features/Auth/actions'
import * as actionsView from 'client/features/Auth/actionsView'
export const useAuth = () => {
const auth = useSelector(state => state.auth, shallowEqual)
@ -32,6 +33,9 @@ export const useAuthApi = () => {
login: user => unwrapDispatch(actions.login(user)),
getAuthUser: () => dispatch(actions.getUser()),
changeGroup: data => unwrapDispatch(actions.changeGroup(data)),
logout: () => dispatch(actions.logout())
logout: () => dispatch(actions.logout()),
getSunstoneViews: () => unwrapDispatch(actionsView.getSunstoneViews()),
changeView: data => unwrapDispatch(actionsView.changeView(data))
}
}

View File

@ -14,5 +14,15 @@ export const authService = ({
if (!res?.id || res?.id !== httpCodes.ok.id) throw res
return res?.data?.USER ?? {}
}),
getSunstoneViews: () => RestClient.get('/api/sunstone/views').then(res => {
if (!res?.id || res?.id !== httpCodes.ok.id) throw res
return res?.data ?? {}
}),
getSunstoneConfig: () => RestClient.get('/api/user/config').then(res => {
if (!res?.id || res?.id !== httpCodes.ok.id) throw res
return res?.data ?? {}
})
})

View File

@ -1,6 +1,7 @@
import { createSlice } from '@reduxjs/toolkit'
import { login, getUser, logout, changeFilter, changeGroup } from 'client/features/Auth/actions'
import { getSunstoneViews, changeView } from 'client/features/Auth/actionsView'
import { JWT_NAME, FILTER_POOL, DEFAULT_SCHEME, DEFAULT_LANGUAGE } from 'client/constants'
import { isBackend } from 'client/utils'
@ -38,7 +39,10 @@ const { actions, reducer } = createSlice({
changeFilter.type,
login.fulfilled.type,
getUser.fulfilled.type,
changeGroup.fulfilled.type
changeGroup.fulfilled.type,
// sunstone views
getSunstoneViews.fulfilled.type,
changeView.type
].includes(type)
},
(state, { payload }) => ({ ...state, ...payload })