Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Organization dropdown bug fix #80

Merged
merged 4 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions webapp/src/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
// Actions
getRsuData,
} from './generalSlices/rsuSlice'
import { selectAuthLoginData, selectLoadingGlobal } from './generalSlices/userSlice'
import { selectAuthLoginData, selectLoadingGlobal, selectOrganizationName } from './generalSlices/userSlice'
import { SecureStorageManager } from './managers'
import { ReactKeycloakProvider } from '@react-keycloak/web'
import keycloak from './keycloak-config'
Expand All @@ -31,6 +31,7 @@ const Dashboard = () => {
const dispatch: ThunkDispatch<RootState, void, AnyAction> = useDispatch()
const authLoginData = useSelector(selectAuthLoginData)
const loadingGlobal = useSelector(selectLoadingGlobal)
const organizationName = useSelector(selectOrganizationName)

useEffect(() => {
keycloak
Expand All @@ -53,7 +54,7 @@ const Dashboard = () => {
dispatch(getRsuData())
}, [authLoginData, dispatch])

console.log('Auth Role', SecureStorageManager.getUserRole())
useEffect(() => {}, [organizationName])

return (
<ReactKeycloakProvider
Expand Down
25 changes: 23 additions & 2 deletions webapp/src/features/adminOrganizationTab/AdminOrganizationTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
getOrgData,
updateTitle,
setSelectedOrg,
AdminOrgSummary,
} from './adminOrganizationTabSlice'
import { useSelector, useDispatch } from 'react-redux'

Expand All @@ -31,6 +32,7 @@ import { RootState } from '../../store'
import { AnyAction, ThunkDispatch } from '@reduxjs/toolkit'
import { Route, Routes, useLocation, useNavigate } from 'react-router-dom'
import { NotFound } from '../../pages/404'
import { changeOrganization, selectOrganizationName, setOrganizationList } from '../../generalSlices/userSlice'

const getTitle = (activeTab: string) => {
if (activeTab === undefined) {
Expand Down Expand Up @@ -59,8 +61,21 @@ const AdminOrganizationTab = () => {
const errorState = useSelector(selectErrorState)
const errorMsg = useSelector(selectErrorMsg)

const defaultOrgName = useSelector(selectOrganizationName)
var defaultOrgData = orgData.find((org) => org.name === defaultOrgName)

useEffect(() => {
dispatch(getOrgData({ orgName: 'all', all: true, specifiedOrg: undefined }))
dispatch(getOrgData({ orgName: 'all', all: true, specifiedOrg: undefined })).then(() => {
// on first render set the default organization in the admin
// organization tab to the currently selected organization
if (defaultOrgData) {
const selectedOrg = (orgData ?? []).find(
(organization: AdminOrgSummary) => organization?.name === defaultOrgName
)
dispatch(setSelectedOrg(selectedOrg))
defaultOrgData = null
dmccoystephenson marked this conversation as resolved.
Show resolved Hide resolved
}
})
}, [dispatch])

const updateTableData = (orgName: string) => {
Expand All @@ -79,6 +94,12 @@ const AdminOrganizationTab = () => {
updateTableData(selectedOrgName)
}

const handleOrgDelete = (orgName) => {
dispatch(deleteOrg(orgName))
dispatch(setOrganizationList({ value: { name: orgName }, type: 'delete' }))
dispatch(changeOrganization(orgData[0].name))
}

return (
<div>
<div>
Expand Down Expand Up @@ -148,7 +169,7 @@ const AdminOrganizationTab = () => {
</Grid>
<Grid item xs={0}>
<AdminOrganizationDeleteMenu
deleteOrganization={() => dispatch(deleteOrg(selectedOrgName))}
deleteOrganization={() => handleOrgDelete(selectedOrgName)}
selectedOrganization={selectedOrgName}
/>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ import {
setSelectedUserRole,
setSelectedUserList,
} from './adminOrganizationTabUserSlice'
import { selectLoadingGlobal } from '../../generalSlices/userSlice'
import {
selectAuthLoginData,
selectEmail,
selectLoadingGlobal,
setOrganizationList,
} from '../../generalSlices/userSlice'
import { useSelector, useDispatch } from 'react-redux'

import '../adminRsuTab/Admin.css'
Expand All @@ -47,6 +52,8 @@ const AdminOrganizationTabUser = (props: AdminOrganizationTabUserProps) => {
const selectedUserList = useSelector(selectSelectedUserList)
const availableRoles = useSelector(selectAvailableRoles)
const loadingGlobal = useSelector(selectLoadingGlobal)
const authLoginData = useSelector(selectAuthLoginData)
const userEmail = useSelector(selectEmail)
const [userColumns] = useState<Column<any>[]>([
{
title: 'First Name',
Expand Down Expand Up @@ -155,6 +162,9 @@ const AdminOrganizationTabUser = (props: AdminOrganizationTabUserProps) => {
updateTableData: props.updateTableData,
})
)
if (row.email === authLoginData?.data?.email) {
dispatch(setOrganizationList({ value: { name: props.selectedOrg, role: row.role }, type: 'delete' }))
}
}

const userMultiDelete = async (rows: AdminOrgUser[]) => {
Expand All @@ -165,6 +175,11 @@ const AdminOrganizationTabUser = (props: AdminOrganizationTabUserProps) => {
updateTableData: props.updateTableData,
})
)
for (let i = 0; i < rows.length; i++) {
if (rows[i].email === authLoginData?.data?.email) {
dispatch(setOrganizationList({ value: { name: props.selectedOrg, role: rows[i].role }, type: 'delete' }))
}
}
}

const userMultiAdd = async (userList: AdminOrgUser[]) => {
Expand All @@ -175,6 +190,11 @@ const AdminOrganizationTabUser = (props: AdminOrganizationTabUserProps) => {
updateTableData: props.updateTableData,
})
)
for (let i = 0; i < userList.length; i++) {
if (userList[i].email === authLoginData?.data?.email) {
dispatch(setOrganizationList({ value: { name: props.selectedOrg, role: userList[i].role }, type: 'add' }))
}
}
}

const userBulkEdit = async (
Expand All @@ -189,6 +209,7 @@ const AdminOrganizationTabUser = (props: AdminOrganizationTabUserProps) => {
dispatch(
userBulkEditAction({
json,
selectedUser: userEmail,
selectedOrg: props.selectedOrg,
updateTableData: props.updateTableData,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ export type AdminOrgUserDeleteMultiple = {
export type AdminOrgTabUserBulkEdit = {
json: { [key: string]: { newData: AdminOrgTabUser } }
selectedOrg: string
selectedUser: string
updateTableData: (org: string) => void
}
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,11 @@ describe('async thunks', () => {
obj2: { newData: { email: 'test2@gmail.com', role: 'role2' } },
}
const selectedOrg = 'selectedOrg'
const selectedUser = 'selectedUser'
const fetchPatchOrganization = jest.fn()
const updateTableData = jest.fn()

const action = userBulkEdit({ json, selectedOrg, updateTableData })
const action = userBulkEdit({ json, selectedOrg, selectedUser, updateTableData })

await action(dispatch, getState, undefined)
expect(dispatch).toHaveBeenCalledTimes(2 + 2)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { selectToken } from '../../generalSlices/userSlice'
import { selectToken, setOrganizationList } from '../../generalSlices/userSlice'
import EnvironmentVars from '../../EnvironmentVars'
import apiHelper from '../../apis/api-helper'
import { RootState } from '../../store'
Expand Down Expand Up @@ -174,19 +174,26 @@ export const userAddMultiple = createAsyncThunk(
export const userBulkEdit = createAsyncThunk(
'adminOrganizationTabUser/userBulkEdit',
async (payload: AdminOrgTabUserBulkEdit, { dispatch }) => {
const { json, selectedOrg, updateTableData } = payload
const { json, selectedOrg, selectedUser, updateTableData } = payload

const patchJson: adminOrgPatch = {
name: selectedOrg,
users_to_modify: [],
}
const rows = Object.values(json)
var orgUpdateVal = {}
for (var row of rows) {
if (row.newData.email === selectedUser) {
orgUpdateVal = { name: selectedOrg, role: row.newData.role }
}
const userRole = { email: row.newData.email, role: row.newData.role }
patchJson.users_to_modify.push(userRole)
}
await dispatch(editOrg(patchJson))
dispatch(refresh({ selectedOrg, updateTableData }))
if (Object.keys(orgUpdateVal).length > 0) {
dispatch(setOrganizationList({ value: orgUpdateVal, orgName: selectedOrg, type: 'update' }))
}
},
{ condition: (_, { getState }) => selectToken(getState() as RootState) != undefined }
)
Expand Down
41 changes: 37 additions & 4 deletions webapp/src/generalSlices/userSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,34 @@ export const userSlice = createSlice({
SecureStorageManager.removeUserRole()
},
changeOrganization: (state, action) => {
state.value.organization =
var organization =
UserManager.getOrganization(state.value.authLoginData, action.payload) ?? state.value.organization
state.value.organization = organization
SecureStorageManager.setUserRole({ name: organization.name, role: organization.role })
},
setOrganizationList: (state, action) => {
if (action.payload.type === 'add') {
state.value.authLoginData.data.organizations = [
...state.value.authLoginData.data.organizations,
action.payload.value,
]
} else if (action.payload.type === 'delete') {
var index = state.value.authLoginData.data.organizations.findIndex(
(org) => org.name === action.payload.value.name
)
if (index > -1) {
var updatedOrgList = state.value.authLoginData.data.organizations
updatedOrgList.splice(index, 1)
state.value.authLoginData.data.organizations = [...updatedOrgList]
}
} else if (action.payload.type === 'update') {
var index = state.value.authLoginData.data.organizations.findIndex((org) => org.name === action.payload.orgName)
if (index > -1) {
var updatedOrgList = state.value.authLoginData.data.organizations
updatedOrgList[index] = action.payload.value
state.value.authLoginData.data.organizations = [...updatedOrgList]
}
}
},
setLoading: (state, action) => {
state.loading = action.payload
Expand Down Expand Up @@ -102,7 +128,7 @@ export const userSlice = createSlice({
state.value.authLoginData = action.payload
state.value.organization = action.payload?.data?.organizations?.[0]
LocalStorageManager.setAuthData(action.payload)
SecureStorageManager.setUserRole(action.payload)
SecureStorageManager.setUserRole(action.payload['data']['organizations'][0])
})
.addCase(keycloakLogin.rejected, (state, action: PayloadAction<unknown>) => {
console.debug('keycloakLogin.rejected')
Expand All @@ -115,8 +141,15 @@ export const userSlice = createSlice({
},
})

export const { logout, changeOrganization, setLoading, setLoginFailure, setKcFailure, setRouteNotFound } =
userSlice.actions
export const {
logout,
changeOrganization,
setOrganizationList,
setLoading,
setLoginFailure,
setKcFailure,
setRouteNotFound,
} = userSlice.actions

export const selectAuthLoginData = (state: RootState) => state.user.value.authLoginData
export const selectToken = (state: RootState) => state.user.value.authLoginData.token
Expand Down
7 changes: 2 additions & 5 deletions webapp/src/managers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,8 @@ const SecureStorageManager = {
return authData['role']
}
},
setUserRole: (authData) => {
return secureLocalStorage.setItem(
AUTH_DATA_SECURE_STORAGE_KEY,
JSON.stringify(authData['data']['organizations'][0])
)
setUserRole: (organization) => {
return secureLocalStorage.setItem(AUTH_DATA_SECURE_STORAGE_KEY, JSON.stringify(organization))
},
removeUserRole: () => {
return secureLocalStorage.removeItem(AUTH_DATA_SECURE_STORAGE_KEY)
Expand Down
2 changes: 2 additions & 0 deletions webapp/src/pages/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {

// actions
selectRsu,
getRsuData,
toggleMapDisplay,
getIssScmsStatus,
getMapData,
Expand Down Expand Up @@ -212,6 +213,7 @@ function MapPage(props: MapPageProps) {

// useEffects for RSU layer
useEffect(() => {
dispatch(getRsuData())
dispatch(selectRsu(null))
dispatch(clearFirmware())
}, [organization, dispatch])
Expand Down
Loading