mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentral-ui-libs.git
synced 2025-10-30 18:27:52 +00:00
Edit user, edit profile, create user form
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ucentral-libs",
|
||||
"version": "0.8.15",
|
||||
"version": "0.8.16",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ucentral-libs",
|
||||
"version": "0.8.15",
|
||||
"version": "0.8.16",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.6",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ucentral-libs",
|
||||
"version": "0.8.15",
|
||||
"version": "0.8.16",
|
||||
"main": "dist/index.js",
|
||||
"source": "src/index.js",
|
||||
"engines": {
|
||||
|
||||
@@ -28,7 +28,7 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies
|
||||
|
||||
return (
|
||||
<CForm>
|
||||
<CFormGroup row>
|
||||
<CFormGroup row className="pb-3">
|
||||
<CLabel sm="2" col htmlFor="email">
|
||||
{t('user.email_address')}
|
||||
</CLabel>
|
||||
@@ -42,14 +42,41 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies
|
||||
/>
|
||||
<CInvalidFeedback>{t('user.provide_email')}</CInvalidFeedback>
|
||||
</CCol>
|
||||
<CLabel sm="2" col htmlFor="userRole">
|
||||
{t('user.user_role')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CSelect custom id="userRole" defaultValue="Admin" onChange={updateField}>
|
||||
<option value="admin">Admin</option>
|
||||
<option value="csr">CSR</option>
|
||||
<option value="root">Root</option>
|
||||
<option value="special">Special</option>
|
||||
<option value="sub">Sub</option>
|
||||
<option value="system">System</option>
|
||||
</CSelect>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CLabel sm="2" col htmlFor="name">
|
||||
{t('user.name')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CInput id="name" value={fields.name.value} onChange={updateField} maxLength="20" />
|
||||
</CCol>
|
||||
<CLabel sm="2" col htmlFor="description">
|
||||
{t('user.description')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CInput
|
||||
id="description"
|
||||
value={fields.description.value}
|
||||
onChange={updateField}
|
||||
maxLength="50"
|
||||
/>
|
||||
<small className="text-muted">{t('common.optional')}</small>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CFormGroup row className="pb-3">
|
||||
<CLabel sm="2" col htmlFor="currentPassword">
|
||||
{t('user.password')}
|
||||
</CLabel>
|
||||
@@ -89,19 +116,6 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CLabel sm="2" col htmlFor="userRole">
|
||||
{t('user.user_role')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CSelect custom id="userRole" defaultValue="Admin" onChange={updateField}>
|
||||
<option value="admin">Admin</option>
|
||||
<option value="csr">CSR</option>
|
||||
<option value="root">Root</option>
|
||||
<option value="special">Special</option>
|
||||
<option value="sub">Sub</option>
|
||||
<option value="system">System</option>
|
||||
</CSelect>
|
||||
</CCol>
|
||||
<CLabel sm="2" col htmlFor="notes">
|
||||
{t('user.note')}
|
||||
</CLabel>
|
||||
@@ -110,35 +124,9 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies
|
||||
<small className="text-muted">{t('common.optional')}</small>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CLabel sm="2" col htmlFor="description">
|
||||
{t('user.description')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CInput
|
||||
id="description"
|
||||
value={fields.description.value}
|
||||
onChange={updateField}
|
||||
maxLength="50"
|
||||
/>
|
||||
<small className="text-muted">{t('common.optional')}</small>
|
||||
</CCol>
|
||||
<CLabel sm="2" col />
|
||||
<CCol sm="4" />
|
||||
</CFormGroup>
|
||||
<CRow>
|
||||
<CCol />
|
||||
<CCol xs={3} className="mt-2 text-right">
|
||||
<CLink
|
||||
className="c-subheader-nav-link"
|
||||
aria-current="page"
|
||||
href={policies.accessPolicy}
|
||||
target="_blank"
|
||||
style={{ paddingRight: '30px' }}
|
||||
hidden={policies.accessPolicy.length === 0}
|
||||
>
|
||||
{t('common.access_policy')}
|
||||
</CLink>
|
||||
<CCol xs={2} className="mt-2 text-right">
|
||||
<CLink
|
||||
className="c-subheader-nav-link"
|
||||
aria-current="page"
|
||||
@@ -149,10 +137,10 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies
|
||||
{t('common.password_policy')}
|
||||
</CLink>
|
||||
</CCol>
|
||||
<CCol xs={1} className="text-right">
|
||||
<CCol xs={2} className="text-center">
|
||||
<LoadingButton
|
||||
label={t('user.create')}
|
||||
isLoadingLabel={t('common.loading_ellipsis')}
|
||||
isLoadingLabel={t('user.creating')}
|
||||
isLoading={loading}
|
||||
action={createUser}
|
||||
block={false}
|
||||
|
||||
140
src/components/EditMyProfile/index.js
Normal file
140
src/components/EditMyProfile/index.js
Normal file
@@ -0,0 +1,140 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
CButton,
|
||||
CCol,
|
||||
CForm,
|
||||
CFormGroup,
|
||||
CInput,
|
||||
CInputGroup,
|
||||
CInputGroupAppend,
|
||||
CInvalidFeedback,
|
||||
CLabel,
|
||||
CLink,
|
||||
CPopover,
|
||||
CRow,
|
||||
CSelect,
|
||||
} from '@coreui/react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import NotesTable from '../NotesTable';
|
||||
import LoadingButton from '../LoadingButton';
|
||||
|
||||
const EditMyProfile = ({ t, user, updateUserWithId, loading, saveUser, policies, addNote }) => {
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const toggleShowPassword = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
|
||||
return (
|
||||
<CForm>
|
||||
<CFormGroup row>
|
||||
<CLabel sm="2" col htmlFor="name">
|
||||
{t('user.name')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CInput id="name" value={user.name.value} onChange={updateUserWithId} maxLength="20" />
|
||||
</CCol>
|
||||
<CLabel sm="2" col htmlFor="description">
|
||||
{t('user.description')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CInput
|
||||
id="description"
|
||||
value={user.description.value}
|
||||
onChange={updateUserWithId}
|
||||
maxLength="50"
|
||||
/>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CLabel sm="2" col htmlFor="userRole">
|
||||
{t('user.user_role')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CSelect custom id="userRole" onChange={updateUserWithId} value={user.userRole.value}>
|
||||
<option value="admin">Admin</option>
|
||||
<option value="csr">CSR</option>
|
||||
<option value="root">Root</option>
|
||||
<option value="special">Special</option>
|
||||
<option value="sub">Sub</option>
|
||||
<option value="system">System</option>
|
||||
</CSelect>
|
||||
</CCol>
|
||||
<CLabel sm="2" col htmlFor="currentPassword">
|
||||
{t('login.new_password')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CInputGroup>
|
||||
<CInput
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
id="currentPassword"
|
||||
value={user.currentPassword.value}
|
||||
onChange={updateUserWithId}
|
||||
invalid={user.currentPassword.error}
|
||||
maxLength="50"
|
||||
/>
|
||||
<CInputGroupAppend>
|
||||
<CPopover content={t('user.show_hide_password')}>
|
||||
<CButton type="button" onClick={toggleShowPassword} color="secondary">
|
||||
<CIcon
|
||||
name={showPassword ? 'cil-envelope-open' : 'cil-envelope-closed'}
|
||||
size="sm"
|
||||
/>
|
||||
</CButton>
|
||||
</CPopover>
|
||||
</CInputGroupAppend>
|
||||
<CInvalidFeedback>{t('user.provide_password')}</CInvalidFeedback>
|
||||
</CInputGroup>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol sm="6">
|
||||
<NotesTable
|
||||
t={t}
|
||||
notes={user.notes.value}
|
||||
addNote={addNote}
|
||||
loading={loading}
|
||||
size="lg"
|
||||
/>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CRow>
|
||||
<CCol />
|
||||
<CCol xs={1} className="mt-2 text-right">
|
||||
<CLink
|
||||
className="c-subheader-nav-link"
|
||||
aria-current="page"
|
||||
href={policies.passwordPolicy}
|
||||
target="_blank"
|
||||
hidden={policies.passwordPolicy.length === 0}
|
||||
>
|
||||
{t('common.password_policy')}
|
||||
</CLink>
|
||||
</CCol>
|
||||
<CCol xs={1} className="text-center">
|
||||
<LoadingButton
|
||||
label={t('common.save')}
|
||||
isLoadingLabel={t('common.saving')}
|
||||
isLoading={loading}
|
||||
action={saveUser}
|
||||
block={false}
|
||||
disabled={loading}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CForm>
|
||||
);
|
||||
};
|
||||
|
||||
EditMyProfile.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
user: PropTypes.instanceOf(Object).isRequired,
|
||||
updateUserWithId: PropTypes.func.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
saveUser: PropTypes.func.isRequired,
|
||||
policies: PropTypes.instanceOf(Object).isRequired,
|
||||
addNote: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default React.memo(EditMyProfile);
|
||||
149
src/components/EditUserForm/index.js
Normal file
149
src/components/EditUserForm/index.js
Normal file
@@ -0,0 +1,149 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
CButton,
|
||||
CCol,
|
||||
CForm,
|
||||
CFormGroup,
|
||||
CInput,
|
||||
CInputGroup,
|
||||
CInputGroupAppend,
|
||||
CInvalidFeedback,
|
||||
CLabel,
|
||||
CLink,
|
||||
CPopover,
|
||||
CRow,
|
||||
CSelect,
|
||||
CSwitch,
|
||||
} from '@coreui/react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import NotesTable from '../NotesTable';
|
||||
import LoadingButton from '../LoadingButton';
|
||||
|
||||
const EditUserForm = ({ t, user, updateUserWithId, loading, saveUser, policies, addNote }) => {
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const toggleShowPassword = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
|
||||
return (
|
||||
<CForm>
|
||||
<CFormGroup row>
|
||||
<CLabel sm="2" col htmlFor="name">
|
||||
{t('user.name')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CInput id="name" value={user.name.value} onChange={updateUserWithId} maxLength="20" />
|
||||
</CCol>
|
||||
<CLabel sm="2" col htmlFor="description">
|
||||
{t('user.description')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CInput
|
||||
id="description"
|
||||
value={user.description.value}
|
||||
onChange={updateUserWithId}
|
||||
maxLength="50"
|
||||
/>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CLabel sm="2" col htmlFor="userRole">
|
||||
{t('user.user_role')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CSelect custom id="userRole" onChange={updateUserWithId} value={user.userRole.value}>
|
||||
<option value="admin">Admin</option>
|
||||
<option value="csr">CSR</option>
|
||||
<option value="root">Root</option>
|
||||
<option value="special">Special</option>
|
||||
<option value="sub">Sub</option>
|
||||
<option value="system">System</option>
|
||||
</CSelect>
|
||||
</CCol>
|
||||
<CLabel sm="2" col htmlFor="currentPassword">
|
||||
{t('login.new_password')}
|
||||
</CLabel>
|
||||
<CCol sm="4">
|
||||
<CInputGroup>
|
||||
<CInput
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
id="currentPassword"
|
||||
value={user.currentPassword.value}
|
||||
onChange={updateUserWithId}
|
||||
invalid={user.currentPassword.error}
|
||||
maxLength="50"
|
||||
/>
|
||||
<CInputGroupAppend>
|
||||
<CPopover content={t('user.show_hide_password')}>
|
||||
<CButton type="button" onClick={toggleShowPassword} color="secondary">
|
||||
<CIcon
|
||||
name={showPassword ? 'cil-envelope-open' : 'cil-envelope-closed'}
|
||||
size="sm"
|
||||
/>
|
||||
</CButton>
|
||||
</CPopover>
|
||||
</CInputGroupAppend>
|
||||
<CInvalidFeedback>{t('user.provide_password')}</CInvalidFeedback>
|
||||
</CInputGroup>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CLabel sm="3" col htmlFor="changePassword">
|
||||
{t('user.force_password_change')}
|
||||
</CLabel>
|
||||
<CCol sm="1">
|
||||
<CInputGroup>
|
||||
<CSwitch
|
||||
id="changePassword"
|
||||
color="success"
|
||||
defaultChecked={user.changePassword.value}
|
||||
onClick={updateUserWithId}
|
||||
size="lg"
|
||||
/>
|
||||
</CInputGroup>
|
||||
</CCol>
|
||||
<CCol sm="8">
|
||||
<NotesTable t={t} notes={user.notes.value} addNote={addNote} loading={loading} />
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CRow>
|
||||
<CCol />
|
||||
<CCol xs={2} className="mt-2 text-right">
|
||||
<CLink
|
||||
className="c-subheader-nav-link"
|
||||
aria-current="page"
|
||||
href={policies.passwordPolicy}
|
||||
target="_blank"
|
||||
hidden={policies.passwordPolicy.length === 0}
|
||||
>
|
||||
{t('common.password_policy')}
|
||||
</CLink>
|
||||
</CCol>
|
||||
<CCol xs={2} className="text-center">
|
||||
<LoadingButton
|
||||
label={t('common.save')}
|
||||
isLoadingLabel={t('common.saving')}
|
||||
isLoading={loading}
|
||||
action={saveUser}
|
||||
block={false}
|
||||
disabled={loading}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CForm>
|
||||
);
|
||||
};
|
||||
|
||||
EditUserForm.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
user: PropTypes.instanceOf(Object).isRequired,
|
||||
updateUserWithId: PropTypes.func.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
saveUser: PropTypes.func.isRequired,
|
||||
policies: PropTypes.instanceOf(Object).isRequired,
|
||||
addNote: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default React.memo(EditUserForm);
|
||||
49
src/components/EditUserModal/index.js
Normal file
49
src/components/EditUserModal/index.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CModal, CModalBody, CModalHeader, CModalTitle } from '@coreui/react';
|
||||
import EditUserForm from '../EditUserForm';
|
||||
|
||||
const EditUserModal = ({
|
||||
t,
|
||||
user,
|
||||
updateUserWithId,
|
||||
saveUser,
|
||||
loading,
|
||||
policies,
|
||||
show,
|
||||
toggle,
|
||||
addNote,
|
||||
}) => (
|
||||
<CModal show={show} onClose={toggle} size="xl">
|
||||
<CModalHeader>
|
||||
<CModalTitle>
|
||||
{t('user.edit')} {user.email.value}
|
||||
</CModalTitle>
|
||||
</CModalHeader>
|
||||
<CModalBody>
|
||||
<EditUserForm
|
||||
t={t}
|
||||
user={user}
|
||||
updateUserWithId={updateUserWithId}
|
||||
saveUser={saveUser}
|
||||
loading={loading}
|
||||
policies={policies}
|
||||
addNote={addNote}
|
||||
/>
|
||||
</CModalBody>
|
||||
</CModal>
|
||||
);
|
||||
|
||||
EditUserModal.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
user: PropTypes.instanceOf(Object).isRequired,
|
||||
updateUserWithId: PropTypes.func.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
saveUser: PropTypes.func.isRequired,
|
||||
policies: PropTypes.instanceOf(Object).isRequired,
|
||||
show: PropTypes.bool.isRequired,
|
||||
toggle: PropTypes.func.isRequired,
|
||||
addNote: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default React.memo(EditUserModal);
|
||||
87
src/components/NotesTable/index.js
Normal file
87
src/components/NotesTable/index.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CDataTable, CRow, CCol, CLabel, CInput } from '@coreui/react';
|
||||
import { prettyDate } from '../../utils/formatting';
|
||||
import LoadingButton from '../LoadingButton';
|
||||
|
||||
const NotesTable = ({ t, notes, addNote, loading, size }) => {
|
||||
const [currentNote, setCurrentNote] = useState('');
|
||||
|
||||
const columns = [
|
||||
{ key: 'created', label: t('common.date'), _style: { width: '30%' } },
|
||||
{ key: 'createdBy', label: t('common.created_by'), _style: { width: '20%' } },
|
||||
{ key: 'note', label: t('configuration.note'), _style: { width: '50%' } },
|
||||
];
|
||||
|
||||
const saveNote = () => {
|
||||
addNote(currentNote);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentNote('');
|
||||
}, [notes]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CRow>
|
||||
<CLabel col sm="2">
|
||||
{t('configuration.notes')} :
|
||||
</CLabel>
|
||||
<CCol sm={size === 'm' ? '7' : '8'}>
|
||||
<CInput
|
||||
id="notes-input"
|
||||
name="text-input"
|
||||
value={currentNote}
|
||||
onChange={(e) => setCurrentNote(e.target.value)}
|
||||
/>
|
||||
</CCol>
|
||||
<CCol sm={size === 'm' ? '3' : '2'}>
|
||||
<LoadingButton
|
||||
label={t('common.add')}
|
||||
isLoadingLabel={t('common.adding_ellipsis')}
|
||||
isLoading={loading}
|
||||
action={saveNote}
|
||||
disabled={loading || currentNote === ''}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className="pt-3">
|
||||
<CCol>
|
||||
<div className="overflow-auto" style={{ height: '200px' }}>
|
||||
<CDataTable
|
||||
striped
|
||||
responsive
|
||||
border
|
||||
loading={loading}
|
||||
fields={columns}
|
||||
items={notes || []}
|
||||
noItemsView={{ noItems: t('common.no_items') }}
|
||||
sorterValue={{ column: 'created', desc: 'true' }}
|
||||
scopedSlots={{
|
||||
created: (item) => (
|
||||
<td>
|
||||
{item.created && item.created !== 0 ? prettyDate(item.created) : t('common.na')}
|
||||
</td>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
NotesTable.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
notes: PropTypes.instanceOf(Array).isRequired,
|
||||
addNote: PropTypes.func.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
size: PropTypes.string,
|
||||
};
|
||||
|
||||
NotesTable.defaultProps = {
|
||||
size: 'm',
|
||||
};
|
||||
|
||||
export default NotesTable;
|
||||
@@ -2,18 +2,17 @@ import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactPaginate from 'react-paginate';
|
||||
import {
|
||||
CButton,
|
||||
CCard,
|
||||
CCardHeader,
|
||||
CSelect,
|
||||
CCol,
|
||||
CRow,
|
||||
CCardBody,
|
||||
CCardHeader,
|
||||
CCol,
|
||||
CDataTable,
|
||||
CPopover,
|
||||
CButton,
|
||||
CLink,
|
||||
CRow,
|
||||
CSelect,
|
||||
} from '@coreui/react';
|
||||
import { cilBan, cilCheckCircle, cilInfo, cilPlus, cilTrash } from '@coreui/icons';
|
||||
import { cilBan, cilCheckCircle, cilPencil, cilSync, cilTrash } from '@coreui/icons';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import { capitalizeFirstLetter, prettyDate } from '../../utils/formatting';
|
||||
import DeleteModal from '../DeleteModal';
|
||||
@@ -28,6 +27,9 @@ const UserListTable = ({
|
||||
setPage,
|
||||
deleteUser,
|
||||
deleteLoading,
|
||||
toggleCreate,
|
||||
toggleEdit,
|
||||
refreshUsers,
|
||||
}) => {
|
||||
const [idToDelete, setIdToDelete] = useState('');
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
@@ -50,13 +52,20 @@ const UserListTable = ({
|
||||
{ key: 'email', label: t('user.login_id'), _style: { width: '20%' } },
|
||||
{ key: 'name', label: t('user.name'), _style: { width: '20%' } },
|
||||
{ key: 'userRole', label: t('user.user_role'), _style: { width: '5%' } },
|
||||
{ key: 'description', label: t('user.description'), _style: { width: '25%' } },
|
||||
{ key: 'description', label: t('user.description'), _style: { width: '24%' } },
|
||||
{ key: 'validated', label: t('user.validated'), _style: { width: '5%' } },
|
||||
{ key: 'lastLogin', label: t('user.last_login'), _style: { width: '20%' } },
|
||||
{
|
||||
key: 'user_actions',
|
||||
key: 'user_details',
|
||||
label: '',
|
||||
_style: { width: '5%' },
|
||||
_style: { width: '3%' },
|
||||
sorter: false,
|
||||
filter: false,
|
||||
},
|
||||
{
|
||||
key: 'user_delete',
|
||||
label: '',
|
||||
_style: { width: '3%' },
|
||||
sorter: false,
|
||||
filter: false,
|
||||
},
|
||||
@@ -68,17 +77,44 @@ const UserListTable = ({
|
||||
<CCardHeader>
|
||||
<CRow>
|
||||
<CCol />
|
||||
<CCol xs={1}>
|
||||
<CSelect
|
||||
custom
|
||||
defaultValue={usersPerPage}
|
||||
onChange={(e) => setUsersPerPage(e.target.value)}
|
||||
disabled={loading}
|
||||
>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
</CSelect>
|
||||
<CCol xs={2}>
|
||||
<CRow>
|
||||
<CCol xs={5}>
|
||||
<div className="text-right">
|
||||
<CSelect
|
||||
custom
|
||||
defaultValue={usersPerPage}
|
||||
onChange={(e) => setUsersPerPage(e.target.value)}
|
||||
disabled={loading}
|
||||
>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
</CSelect>
|
||||
</div>
|
||||
</CCol>
|
||||
<CCol xs={5}>
|
||||
<div className="text-right">
|
||||
<CButton
|
||||
color="primary"
|
||||
variant="outline"
|
||||
shape="square"
|
||||
onClick={toggleCreate}
|
||||
>
|
||||
{t('user.create')}
|
||||
</CButton>
|
||||
</div>
|
||||
</CCol>
|
||||
<CCol xs={2}>
|
||||
<div className="text-center">
|
||||
<CPopover content={t('common.refresh')}>
|
||||
<CButton onClick={refreshUsers} color="primary" variant="outline">
|
||||
<CIcon name="cil-sync" content={cilSync} />
|
||||
</CButton>
|
||||
</CPopover>
|
||||
</div>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CCardHeader>
|
||||
@@ -89,23 +125,6 @@ const UserListTable = ({
|
||||
loading={loading}
|
||||
hover
|
||||
border
|
||||
columnHeaderSlot={{
|
||||
user_actions: (
|
||||
<div className="text-center">
|
||||
<CPopover content={t('user.create')}>
|
||||
<CLink
|
||||
className="c-subheader-nav-link"
|
||||
aria-current="page"
|
||||
to={() => `/users/create`}
|
||||
>
|
||||
<CButton color="primary" variant="outline" shape="square" size="sm">
|
||||
<CIcon name="cil-info" content={cilPlus} size="sm" />
|
||||
</CButton>
|
||||
</CLink>
|
||||
</CPopover>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
scopedSlots={{
|
||||
validated: (item) => (
|
||||
<td className="text-center">
|
||||
@@ -120,35 +139,33 @@ const UserListTable = ({
|
||||
userRole: (item) => (
|
||||
<td>{item.userRole ? capitalizeFirstLetter(item.userRole) : ''}</td>
|
||||
),
|
||||
user_actions: (item) => (
|
||||
user_details: (item) => (
|
||||
<td className="py-2 text-center">
|
||||
<CRow>
|
||||
<CCol>
|
||||
<CPopover content={t('configuration.details')}>
|
||||
<CLink
|
||||
className="c-subheader-nav-link"
|
||||
aria-current="page"
|
||||
to={() => `/users/${item.Id}`}
|
||||
>
|
||||
<CButton color="primary" variant="outline" shape="square" size="sm">
|
||||
<CIcon name="cil-info" content={cilInfo} size="sm" />
|
||||
</CButton>
|
||||
</CLink>
|
||||
</CPopover>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CPopover content={t('common.delete')}>
|
||||
<CButton
|
||||
onClick={() => handleDeleteClick(item.Id)}
|
||||
color="primary"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
>
|
||||
<CIcon content={cilTrash} size="sm" />
|
||||
</CButton>
|
||||
</CPopover>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CPopover content={t('common.edit')}>
|
||||
<CButton
|
||||
color="primary"
|
||||
variant="outline"
|
||||
shape="square"
|
||||
size="sm"
|
||||
onClick={() => toggleEdit(item.Id)}
|
||||
>
|
||||
<CIcon name="cil-pencil" content={cilPencil} size="sm" />
|
||||
</CButton>
|
||||
</CPopover>
|
||||
</td>
|
||||
),
|
||||
user_delete: (item) => (
|
||||
<td className="py-2 text-center">
|
||||
<CPopover content={t('common.delete')}>
|
||||
<CButton
|
||||
onClick={() => handleDeleteClick(item.Id)}
|
||||
color="primary"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
>
|
||||
<CIcon content={cilTrash} size="sm" />
|
||||
</CButton>
|
||||
</CPopover>
|
||||
</td>
|
||||
),
|
||||
}}
|
||||
@@ -196,6 +213,9 @@ UserListTable.propTypes = {
|
||||
setPage: PropTypes.func.isRequired,
|
||||
deleteUser: PropTypes.func.isRequired,
|
||||
deleteLoading: PropTypes.bool.isRequired,
|
||||
toggleCreate: PropTypes.func.isRequired,
|
||||
toggleEdit: PropTypes.func.isRequired,
|
||||
refreshUsers: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default React.memo(UserListTable);
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
CButton,
|
||||
CCard,
|
||||
CCardBody,
|
||||
CCardHeader,
|
||||
CCol,
|
||||
CForm,
|
||||
CFormGroup,
|
||||
CInput,
|
||||
CInputGroup,
|
||||
CInputGroupAppend,
|
||||
CInvalidFeedback,
|
||||
CLabel,
|
||||
CPopover,
|
||||
CRow,
|
||||
CSelect,
|
||||
CSwitch,
|
||||
} from '@coreui/react';
|
||||
import PropTypes from 'prop-types';
|
||||
import LoadingButton from 'components/LoadingButton';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
|
||||
const CreateUserForm = ({ t, user, updateUserWithId, loading, saveUser }) => {
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const toggleShowPassword = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
|
||||
return (
|
||||
<CCard>
|
||||
<CCardHeader>{t('common.details')}</CCardHeader>
|
||||
<CCardBody>
|
||||
<CForm>
|
||||
<CFormGroup row>
|
||||
<CCol>
|
||||
<CLabel htmlFor="email">{t('user.email_address')}</CLabel>
|
||||
<p className="form-control-static mt-2">{user.email.value}</p>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CLabel htmlFor="name">{t('user.name')}</CLabel>
|
||||
<CInput
|
||||
id="name"
|
||||
value={user.name.value}
|
||||
onChange={updateUserWithId}
|
||||
maxLength="20"
|
||||
/>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CLabel htmlFor="changePassword">{t('user.force_password_change')}</CLabel>
|
||||
<CInputGroup>
|
||||
<CSwitch
|
||||
id="changePassword"
|
||||
color="success"
|
||||
defaultChecked={user.changePassword.value}
|
||||
onClick={updateUserWithId}
|
||||
size="lg"
|
||||
/>
|
||||
</CInputGroup>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol>
|
||||
<CLabel htmlFor="userRole">{t('user.user_role')}</CLabel>
|
||||
<CSelect custom id="userRole" defaultValue="Admin" onChange={updateUserWithId}>
|
||||
<option value="admin">Admin</option>
|
||||
<option value="csr">CSR</option>
|
||||
<option value="root">Root</option>
|
||||
<option value="special">Special</option>
|
||||
<option value="sub">Sub</option>
|
||||
<option value="system">System</option>
|
||||
</CSelect>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CLabel htmlFor="newPascurrentPasswordsword">{t('login.new_password')}</CLabel>
|
||||
<CInputGroup>
|
||||
<CInput
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
id="currentPassword"
|
||||
value={user.currentPassword.value}
|
||||
onChange={updateUserWithId}
|
||||
invalid={user.currentPassword.error}
|
||||
maxLength="50"
|
||||
/>
|
||||
<CInputGroupAppend>
|
||||
<CPopover content={t('user.show_hide_password')}>
|
||||
<CButton type="button" onClick={toggleShowPassword} color="secondary">
|
||||
<CIcon
|
||||
name={showPassword ? 'cil-envelope-open' : 'cil-envelope-closed'}
|
||||
size="sm"
|
||||
/>
|
||||
</CButton>
|
||||
</CPopover>
|
||||
</CInputGroupAppend>
|
||||
<CInvalidFeedback>{t('user.provide_password')}</CInvalidFeedback>
|
||||
</CInputGroup>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol>
|
||||
<CLabel htmlFor="description">{t('user.description')}</CLabel>
|
||||
<CInput
|
||||
id="description"
|
||||
value={user.description.value}
|
||||
onChange={updateUserWithId}
|
||||
maxLength="50"
|
||||
/>
|
||||
</CCol>
|
||||
<CCol />
|
||||
</CFormGroup>
|
||||
<CRow>
|
||||
<CCol />
|
||||
<CCol xs={3} className="text-right">
|
||||
<LoadingButton
|
||||
label={t('common.save')}
|
||||
isLoadingLabel={t('common.saving')}
|
||||
isLoading={loading}
|
||||
action={saveUser}
|
||||
block={false}
|
||||
disabled={loading}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CForm>
|
||||
</CCardBody>
|
||||
</CCard>
|
||||
);
|
||||
};
|
||||
|
||||
CreateUserForm.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
user: PropTypes.instanceOf(Object).isRequired,
|
||||
updateUserWithId: PropTypes.func.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
saveUser: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default React.memo(CreateUserForm);
|
||||
@@ -18,7 +18,7 @@ export default (initialState) => {
|
||||
(key, newValues) => {
|
||||
setUser({
|
||||
...user,
|
||||
[user]: {
|
||||
[key]: {
|
||||
...user[key],
|
||||
...newValues,
|
||||
},
|
||||
|
||||
@@ -10,7 +10,9 @@ export { default as UserListTable } from './components/UserListTable';
|
||||
export { default as CreateUserForm } from './components/CreateUserForm';
|
||||
export { default as LoadingButton } from './components/LoadingButton';
|
||||
export { default as ConfirmFooter } from './components/ConfirmFooter';
|
||||
export { default as UserProfileCard } from './components/UserProfileCard';
|
||||
export { default as EditUserModal } from './components/EditUserModal';
|
||||
export { default as EditUserForm } from './components/EditUserForm';
|
||||
export { default as EditMyProfile } from './components/EditMyProfile';
|
||||
|
||||
// Pages
|
||||
export { default as LoginPage } from './components/LoginPage';
|
||||
|
||||
@@ -62,7 +62,7 @@ const Header = ({
|
||||
<CHeaderNav className="px-1">
|
||||
<CDropdown inNav className="c-header-nav-items mx-2" direction="down">
|
||||
<CDropdownToggle className="c-header-nav-link" caret={false}>
|
||||
<div className="c-avatar">
|
||||
<div className="c-avatar avatar">
|
||||
<ImgWithFallback
|
||||
src={user.avatar && user.avatar !== '' ? user.avatar : '/'}
|
||||
fallback={() => emailToName(user.email)}
|
||||
@@ -70,11 +70,11 @@ const Header = ({
|
||||
</div>
|
||||
</CDropdownToggle>
|
||||
<CDropdownMenu className="pt-0" placement="bottom-end">
|
||||
<CDropdownItem>
|
||||
<div className="px-3">My Account</div>
|
||||
<CDropdownItem to={() => '/myprofile'}>
|
||||
<div className="px-3">{t('user.my_profile')}</div>
|
||||
</CDropdownItem>
|
||||
<CDropdownItem onClick={() => logout(authToken, endpoints.ucentralsec)}>
|
||||
<strong className="px-3">Logout</strong>
|
||||
<strong className="px-3">{t('common.logout')}</strong>
|
||||
<CIcon name="cilAccountLogout" content={cilAccountLogout} />
|
||||
</CDropdownItem>
|
||||
</CDropdownMenu>
|
||||
|
||||
Reference in New Issue
Block a user