Displaying differences for changeset
 
display as  

config.yml

@@ -10,7 +10,7 @@
 # The current version of your application.  This will be advertised
 # through your REST API, and should take the form
 # "<major_version>.<minor_version>.<patch>".
-version: 0.5.6
+version: 0.5.7
 
 # The kind of application.  Currently eRAMS supports two kinds of applications, `system` and `app`.
 # System apps have pre-configured installation and configurations, while all `app` applications are
@@ -55,7 +55,7 @@
     type: hg
   er2_map:
     url: http://alm.engr.colostate.edu/cb/hg/er2_map
-    version: "2.0.8"
+    version: "2.0.10"
     type: hg
 
 

services.py

@@ -410,7 +410,6 @@
     def update_users(self):
         request_json = er2_api.load_json(self._request.body)
         updated_users = request_json["updatedUsers"]
-        logger.info("Inside of Update_Users in services.py, request body: {}".format(updated_users))
 
         try:
             conn = self.get_connection()
@@ -419,7 +418,7 @@
             # For each updated user coming in, we will update their role, state and status
             for updated_user_id in updated_users:
                 updated_user_role = updated_users[updated_user_id]["role"]
-                updated_user_state = updated_users[updated_user_id]["state"]
+                updated_user_states = updated_users[updated_user_id]["states"]
                 updated_user_status = updated_users[updated_user_id]["status"]
 
                 # With updated_user: id, role, state and status, we will update the related info in the participant table
@@ -429,8 +428,6 @@
                     SET
                         fk_d_participant_type_id = 
                             (SELECT id FROM d_participant_type WHERE participant_type = %s),
-                        fk_d_state_id =
-                            (SELECT id FROM d_state WHERE state_abbreviation = %s),
                         fk_d_participant_status =
                             (SELECT id FROM d_participant_status WHERE status = %s)
                     WHERE
@@ -438,11 +435,22 @@
 
                 cursor.execute(update_participant_query, (
                     updated_user_role,
-                    updated_user_state,
                     updated_user_status,
                     updated_user_id
                 ))
 
+                delete_participant_states_query = f"""
+                DELETE FROM participant_state WHERE fk_participant_id = '{updated_user_id}'"""
+
+                cursor.execute(delete_participant_states_query)
+
+
+                for state in updated_user_states:
+                    insert_state_query = f"""INSERT INTO participant_state(fk_participant_id, fk_state_id)
+                                        VALUES (%s, (SELECT id FROM d_state WHERE state_abbreviation = %s))"""
+                    cursor.execute(insert_state_query, (updated_user_id, state))
+                
+
         except Exception as e:
             logger.error(e)
 
@@ -1225,20 +1233,40 @@
                             fname,
                             email,
                             participant_type,
-                            d_state.state_name,
-                            d_state.state_abbreviation,
                             status
                         FROM [participant]
         LEFT JOIN d_participant_type
                                 ON participant.fk_d_participant_type_id = d_participant_type.id
-                            LEFT JOIN d_state
-                                ON participant.fk_d_state_id = d_state.id
                             LEFT JOIN d_participant_status
                                 ON fk_d_participant_status = d_participant_status.id  {}""".format(where_clause)
 
                 cursor.execute(query)
                 users = cursor.fetchall()
 
+                user_state_query = f"""
+                                    SELECT fk_participant_id as user_id, state_abbreviation
+                                    FROM participant_state 
+                                        left join
+                                            participant ON participant_state.fk_participant_id = participant.id
+                                        left join
+                                            d_state ON participant_state.fk_state_id = d_state.id
+                                    WHERE state_abbreviation != ''
+                                    """
+
+                cursor.execute(user_state_query)
+                user_states = cursor.fetchall()
+                logger.info(json.dumps(user_states))
+
+                for u_s_entry in user_states:
+                    user = next((user for user in users if user["id"] == u_s_entry['user_id']), None)
+                    if 'states' in user:
+                        user['states'].append(u_s_entry['state_abbreviation'])
+                    else: 
+                        user['states'] = [u_s_entry['state_abbreviation']]
+
+                    logger.info(user)
+
+
                 return er2_api.respond({'users': users})
         except Exception as e:
             logger.info(e)
@@ -1281,8 +1309,8 @@
                 user = {}
 
                 if len(rows) == 0:
-                    insert_query = f"""INSERT INTO participant (id, lname, fname, email, fk_d_participant_status, fk_d_participant_type_id, fk_d_state_id)
-                                    VALUES('{user_token}', '{user_lName}', '{user_fName}', '{user_email}', 1, 1, 53)"""
+                    insert_query = f"""INSERT INTO participant (id, lname, fname, email, fk_d_participant_status, fk_d_participant_type_id)
+                                    VALUES('{user_token}', '{user_lName}', '{user_fName}', '{user_email}', 1, 1)"""
                     logger.info(insert_query)
                     cursor.execute(insert_query)
                     user = {'id': user_token, 'firstName': user_fName,

static/er2_eofDB/js/actions/documents.tsx

@@ -59,7 +59,7 @@
                     document.removeChild(a)
                     window.URL.revokeObjectURL(blobURL)
                 } else {
-                    console.log('Error occurred fetching documents')
+                    console.error('Error occurred fetching documents')
                 }
             })
     })
@@ -89,7 +89,7 @@
             method: 'POST',
         }).then(response => response.json())
         .then((result) => {
-            console.log(result)
+            console.debug(result)
         })
     const action = { type: actionTypes.UPDATE_DOCUMENT, payload: { eqipNum, doc } } // use doc here, to record categories to state so we don't lose monitoring station association.
     dispatch(action)

static/er2_eofDB/js/actions/manageProjects.tsx

@@ -59,7 +59,7 @@
             })
             .then((result) => {
                 if (fetchError) {
-                    console.log(
+                    console.error(
                         "Something went wrong when getting updated project members from db"
                     )
                 } else {
@@ -75,7 +75,7 @@
                     })
                 }
             })
-            .catch((ret) => console.log(ret.message, ret.stack))
+            .catch((ret) => console.error(ret.message, ret.stack))
     }
 
 export const onSaveProject = (payload) => (dispatch, getState) => {
@@ -124,7 +124,7 @@
             .then((result) => {
                 dispatch({ type: types.SET_FETCHING, payload: false })
                 if (fetchError) {
-                    console.log(
+                    console.error(
                         "Something went wrong when attempting to fetch geometry from NPAD"
                     )
                     dispatch({
@@ -140,7 +140,7 @@
                     // dispatch(updateAppState('manageProjects'))
                 }
             })
-            .catch((ret) => console.log(ret.message, ret.stack))
+            .catch((ret) => console.error(ret.message, ret.stack))
     }
 
 export const getConservationPractices = () => (dispatch, getState) => {
@@ -159,7 +159,7 @@
         })
         .then((result) => {
             if (fetchError) {
-                console.log(
+                console.error(
                     "Something went wrong when attempting to fetch conservation practices"
                 )
             } else {
@@ -174,7 +174,7 @@
                 })
             }
         })
-        .catch((ret) => console.log(ret.message, ret.stack))
+        .catch((ret) => console.error(ret.message, ret.stack))
 }
 
 export const isEQIPNumAlreadyUsed = (eqipNum) => (dispatch, getState) => {
@@ -197,7 +197,7 @@
             })
             .then((result) => {
                 if (fetchError) {
-                    console.log(
+                    console.error(
                         "Something went wrong when attempting determine is the user entered a unique eqip contract number"
                     )
                     dispatch(
@@ -207,7 +207,7 @@
                     dispatch({ type: types.SET_EQIP_NUM_ALREADY_USED, payload: result.used })
                 }
             })
-            .catch((ret) => console.log(ret.message, ret.stack))
+            .catch((ret) => console.error(ret.message, ret.stack))
 }
 
 export const setProjectUndo = (projectEQIPNum) => ({

static/er2_eofDB/js/actions/monitoringStation.tsx

@@ -23,7 +23,6 @@
     station: MonitoringStationType,
     projectEQIPNum: number,
 ) => (dispatch, getState) => {
-    console.log('onCreateMonitoringStation - action')
     dispatch({ type: actionTypes.CREATE_MONITORING_STATION, payload: { station, projectEQIPNum } })
     dispatch(updateAppState('manageProjects'))
 }

static/er2_eofDB/js/actions/users.tsx

@@ -1,5 +1,5 @@
 import * as types from '../constants/action_types'
-import { RoleType, StateType, StatusType } from '../reducers/users'
+import { RoleType, StatusType } from '../reducers/users'
 
 export const setFetchingUsers = fetchingUsers => ({ type: types.SET_FETCHING_USERS, payload: fetchingUsers })
 export const setFetchingUserData = fetchingUserData => ({ type: types.SET_FETCHING_USER_DATA, payload: fetchingUserData })
@@ -35,12 +35,12 @@
         return response.json()
     }).then((result) => {
         if (fetchError) {
-            console.log('Something went wrong when attempting to fetch user role list')
+            console.error('Something went wrong when attempting to fetch user role list')
         } else {
             const userRoles: RoleType[] = result.participant_types.map(pt => ({ id: pt.id, role: pt.participant_type }))
             dispatch({ type: types.SET_USER_ROLES, payload: { userRoles } })
         }
-    }).catch(ret => console.log(ret.message, ret.stack))
+    }).catch(ret => console.error(ret.message, ret.stack))
 }
 
 export const getUsersFromDB = () => (dispatch, getState) => {
@@ -60,7 +60,7 @@
         })
         .then((result) => {
             if (fetchError) {
-                console.log('Something went wrong when attempting to fetch users')
+                console.error('Something went wrong when attempting to fetch users')
             } else {
                 const users = result.users.map(user => {
                     return { 
@@ -69,15 +69,14 @@
                         lastName: user.lname, 
                         email: user.email, 
                         role: user.participant_type, 
-                        state: user.state_abbreviation
+                        states: user.states
                         status: user.status,
                     }
                 })
-                
                 dispatch(setUsers(users))
             }
         })
-        .catch(ret => console.log(ret.message, ret.stack))
+        .catch(ret => console.error(ret.message, ret.stack))
 }
 
 export const getUserDataFromDB = idTokenParsed => (dispatch, getState) => {
@@ -103,19 +102,18 @@
         })
         .then((result) => {
             if (fetchError) {
-                console.log('Something went wrong when attempting to fetch user data')
+                console.error('Something went wrong when attempting to fetch user data')
             } else {
                 const userData = result.user
                 dispatch(setUserData(userData))
                 dispatch(setFetchingUserData(false))
             }
         })
-        .catch(ret => console.log(ret.message, ret.stack))
+        .catch(ret => console.error(ret.message, ret.stack))
 }
 
 
 export const getStatesFromDB = () => (dispatch, getState) => {
-    console.log('getStatesFromDB')
     let fetchError
     fetch(
         `/${getState().meta.name}/api/v1/get_states/?token=${
@@ -129,17 +127,17 @@
         return response.json()
     }).then((result) => {
         if (fetchError) {
-            console.log('Something went wrong when attempting to fetch states list')
+            console.error('Something went wrong when attempting to fetch states list')
         } else {
-            const states: StateType[] = result.states.map(state => ({ id: state.id, name: state.state_name, abbreviation: state.state_abbreviation }))
+            const states: string[] = result.states.map(state => (state.state_abbreviation))
             dispatch({ type: types.SET_STATES, payload: { states } })
         }
-    }).catch(ret => console.log(ret.message, ret.stack))
+    }).catch(ret => console.error(ret.message, ret.stack))
 }
 
 
 export const getStatusFromDB = () => (dispatch, getState) => {
-    console.log('getStatusFromDB')
+    console.debug('getStatusFromDB')
     let fetchError
     fetch(
         `/${getState().meta.name}/api/v1/get_status/?token=${
@@ -153,16 +151,16 @@
         return response.json()
     }).then((result) => {
         if (fetchError) {
-            console.log('Something went wrong when attempting to fetch statuses list')
+            console.error('Something went wrong when attempting to fetch statuses list')
         } else {
             const status: StatusType[] = result.status.map(status => ({ id: status.id, status: status.status }))
             dispatch({ type: types.SET_STATUS, payload: { status } })
         }
-    }).catch(ret => console.log(ret.message, ret.stack))
+    }).catch(ret => console.error(ret.message, ret.stack))
 }
 
 export const saveUsers = updatedUsers => (dispatch, getState) => {
-    console.log('save updated users info in actions ====>', updatedUsers)
+    console.debug('save updated users info in actions ====>', updatedUsers)
 
     let fetchError
     fetch(
@@ -182,11 +180,11 @@
         })
         .then((result) => {
             if (fetchError) {
-                console.log('Something went wrong when updating users in db')
+                console.error('Something went wrong when updating users in db')
             } else {
-                console.log('Successfully updated users info in database')
+                console.debug('Successfully updated users info in database')
             }
         })
-        .catch(ret => console.log(ret.message, ret.stack))
+        .catch(ret => console.error(ret.message, ret.stack))
 }
 

static/er2_eofDB/js/components/ManageProjects.tsx

@@ -254,7 +254,6 @@
   const { keycloak, initialized } = useKeycloak()
   const dispatch = useDispatch()
   const eqipIdAlreadyUsed = useSelector((state) => state.manageProjects.isEQIPIDAlreadyUsed)
-  console.log({eqipIdAlreadyUsed, createProjectDetailsEQIPNum})
 
   const selectedProjects = props.manageProjects.projects.filter(
     (p) => p.selected === true
@@ -263,7 +262,6 @@
   useEffect(() => {
     dispatch({ type: types.SET_EQIP_NUM_ALREADY_USED, payload: null })
     const timeoutHandle = setTimeout(() => {
-      console.log('user stopped typing 2 seconds ago')
       if(createProjectDetailsEQIPNum !== -1){
         dispatch(isEQIPNumAlreadyUsed(createProjectDetailsEQIPNum))
       }
@@ -472,7 +470,7 @@
       try {
         f.value = '' // for IE11, latest Chrome/Firefox/Opera...
       } catch (err) {
-        console.log(err)
+        console.error(err)
       }
 
       if (f.value) {
@@ -950,7 +948,7 @@
             props.setDismissSnackbar(
               'Something went wrong parsing the shapefile'
             )
-            console.log(evt)
+            console.error(evt)
           }
         )
       }
@@ -1009,7 +1007,7 @@
             props.setDismissSnackbar(
               'Something went wrong parsing the shapefile.  Please double check the file and try again.'
             )
-            console.log(evt)
+            console.error(evt)
           }
         )
       }

static/er2_eofDB/js/components/ManageUsers.tsx

@@ -1,7 +1,7 @@
 /* eslint-disable no-use-before-define */
 // @flow
 import React, {useState, useEffect} from "react"
-import { useSelector, connect } from 'react-redux'
+import { useSelector, connect, useDispatch } from 'react-redux'
 import {
     FormControl,
     MenuItem,
@@ -20,10 +20,14 @@
 } from '../actions'
 import Autocomplete from '@material-ui/lab/Autocomplete/Autocomplete'
 import { makeStyles } from "@material-ui/core/styles"
+import WindowState, { windowStates } from '@owsi/catena/er2_map_userlayers/js/components/window_state'
+import { setTabbedPanelWindowState } from '@owsi/catena/er2_map_userlayers/js/actions/tabbed_panel'
 import { primaryDarkColor, contrastTextColor, gray } from "../styles/colors.js"
+import { RootStateType } from '../types'
 
 interface Props {
-    saveUsers: Function
+    saveUsers: Function,
+    height: number
 }
 
 const useTableStyles = makeStyles({
@@ -38,13 +42,6 @@
         fontSize: "18px",
         backgroundColor: primaryDarkColor,
         color: contrastTextColor,
-        // "&.MuiTableSortLabel-root": {
-        //     padding: "0px 0px 0px 15px",
-        //     color: contrastTextColor,
-        //     "& .MuiTableSortLabel-icon": {
-        //         color: contrastTextColor,
-        //     },
-        // },
     },
     tableRow: {
         "&:hover": {
@@ -67,17 +64,20 @@
     const spinnerClasses = useSpinnerStyles()
 
     const [usersUpdated, setUsersUpdated] = React.useState({})
-    const users = useSelector(state => state.users.users)
-    const states = useSelector(state => state.users.states)
-    const statuses = useSelector(state => state.users.status)
-    const roles = useSelector(state => state.users.userRoles)
+    const users = useSelector((state: RootStateType) => state.users.users)
+    const states = useSelector((state: RootStateType) => state.users.states)
+    const statuses = useSelector((state: RootStateType) => state.users.status)
+    const roles = useSelector((state: RootStateType) => state.users.userRoles)
+    const tabbedPanel = useSelector((state: RootStateType) => state.tabbedPanel)
 
     const [sortBy, setSortBy] = React.useState("firstName")
-    const [sortOrder, setSortOrder] = React.useState("asc")
+    const [sortOrder, setSortOrder] = React.useState<'asc' | 'desc'>("asc")
     const [usersSorted, setUsersSorted] = React.useState([])
     const [usersFiltered, setUsersFiltered] = React.useState([])
     const [usersFilterText, setUsersFilterText] = React.useState("")
 
+    const dispatch = useDispatch()
+
     // Map through users info to create component-level state that is in the form: id: {firstName: '', lastName: '', role: '', state: '', status: ''}
     React.useEffect(() => {
         // If users info is stored as array of objects (necessary in order to sort table):
@@ -95,6 +95,12 @@
     }, [users, sortBy, sortOrder])
 
     React.useEffect(() => {
+        if(tabbedPanel.windowState !== windowStates.maximized){
+            dispatch(setTabbedPanelWindowState(windowStates.maximized))
+        }
+    }, [])
+
+    React.useEffect(() => {
         // if the project filter text is empty, we just want to display all, sorted users; otherwise, filter users based on text entry (for firstName, lastName or role)
         if (usersFilterText !== "") {
             const filteredUsers = usersSorted.filter(
@@ -131,11 +137,11 @@
     }, [usersUpdated])
 
     const headers = [
-        { text: "First Name", sortable: true, key: "firstName" },
-        { text: "Last Name", sortable: true, key: "lastName" },
-        { text: "Role", sortable: true, key: "role" },
-        { text: "State", sortable: true, key: "state" },
-        { text: "Status", sortable: true, key: "status" },
+        { text: "First Name", sortable: true, key: "firstName", width: '15%' },
+        { text: "Last Name", sortable: true, key: "lastName", width: '15%' },
+        { text: "Role", sortable: true, key: "role", width: '15%' },
+        { text: "State(s)", sortable: true, key: "state", width: '40%' },
+        { text: "Status", sortable: true, key: "status", width: '15%' },
     ]
 
     const handleChange = (event, userID, dropdownType) => {
@@ -146,7 +152,16 @@
         setUsersSorted(copyOfSortedUsers)
         setUsersFiltered(copyOfSortedUsers)
         setUsersUpdated({...usersUpdated, [userID]: copyOfSortedUsers[usersInfoIndex]})
-    };
+    }
+
+    const handleStateChange = (userID, newStates) => {
+        let usersInfoIndex = usersSorted.findIndex(user => user.id === userID)
+        let copyOfSortedUsers = usersSorted.slice()
+        copyOfSortedUsers[usersInfoIndex]['states'] = newStates
+        setUsersSorted(copyOfSortedUsers)
+        setUsersFiltered(copyOfSortedUsers)
+        setUsersUpdated({...usersUpdated, [userID]: copyOfSortedUsers[usersInfoIndex]})
+    }
 
     const onChangeFilterUsers = (evt) => {
         setUsersFilterText(evt.target.value)
@@ -229,12 +244,8 @@
 
     const displayTable = () => {
         let usersDisplayed = usersFilterText === "" ? usersSorted : usersFiltered
-
         return (
-            <div>
-                <h2>
-                    Click on the respective cell to update a user's: Role, State or Status.
-                </h2>
+            <div style={{height: props.height}}>
                 <div key="toolBar" className={'filterUsers'}>
                     <TextField
                         label="Filter Users"
@@ -249,12 +260,13 @@
                         size="small"
                     />
                 </div>
-                <TableContainer style={{ maxHeight: 800 }}>
+                <TableContainer>
                     <Table id="ManageUsers" stickyHeader>
                         <TableHead>
                             <TableRow>
                                 {headers.map((header) => (
                                     <TableCell
+                                        style={{width: header.width}}
                                         key={"header-" + header.text}
                                         className={tableClasses.headerCell}
                                         onClick={() =>
@@ -266,15 +278,6 @@
                                                 padding: "0px 0px 0px 15px",
                                                 color: contrastTextColor,
                                             }}
-                                            // Below styling works in this sandbox: https://codesandbox.io/s/enhancedtable-material-demo-forked-3go1p?file=/demo.js  to make the active arrow a specific color... however, doesn't work here... IDK
-                                            // sx={{
-                                            //     "&.MuiTableSortLabel-root": {
-                                            //         color: contrastTextColor,
-                                            //         "& .MuiTableSortLabel-icon": {
-                                            //             color: contrastTextColor,
-                                            //         },
-                                            //     },
-                                            // }}
                                             active={sortBy === header.key}
                                             direction={sortOrder}
                                             onClick={() =>
@@ -322,13 +325,13 @@
 
                                         {/* State */}
                                         <TableCell className={tableClasses.bodyCell}> 
-                                            <FormControl style={{ minWidth: '100px' }} >
+                                            <FormControl style={{ width: '100%' }} >
                                                 <Autocomplete
-                                                    value={user.state}
+                                                    multiple
+                                                    value={user.states}
                                                     id="state-name-select"
                                                     options={states}
-                                                    onChange={(e, newValue) => handleChange(newValue.abbreviation, user.id, 'state')}
-                                                    getOptionSelected={(o, value) => o.abbreviation === value}
+                                                    onChange={(e, newStates) => handleStateChange(user.id, newStates)}
                                                     ChipProps={{
                                                         size: 'small',
                                                     }}
@@ -340,7 +343,9 @@
                                                         }
                                                     }}
                                                     renderInput={(params) =>  
-                                                        <TextField {...params}/>
+                                                        <TextField 
+                                                            {...params}
+                                                        />
                                                     }
                                                 />
                                             </FormControl>
@@ -374,15 +379,10 @@
 
     const displayLoading = () => {
         return (
-            <div>
-                <h2>
-                    To update a user's: role, status or state click on their respective cell and select from the dropdown.
-                </h2>
                 <div className={spinnerClasses.center}>
                     <i className="fa fa-cog fa-spin fa-3x fa-fw" />
                     <span className="sr-only">Loading...</span>
                 </div>
-            </div>
         )
     }
 

static/er2_eofDB/js/constants/routes.js

@@ -4,21 +4,7 @@
 export const INSTRUCTIONS_TOOL_FUNCTIONALITY = '/docs/functionality'
 export const INSTRUCTIONS_TOOL_VISION = '/docs/tool-vision'
 export const INSTRUCTIONS_TOOL_COMPONENTS = '/docs/tool-components'
-export const CROP = '/crop/'
-export const REGION = '/region/'
-export const RUN = '/run/'
-export const SELECT_AREA = '/select-area/'
-export const SLOPE = '/slope/'
-export const WATERSHEDS = '/watersheds/'
-export const SIMULATION = '/simulation/'
 
-export const MANAGE_FARMS = '/ManageFarms/' // Deprecated
 export const MANAGE_PROJECTS = '/ManageProjects/'
-export const MANAGE_FIELDS = '/ManageFields/'
-export const MANAGE_PRACTICES = '/ManagePractices/'
-export const MANAGE_STATIONS = '/ManageStations/'
-export const SOIL = '/Soil/'
-export const CLIMATE = '/Climate/'
 export const SETTINGS = '/Settings/'
-export const WATERSHED_DELINEATION = '/WatershedDelineation/'
 export const USERS = '/Users/'

static/er2_eofDB/js/containers/app.tsx

@@ -55,6 +55,7 @@
     faFilePdf, faFilter, faBars, faTrash, faEdit, faCog, faCogs, faDownload, faUsers,
 } from '@fortawesome/free-solid-svg-icons'
 import { setFetchingUserData } from '../actions'
+import ManageUsersCB from '../components/ManageUsersCB'
 
 library.add(faFilePdf, faFilter, faBars, faTrash, faEdit, faCog, faCogs, faDownload, faUsers)
 
@@ -210,6 +211,9 @@
         indicator: {
             backgroundColor: '#CAFE48',
         },
+        root: {
+            paddingLeft: 60,
+        },
     },
     MuiTab: {
         root: {
@@ -248,14 +252,21 @@
     const activeMapToolbarPanel = theprops.mapToolbar.items.filter(
         item => item.active,
     )
-    const isMapToolbarVisible = activeMapToolbarPanel.length > 0
+    
     const mapVisible = [
         routes.MANAGE_PROJECTS,
         routes.SETTINGS,
     ].some(route => parsedLoc.path.startsWith(route))
+    const usersVisible = location.pathname === routes.USERS
+    let isMapToolbarVisible = activeMapToolbarPanel.length > 0
+    if(usersVisible){
+        isMapToolbarVisible = undefined
+    }
 
-    const tocVisible = location.pathname === routes.MANAGE_PROJECTS
-        || location.pathname === routes.SETTINGS
+    const tocVisible = location.pathname === routes.MANAGE_PROJECTS ||
+        location.pathname === routes.USERS || 
+        location.pathname === routes.SETTINGS
+
 
     const dispatch = useDispatch()
     const { token, actions } = theprops
@@ -329,6 +340,19 @@
     }, [theprops.serverState])
 
     useEffect(() => {
+        if(location.pathname === routes.USERS){
+            if(theprops.tabbedPanel.windowState !== windowStates.maximized){
+                theprops.actions.setTabbedPanelWindowState(windowStates.maximized)
+            }
+        }
+        if(location.pathname === routes.MANAGE_PROJECTS){
+            if(theprops.tabbedPanel.windowState !== windowStates.opened){
+                theprops.actions.setTabbedPanelWindowState(windowStates.opened)
+            }
+        }
+    }, [location.pathname])
+
+    useEffect(() => {
         theprops.actions.getUsersFromDB()
         theprops.actions.setDefaultBaseLayer('USGS Imagery Topo')
     }, [])
@@ -553,20 +577,7 @@
             </div>
         )
     }
-    /* Don't do this for now since the token won't be available when the user isn't logged in.
-    if (!theprops.token.value) {
-    // Render loading page until the server state is available
-        return (
-            <div className={classes.root}>
-                {renderHeader()}
-                <div className={classes.loading}>
-                    <i className="fa fa-cog fa-spin fa-3x fa-fw" />
-                    <span className="sr-only">Loading...</span>
-                </div>
-            </div>
-        )
-    }
-*/
+    
     const renderCatenaMap = () => (
         <CatenaMap
             analysisPanelClosed={theprops.tabbedPanel.windowState === windowStates.minimized}
@@ -623,6 +634,7 @@
     )
 
     const renderTabbedPanel = () => {
+        console.log({isMapToolbarVisible})
         const selectedProjects = theprops.manageProjects.projects.filter(p => p.selected === true)
         return (
             <React.Fragment>
@@ -634,7 +646,7 @@
                     type="south"
                     windowState={theprops.tabbedPanel.windowState}
                 />
-                {theprops.tabbedPanel.windowState !== windowStates.minimized && (
+                {theprops.tabbedPanel.windowState !== windowStates.minimized && parsedLoc.path === routes.MANAGE_PROJECTS && (
                     <TabbedPanel
                         heightOffset={theprops.theme.analysisPanelOffset}
                         maptoolbarVisible={isMapToolbarVisible}
@@ -648,11 +660,24 @@
                         <MonitoringStationSP
                             key="Monitoring Stations"
                             classes={theprops.classes}
-                            project={selectedProjects[0]}
-                        />
+                            project={selectedProjects[0]} />
                         <DocumentsSP key="Documents" project={selectedProjects[0]} />
                     </TabbedPanel>
                 )}
+                {theprops.tabbedPanel.windowState !== windowStates.minimized && parsedLoc.path === routes.USERS && (
+                    <TabbedPanel
+                        heightOffset={theprops.theme.analysisPanelOffset}
+                        maptoolbarVisible={isMapToolbarVisible}
+                        onResize={theprops.actions.onResizeAnalysisPanel}
+                        tocVisible={tocVisible}
+                        tabbedPanel={theprops.tabbedPanel}
+                        theme={theprops.classes}
+                        onSetTabbedPanelKey={theprops.actions.onSetTabbedPanelKey}
+                    >
+                        <ManageUsers key="Users"/>
+                        
+                    </TabbedPanel>
+                )}
             </React.Fragment>
         )
     }
@@ -673,11 +698,8 @@
     const renderManageUsersCB = () => (
         <Route
             path={routes.USERS}
-            render={() => (
-                <ManageUsers
-                    // serverState={theprops.serverState}
-                    // theme={theprops.classes}
-                />
+            render={() =>  (
+                <ManageUsersCB theme={theprops.classes} />
             )}
         />
     )
@@ -705,12 +727,12 @@
 
     const renderContextBarItems = () => {
         const isManageProjectsVisible = location.pathname === routes.MANAGE_PROJECTS && catenaMap.current
-
         const isManageUsersVisible = location.pathname === routes.USERS
 
         if (isManageProjectsVisible) {
             return renderManageProjectsCB()
-        } else if (isManageUsersVisible) {
+        } 
+        if(isManageUsersVisible) {
             return renderManageUsersCB()
         }
 
@@ -722,22 +744,6 @@
             <Redirect to={routes.INSTRUCTIONS} />)
     }
 
-    /* Don't do this for now since the token will be undefined if the user isn't logged in.
-    if (!theprops.token.value) {
-    // Render loading page until the server state is available
-        return (
-            <div className={theprops.classes.root}>
-                {renderHeader()}
-                {renderContextBar()}
-                <div className={theprops.classes.loading}>
-                    <i className="fa fa-cog fa-spin fa-3x fa-fw" />
-                    <span className="sr-only">Loading...</span>
-                </div>
-            </div>
-        )
-    }
-    */
-
     const theMuiTheme = customMuiTheme({ colors, overrides })
 
     return (
@@ -745,18 +751,17 @@
             <div className={classes.root}>
                 {renderHeader()}
                 {renderContextBar()}
+                {/* Rendering the Settings */}
+                {renderSettings()}
                 {renderBreadcrumbs(theprops.classes)}
                 {renderInstructions()}
                 {/* Rendering the Maps and the tabbed panels */}
                 {mapVisible && renderCatenaMap()}
                 {mapVisible && catenaMap.current && renderUserContainerLayer()}
-                {mapVisible && renderTabbedPanel()}
-
                 {/* Rendering the Context Bar Items */}
                 {renderContextBarItems()}
+                {(mapVisible || usersVisible) && renderTabbedPanel()}
 
-                {/* Rendering the Settings */}
-                {renderSettings()}
             </div>
         </MuiThemeProvider>
     )

static/er2_eofDB/js/index.tsx

@@ -13,11 +13,11 @@
 const store = createStore(reducer, applyMiddleware(thunkMiddleware))
 
 const eventLogger = (event: unknown, error: unknown) => {
-    // console.log("onKeycloakEvent", event, error)
+    console.debug("onKeycloakEvent", event, error)
 }
 
 const tokenLogger = (tokens: unknown) => {
-    // console.log("onKeycloakTokens", tokens)
+    console.debug("onKeycloakTokens", tokens)
 }
 
 render(
@@ -25,11 +25,11 @@
         authClient={keycloak}
         onEvent={eventLogger}
         onTokens={tokenLogger}>
-    <Provider store={store}>
-        <BrowserRouter>
-            <App />
-        </BrowserRouter>
-    </Provider>
+        <Provider store={store}>
+            <BrowserRouter>
+                <App />
+            </BrowserRouter>
+        </Provider>
     </ReactKeycloakProvider>,
     document.getElementById("root"),
 )

static/er2_eofDB/js/reducers/manageProjects.tsx

@@ -326,7 +326,7 @@
       stationID,
     )
     if (changedProjectIndex === -1) {
-      console.log('No monitoring station found with the ID provided')
+      console.error('No monitoring station found with the ID provided')
     }
     const changedProject = { ...state.projects[changedProjectIndex] }
 

static/er2_eofDB/js/reducers/users.ts

@@ -7,12 +7,6 @@
     role: string,
 }
 
-export type StateType = {
-    id: number,
-    name: string,
-    abbreviation: string,
-}
-
 export type StatusType = {
     id: number,
     status: string,
@@ -42,6 +36,7 @@
     userRoles: [],
     fetchingUserData: false,
     fetchingUsers: false,
+    fetchingRoles: false,
     states: {},
     status: {}
 }

static/package.json

@@ -1,6 +1,6 @@
 {
   "name": "er2_eofdb",
-  "version": "0.5.6",
+  "version": "0.5.7",
   "target": "web",
   "module": "index.js",
   "license": "MIT",