mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
implemented users and mappings management for usergroups
Signed-off-by: Andrii Podriez <andrey5577990@gmail.com>
This commit is contained in:
parent
54130a56de
commit
9ad6467c80
10 changed files with 453 additions and 45 deletions
|
@ -27,6 +27,7 @@ import {Button} from "react-bootstrap";
|
|||
import NotificationsFactory from "../../../common/data-managers/notifications-factory";
|
||||
import notificationsDataManager from "../../../common/data-managers/notifications-data-manager";
|
||||
import FileSaver from "file-saver";
|
||||
import moment from "moment";
|
||||
import {
|
||||
useGetResultsQuery,
|
||||
useAddResultMutation,
|
||||
|
@ -142,6 +143,11 @@ const ResultsTable = (props) => {
|
|||
setIsDeleteModalOpened(false);
|
||||
setResultToDelete({});
|
||||
}
|
||||
|
||||
const stateUpdateModifier = (dateString) => {
|
||||
const date = moment(dateString);
|
||||
return `${date.fromNow()}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -175,11 +181,13 @@ const ResultsTable = (props) => {
|
|||
<DataColumn
|
||||
title='Created at'
|
||||
dataKey='createdAt'
|
||||
modifier={(createdAt) => stateUpdateModifier(createdAt)}
|
||||
width={200}
|
||||
/>
|
||||
<DataColumn
|
||||
title='Last update'
|
||||
dataKey='updatedAt'
|
||||
modifier={(updatedAt) => stateUpdateModifier(updatedAt)}
|
||||
width={200}
|
||||
/>
|
||||
<LinkbuttonColumn
|
||||
|
|
97
src/pages/usergroups/dialogs/addScenarioMappingDialog.js
Normal file
97
src/pages/usergroups/dialogs/addScenarioMappingDialog.js
Normal file
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* This file is part of VILLASweb.
|
||||
*
|
||||
* VILLASweb is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* VILLASweb is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import { useState } from 'react';
|
||||
import { Form, Col, Button} from 'react-bootstrap';
|
||||
import Dialog from '../../../common/dialogs/dialog';
|
||||
import { useGetScenariosQuery } from '../../../store/apiSlice';
|
||||
|
||||
const AddScenarioMappingDialog = ({isDialogOpened, onClose, mappings}) => {
|
||||
|
||||
const [name, setName] = useState('');
|
||||
const [isValid, setIsValid] = useState(false);
|
||||
const [selectedOption, setSelectedOption] = useState('addUsersToScenario');
|
||||
const [selectedScenarioID, setSelectedScenarioID] = useState('');
|
||||
|
||||
const {data: {scenarios} = {}, isLoading: isLoadingScenarios} = useGetScenariosQuery();
|
||||
|
||||
const handleRadioChange = (e) => {
|
||||
setSelectedOption(e.target.value);
|
||||
}
|
||||
|
||||
const handleClose = (canceled) => {
|
||||
if(canceled) {
|
||||
onClose(null);
|
||||
} else {
|
||||
onClose({scenarioID: Number(selectedScenarioID), duplicate: selectedOption === 'duplicateScenarioForUsers'});
|
||||
}
|
||||
}
|
||||
|
||||
const handleSelectChange = (e) => {
|
||||
setSelectedScenarioID(e.target.value);
|
||||
setIsValid(e.target.value !== '');
|
||||
};
|
||||
|
||||
return (<Dialog
|
||||
show={isDialogOpened}
|
||||
title="New User Group"
|
||||
buttonTitle="Add"
|
||||
onClose={handleClose}
|
||||
onReset={() => {}}
|
||||
valid={isValid}>
|
||||
<Form>
|
||||
<Form.Group as={Col} controlId="radioGroup" style={{ marginBottom: '15px' }}>
|
||||
<div>
|
||||
<Form.Check
|
||||
type="radio"
|
||||
id="addUsersToScenario"
|
||||
name="options"
|
||||
label="Add users to scenario"
|
||||
value="addUsersToScenario"
|
||||
checked={selectedOption === 'addUsersToScenario'}
|
||||
onChange={handleRadioChange}
|
||||
/>
|
||||
<Form.Check
|
||||
type="radio"
|
||||
id="duplicateScenarioForUsers"
|
||||
name="options"
|
||||
label="Duplicate scenario for each user"
|
||||
value="duplicateScenarioForUsers"
|
||||
checked={selectedOption === 'duplicateScenarioForUsers'}
|
||||
onChange={handleRadioChange}
|
||||
/>
|
||||
</div>
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group controlId="scenario">
|
||||
<Form.Label>Select Option</Form.Label>
|
||||
{isLoadingScenarios ? <div>Loading...</div> : (
|
||||
<Form.Control as="select" value={selectedScenarioID} onChange={handleSelectChange}>
|
||||
<option value="">-- Select scenario --</option>
|
||||
{scenarios.map(scenario => {
|
||||
//check if existing mappings are already added to the usergroup
|
||||
if(!mappings.some(mapping => mapping.scenarioID === scenario.id)) return <option key={scenario.id} value={scenario.id}>{scenario.name}</option>;
|
||||
})}
|
||||
</Form.Control>
|
||||
)}
|
||||
</Form.Group>
|
||||
</Form>
|
||||
</Dialog>);
|
||||
}
|
||||
|
||||
export default AddScenarioMappingDialog;
|
81
src/pages/usergroups/dialogs/addUserToUsergroupDialog.js
Normal file
81
src/pages/usergroups/dialogs/addUserToUsergroupDialog.js
Normal file
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* This file is part of VILLASweb.
|
||||
*
|
||||
* VILLASweb is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* VILLASweb is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Form, Col, Dropdown, Badge } from 'react-bootstrap';
|
||||
import Dialog from '../../../common/dialogs/dialog';
|
||||
import { useGetUsersQuery } from '../../../store/apiSlice';
|
||||
|
||||
const AddUserToUsergroupDialog = ({isModalOpened, onClose, currentUsers}) => {
|
||||
|
||||
const [selectedUsers, setSelectedusers] = useState([]);
|
||||
const [isValid, setIsValid] = useState(false);
|
||||
|
||||
const {data: {users} = {}, isLoading: isLoadingUsers} = useGetUsersQuery();
|
||||
|
||||
const toggleUser = (event, option) => {
|
||||
event.preventDefault();
|
||||
if (selectedUsers.includes(option)) {
|
||||
setSelectedusers(prevState => ([...prevState.filter((item) => item !== option)]));
|
||||
} else {
|
||||
setSelectedusers(prevState => ([...prevState, option]));
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setIsValid(selectedUsers.length > 0);
|
||||
}, [selectedUsers]);
|
||||
|
||||
const handleClose = (canceled) => {
|
||||
if(!canceled){
|
||||
onClose(selectedUsers);
|
||||
} else {
|
||||
onClose([]);
|
||||
}
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
setSelectedusers([]);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog show={isModalOpened} title="Add Users" buttonTitle="Add" onClose={handleClose} onReset={handleReset} valid={isValid}>
|
||||
<Dropdown autoClose="outside">
|
||||
<Dropdown.Toggle variant="success" id="dropdown-basic">Select Options</Dropdown.Toggle>
|
||||
<Dropdown.Menu>
|
||||
{isLoadingUsers ? <div>Loading...</div> : [...users].filter(user => !currentUsers.some(currentUser => currentUser.id == user.id)).map(user =>
|
||||
<Dropdown.Item
|
||||
key={user.id}
|
||||
onClick={(event) => toggleUser(event, user)}
|
||||
style={{
|
||||
backgroundColor: selectedUsers.includes(user) ? '#d3d3d3' : ''
|
||||
}}
|
||||
>
|
||||
{user.username}
|
||||
</Dropdown.Item>)}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
<div className='mt-4'>
|
||||
{selectedUsers.length > 0 ? selectedUsers.map(user =>
|
||||
<Badge className="fs-6 me-2 mb-2" key={user.id} bg="primary">{user.username}</Badge>) : <div className="fst-italic">No users selected</div>}
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddUserToUsergroupDialog;
|
69
src/pages/usergroups/dialogs/renameGroupDialog.js
Normal file
69
src/pages/usergroups/dialogs/renameGroupDialog.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* This file is part of VILLASweb.
|
||||
*
|
||||
* VILLASweb is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* VILLASweb is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Form, Col, Button} from 'react-bootstrap';
|
||||
import Dialog from '../../../common/dialogs/dialog';
|
||||
|
||||
const RenameUsergroupDialog = ({isModalOpened, onClose, oldName}) => {
|
||||
|
||||
const [name, setName] = useState(oldName);
|
||||
const [isValid, setIsValid] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (isModalOpened && oldName) {
|
||||
setName(oldName);
|
||||
}
|
||||
}, [isModalOpened, oldName]);
|
||||
|
||||
const handleNameChange = (e) => {
|
||||
const newName = e.target.value;
|
||||
setName(newName);
|
||||
setIsValid(newName.length >= 3 && !(/^\s/.test(newName)));
|
||||
}
|
||||
|
||||
const handleClose = (canceled) => {
|
||||
if(canceled) {
|
||||
onClose(null);
|
||||
} else {
|
||||
onClose(name);
|
||||
}
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
setName('');
|
||||
}
|
||||
|
||||
return (<Dialog
|
||||
show={isModalOpened}
|
||||
title="Rename User Group"
|
||||
buttonTitle="Update"
|
||||
onClose={handleClose}
|
||||
onReset={handleReset}
|
||||
valid={isValid}>
|
||||
<Form>
|
||||
<Form.Group as={Col} controlId="name" style={{marginBottom: '15px'}}>
|
||||
<Form.Label>Name</Form.Label>
|
||||
<Form.Control type="text" placeholder="Enter new name" value={name} onChange={handleNameChange} />
|
||||
<Form.Control.Feedback />
|
||||
</Form.Group>
|
||||
</Form>
|
||||
</Dialog>);
|
||||
}
|
||||
|
||||
export default RenameUsergroupDialog;
|
|
@ -15,16 +15,60 @@
|
|||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import { useGetUsergroupByIdQuery } from "../../../store/apiSlice";
|
||||
import { useState } from "react";
|
||||
import { useGetScenariosQuery, useGetUsergroupByIdQuery } from "../../../store/apiSlice";
|
||||
import { Table, DataColumn, LinkColumn, ButtonColumn } from "../../../common/table";
|
||||
import { iconStyle, buttonStyle } from "../styles";
|
||||
import IconButton from "../../../common/buttons/icon-button";
|
||||
import AddScenarioMappingDialog from "../dialogs/addScenarioMappingDialog";
|
||||
import { useUpdateUsergroupMutation } from "../../../store/apiSlice";
|
||||
import DeleteDialog from "../../../common/dialogs/delete-dialog";
|
||||
|
||||
const UsergroupScenariosTable = ({usergroupID}) => {
|
||||
const {data: {usergroup} = {}, isLoading} = useGetUsergroupByIdQuery(usergroupID);
|
||||
const {data: {usergroup} = {}, isLoading, refetch} = useGetUsergroupByIdQuery(usergroupID);
|
||||
const {data: {scenarios} = {}, isLoading: isScenariosLoading } = useGetScenariosQuery();
|
||||
const [isAddScenarioDialogOpen, setIsAddScenarioDialogOpen] = useState(false);
|
||||
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
|
||||
const [mappingToDelete, setMappingToDelete] = useState({scenarioID: null});
|
||||
const [updateUsergroup] = useUpdateUsergroupMutation();
|
||||
|
||||
const handleAddScenarioMapping = () => {
|
||||
const handleAddScenarioMapping = async (newMapping) => {
|
||||
if(newMapping){
|
||||
try{
|
||||
//add new mapping while saving name and existing mappings if there are any
|
||||
const oldMappings = usergroup.scenarioMappings.length > 0 ? [...usergroup.scenarioMappings] : [];
|
||||
await updateUsergroup({usergroupID: usergroupID, usergroup: {name: usergroup.name, scenarioMappings: [...oldMappings, newMapping]}}).unwrap();
|
||||
refetch();
|
||||
} catch(error) {
|
||||
console.log("Error updating mappings", error);
|
||||
}
|
||||
}
|
||||
setIsAddScenarioDialogOpen(false);
|
||||
}
|
||||
|
||||
const handleRemoveScenarioMapping = async (isConfirmed) => {
|
||||
if(isConfirmed){
|
||||
try {
|
||||
//update usergroup with new mappings without the target
|
||||
const newMappings = [...usergroup.scenarioMappings].filter(mapping => mapping.id !== mappingToDelete.id);
|
||||
await updateUsergroup({usergroupID: usergroupID, usergroup: {name: usergroup.name, scenarioMappings: newMappings}}).unwrap();
|
||||
refetch();
|
||||
} catch (error) {
|
||||
console.log("Error removing mapping", error);
|
||||
}
|
||||
}
|
||||
setIsDeleteDialogOpen(false);
|
||||
setMappingToDelete({scenarioID: null});
|
||||
}
|
||||
|
||||
const getScenarioName = (scenarioID) => {
|
||||
if(isScenariosLoading){
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
const scenario = scenarios.find((scenario) => scenario.id === scenarioID);
|
||||
|
||||
return scenario ? <div>{scenario.name}</div> : <div>unknown</div>;
|
||||
}
|
||||
|
||||
const getDuplicateLabel = (duplicate) => {
|
||||
|
@ -40,7 +84,7 @@ const UsergroupScenariosTable = ({usergroupID}) => {
|
|||
<IconButton
|
||||
childKey={0}
|
||||
tooltip="Add Scenario Mapping"
|
||||
onClick={() => handleAddScenarioMapping()}
|
||||
onClick={() => setIsAddScenarioDialogOpen(true)}
|
||||
icon="plus"
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
|
@ -48,14 +92,27 @@ const UsergroupScenariosTable = ({usergroupID}) => {
|
|||
</span>
|
||||
</h2>
|
||||
<Table data={usergroup.scenarioMappings}>
|
||||
<DataColumn title='ID' dataKey='id' width={70}/>
|
||||
<LinkColumn title="Scenario ID" dataKey="scenarioID" link="/scenarios/" linkKey="id" />
|
||||
<DataColumn title='Duplicate' dataKey='duplicate' modifier={(duplicate) => getDuplicateLabel(duplicate)}/>
|
||||
{/* <ButtonColumn
|
||||
width="200"
|
||||
align="right"
|
||||
/> */}
|
||||
<LinkColumn title="Scenario ID" dataKey="scenarioID" link="/scenarios/" linkKey="scenarioID" width={120} />
|
||||
<DataColumn title='Name' dataKey='scenarioID' modifier={(scenarioID) => getScenarioName(scenarioID)}/>
|
||||
<DataColumn title='Duplicated' dataKey='duplicate' modifier={(duplicate) => getDuplicateLabel(duplicate)}/>
|
||||
<ButtonColumn
|
||||
width="200"
|
||||
align="right"
|
||||
deleteButton
|
||||
onDelete={(index) => {
|
||||
setMappingToDelete(usergroup.scenarioMappings[index]);
|
||||
setIsDeleteDialogOpen(true);
|
||||
}}
|
||||
/>
|
||||
</Table>
|
||||
|
||||
<AddScenarioMappingDialog isDialogOpened={isAddScenarioDialogOpen} mappings={usergroup.scenarioMappings} onClose={(newMapping) => handleAddScenarioMapping(newMapping)} />
|
||||
<DeleteDialog
|
||||
title="scenario mapping for scenario"
|
||||
name={mappingToDelete.scenarioID}
|
||||
show={isDeleteDialogOpen}
|
||||
onClose={(isConfirmed) => handleRemoveScenarioMapping(isConfirmed)}
|
||||
/>
|
||||
</div>);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,16 +15,40 @@
|
|||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import { useGetUsersByUsergroupIdQuery } from "../../../store/apiSlice";
|
||||
import { useState } from "react";
|
||||
import { useGetUsersByUsergroupIdQuery, useAddUserToUsergroupMutation, useDeleteUserFromUsergroupMutation } from "../../../store/apiSlice";
|
||||
import { Table, DataColumn, LinkColumn, ButtonColumn } from "../../../common/table";
|
||||
import { iconStyle, buttonStyle } from "../styles";
|
||||
import IconButton from "../../../common/buttons/icon-button";
|
||||
import AddUserToUsergroupDialog from "../dialogs/addUserToUsergroupDialog";
|
||||
import NotificationsFactory from "../../../common/data-managers/notifications-factory";
|
||||
import notificationsDataManager from "../../../common/data-managers/notifications-data-manager";
|
||||
|
||||
const UsergroupUsersTable = ({usergroupID}) => {
|
||||
const {data: {users}=[], isLoading} = useGetUsersByUsergroupIdQuery(usergroupID);
|
||||
const {data: {users}=[], isLoading, refetch} = useGetUsersByUsergroupIdQuery(usergroupID);
|
||||
const [isAddUserDialogOpen, setIsAddUserDialogOpen] = useState(false);
|
||||
const [addUserToUsergroup] = useAddUserToUsergroupMutation();
|
||||
const [removeUserFromGroup] = useDeleteUserFromUsergroupMutation();
|
||||
|
||||
const handleAddUser = () => {
|
||||
const handleAddUser = async (selectedUsers) => {
|
||||
if(selectedUsers.length > 0){
|
||||
try {
|
||||
await Promise.all(selectedUsers.map(user => addUserToUsergroup({usergroupID: usergroupID, username: user.username}).unwrap()));
|
||||
refetch();
|
||||
} catch (error) {
|
||||
console.log('Error adding users', error);
|
||||
}
|
||||
}
|
||||
setIsAddUserDialogOpen(false);
|
||||
}
|
||||
|
||||
const handleRemoveUser = async (user) => {
|
||||
try{
|
||||
await removeUserFromGroup({usergroupID: usergroupID, username: user.username}).unwrap();
|
||||
refetch();
|
||||
} catch(error) {
|
||||
console.log('Error removing users', error);
|
||||
}
|
||||
}
|
||||
|
||||
if(isLoading) return <div>Loading...</div>;
|
||||
|
@ -36,7 +60,7 @@ const UsergroupUsersTable = ({usergroupID}) => {
|
|||
<IconButton
|
||||
childKey={0}
|
||||
tooltip="Add Users"
|
||||
onClick={() => handleAddUser()}
|
||||
onClick={() => setIsAddUserDialogOpen(true)}
|
||||
icon="plus"
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
|
@ -44,21 +68,20 @@ const UsergroupUsersTable = ({usergroupID}) => {
|
|||
</span>
|
||||
</h2>
|
||||
<Table data={users}>
|
||||
<DataColumn
|
||||
title='ID'
|
||||
dataKey='id'
|
||||
width={70}
|
||||
<DataColumn title='ID' dataKey='id' width={70} />
|
||||
<DataColumn title="Username" dataKey="username" width={150} />
|
||||
<ButtonColumn
|
||||
width="200"
|
||||
align="right"
|
||||
deleteButton
|
||||
onDelete={(index) => handleRemoveUser(users[index])}
|
||||
/>
|
||||
<DataColumn
|
||||
title="Name"
|
||||
dataKey="name"
|
||||
width={70}
|
||||
/>
|
||||
{/* <ButtonColumn
|
||||
width="200"
|
||||
align="right"
|
||||
/> */}
|
||||
</Table>
|
||||
<AddUserToUsergroupDialog
|
||||
isModalOpened={isAddUserDialogOpen}
|
||||
onClose={(selectedUsers) => handleAddUser(selectedUsers)}
|
||||
currentUsers={users}
|
||||
/>
|
||||
</div>);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,23 +15,55 @@
|
|||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import { useState } from "react";
|
||||
import { useParams } from "react-router-dom/cjs/react-router-dom.min";
|
||||
import { Table, DataColumn, LinkColumn } from "../../common/table";
|
||||
import { Row, Col } from "react-bootstrap";
|
||||
import UsergroupScenariosTable from "./tables/usergroup-scenarios-table";
|
||||
import UsergroupUsersTable from "./tables/usergroup-users-table";
|
||||
import { useGetUsergroupByIdQuery } from "../../store/apiSlice";
|
||||
import IconButton from "../../common/buttons/icon-button";
|
||||
import { buttonStyle, iconStyle } from "./styles";
|
||||
import { useGetUsergroupByIdQuery, useUpdateUsergroupMutation } from "../../store/apiSlice";
|
||||
import RenameUsergroupDialog from "./dialogs/renameGroupDialog";
|
||||
|
||||
const Usergroup = (props) => {
|
||||
const Usergroup = () => {
|
||||
const params = useParams();
|
||||
const usergroupID = params.usergroup;
|
||||
const {data: {usergroup} = {}, isLoading} = useGetUsergroupByIdQuery(usergroupID);
|
||||
const {data: {usergroup} = {}, isLoading, refetch} = useGetUsergroupByIdQuery(usergroupID);
|
||||
const [isRenameModalOpened, setIsRenameModalOpened] = useState(false);
|
||||
const [updateUsergroup] = useUpdateUsergroupMutation();
|
||||
|
||||
const handleRename = async (newName) => {
|
||||
if(newName){
|
||||
try {
|
||||
//update only the name
|
||||
await updateUsergroup({usergroupID: usergroup.id, usergroup: {name: newName, ScenarioMappings: usergroup.ScenarioMappings}}).unwrap();
|
||||
refetch();
|
||||
} catch (error) {
|
||||
console.log('Error updating group', error);
|
||||
}
|
||||
}
|
||||
|
||||
setIsRenameModalOpened(false);
|
||||
}
|
||||
|
||||
if(isLoading) return <div className='loading'>Loading...</div>;
|
||||
|
||||
return (
|
||||
<div className='section'>
|
||||
<h1>{usergroup.name}</h1>
|
||||
<h1>
|
||||
{usergroup.name}
|
||||
<span className="icon-button">
|
||||
<IconButton
|
||||
childKey={1}
|
||||
tooltip='Change name'
|
||||
onClick={() => setIsRenameModalOpened(true)}
|
||||
icon='edit'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<Row className="mt-4">
|
||||
<Col>
|
||||
<UsergroupUsersTable usergroupID={usergroupID} />
|
||||
|
@ -40,6 +72,12 @@ const Usergroup = (props) => {
|
|||
<UsergroupScenariosTable usergroupID={usergroupID} />
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<RenameUsergroupDialog
|
||||
isModalOpened={isRenameModalOpened}
|
||||
onClose={handleRename}
|
||||
oldName={usergroup.name}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import IconButton from "../../common/buttons/icon-button";
|
|||
import { buttonStyle, iconStyle } from "./styles";
|
||||
import AddUsergroupDialog from "./dialogs/addUsergroupDialog";
|
||||
import DeleteDialog from "../../common/dialogs/delete-dialog";
|
||||
import moment from "moment";
|
||||
|
||||
const Usergroups = (props) => {
|
||||
const {data: {usergroups} = {}, refetch: refetchUsergroups, isLoading} = useGetUsergroupsQuery();
|
||||
|
@ -60,6 +61,11 @@ const Usergroups = (props) => {
|
|||
setDialogUsergroup({});
|
||||
setIsDeleteDialogOpen(false);
|
||||
}
|
||||
|
||||
const stateUpdateModifier = (dateString) => {
|
||||
const date = moment(dateString);
|
||||
return `${date.fromNow()}`;
|
||||
};
|
||||
|
||||
if(isLoading) return <div>Loading</div>;
|
||||
|
||||
|
@ -69,12 +75,12 @@ const Usergroups = (props) => {
|
|||
User Groups
|
||||
<span className="icon-button">
|
||||
<IconButton
|
||||
childKey={0}
|
||||
tooltip="Add Usergroup"
|
||||
onClick={() => setIsAddDialogOpen(true)}
|
||||
icon="plus"
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
childKey={0}
|
||||
tooltip="Add Usergroup"
|
||||
onClick={() => setIsAddDialogOpen(true)}
|
||||
icon="plus"
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
|
@ -90,6 +96,11 @@ const Usergroups = (props) => {
|
|||
link="/usergroup/"
|
||||
linkKey="id"
|
||||
/>
|
||||
<DataColumn
|
||||
title='Last Update'
|
||||
dataKey='updatedAt'
|
||||
modifier={(updatedAt) => stateUpdateModifier(updatedAt)}
|
||||
/>
|
||||
<ButtonColumn
|
||||
width="200"
|
||||
align="right"
|
||||
|
@ -103,11 +114,11 @@ const Usergroups = (props) => {
|
|||
|
||||
<AddUsergroupDialog isModalOpened={isAddDialogOpen} onClose={handleAddNewGroup} />
|
||||
<DeleteDialog
|
||||
title="scenario"
|
||||
name={dialogUsegroup.name}
|
||||
show={isDeleteDialogOpen}
|
||||
onClose={(isConfirmed) => handleDeleteUsergroup(isConfirmed)}
|
||||
/>
|
||||
title="scenario"
|
||||
name={dialogUsegroup.name}
|
||||
show={isDeleteDialogOpen}
|
||||
onClose={(isConfirmed) => handleDeleteUsergroup(isConfirmed)}
|
||||
/>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,5 +110,8 @@ export const {
|
|||
useAddUsergroupMutation,
|
||||
useDeleteUsergroupMutation,
|
||||
useGetUsergroupByIdQuery,
|
||||
useGetUsersByUsergroupIdQuery
|
||||
useGetUsersByUsergroupIdQuery,
|
||||
useAddUserToUsergroupMutation,
|
||||
useDeleteUserFromUsergroupMutation,
|
||||
useUpdateUsergroupMutation
|
||||
} = apiSlice;
|
||||
|
|
|
@ -31,6 +31,27 @@ export const usergroupEndpoints = (builder) => ({
|
|||
},
|
||||
}),
|
||||
}),
|
||||
updateUsergroup: builder.mutation({
|
||||
query: ({ usergroupID, usergroup }) => ({
|
||||
url: `/usergroups/${usergroupID}`,
|
||||
method: 'PUT',
|
||||
body: { usergroup },
|
||||
}),
|
||||
}),
|
||||
addUserToUsergroup: builder.mutation({
|
||||
query: ({ usergroupID, username }) => ({
|
||||
url: `/usergroups/${usergroupID}/user`,
|
||||
method: 'PUT',
|
||||
params: { username },
|
||||
}),
|
||||
}),
|
||||
deleteUserFromUsergroup: builder.mutation({
|
||||
query: ({ usergroupID, username }) => ({
|
||||
url: `/usergroups/${usergroupID}/user`,
|
||||
method: 'DELETE',
|
||||
params: { username },
|
||||
}),
|
||||
}),
|
||||
getUsersByUsergroupId: builder.query({
|
||||
query: (usergroupID) => `/usergroups/${usergroupID}/users`,
|
||||
}),
|
||||
|
|
Loading…
Add table
Reference in a new issue