mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentral-ui-libs.git
synced 2025-11-02 03:37:56 +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",
|
"name": "ucentral-libs",
|
||||||
"version": "0.8.15",
|
"version": "0.8.16",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ucentral-libs",
|
"name": "ucentral-libs",
|
||||||
"version": "0.8.15",
|
"version": "0.8.16",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.14.6",
|
"@babel/core": "^7.14.6",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ucentral-libs",
|
"name": "ucentral-libs",
|
||||||
"version": "0.8.15",
|
"version": "0.8.16",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"source": "src/index.js",
|
"source": "src/index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CForm>
|
<CForm>
|
||||||
<CFormGroup row>
|
<CFormGroup row className="pb-3">
|
||||||
<CLabel sm="2" col htmlFor="email">
|
<CLabel sm="2" col htmlFor="email">
|
||||||
{t('user.email_address')}
|
{t('user.email_address')}
|
||||||
</CLabel>
|
</CLabel>
|
||||||
@@ -42,14 +42,41 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies
|
|||||||
/>
|
/>
|
||||||
<CInvalidFeedback>{t('user.provide_email')}</CInvalidFeedback>
|
<CInvalidFeedback>{t('user.provide_email')}</CInvalidFeedback>
|
||||||
</CCol>
|
</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">
|
<CLabel sm="2" col htmlFor="name">
|
||||||
{t('user.name')}
|
{t('user.name')}
|
||||||
</CLabel>
|
</CLabel>
|
||||||
<CCol sm="4">
|
<CCol sm="4">
|
||||||
<CInput id="name" value={fields.name.value} onChange={updateField} maxLength="20" />
|
<CInput id="name" value={fields.name.value} onChange={updateField} maxLength="20" />
|
||||||
</CCol>
|
</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>
|
||||||
<CFormGroup row>
|
<CFormGroup row className="pb-3">
|
||||||
<CLabel sm="2" col htmlFor="currentPassword">
|
<CLabel sm="2" col htmlFor="currentPassword">
|
||||||
{t('user.password')}
|
{t('user.password')}
|
||||||
</CLabel>
|
</CLabel>
|
||||||
@@ -89,19 +116,6 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies
|
|||||||
</CCol>
|
</CCol>
|
||||||
</CFormGroup>
|
</CFormGroup>
|
||||||
<CFormGroup row>
|
<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">
|
<CLabel sm="2" col htmlFor="notes">
|
||||||
{t('user.note')}
|
{t('user.note')}
|
||||||
</CLabel>
|
</CLabel>
|
||||||
@@ -110,35 +124,9 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies
|
|||||||
<small className="text-muted">{t('common.optional')}</small>
|
<small className="text-muted">{t('common.optional')}</small>
|
||||||
</CCol>
|
</CCol>
|
||||||
</CFormGroup>
|
</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>
|
<CRow>
|
||||||
<CCol />
|
<CCol />
|
||||||
<CCol xs={3} className="mt-2 text-right">
|
<CCol xs={2} 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>
|
|
||||||
<CLink
|
<CLink
|
||||||
className="c-subheader-nav-link"
|
className="c-subheader-nav-link"
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
@@ -149,10 +137,10 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies
|
|||||||
{t('common.password_policy')}
|
{t('common.password_policy')}
|
||||||
</CLink>
|
</CLink>
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol xs={1} className="text-right">
|
<CCol xs={2} className="text-center">
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
label={t('user.create')}
|
label={t('user.create')}
|
||||||
isLoadingLabel={t('common.loading_ellipsis')}
|
isLoadingLabel={t('user.creating')}
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
action={createUser}
|
action={createUser}
|
||||||
block={false}
|
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 PropTypes from 'prop-types';
|
||||||
import ReactPaginate from 'react-paginate';
|
import ReactPaginate from 'react-paginate';
|
||||||
import {
|
import {
|
||||||
|
CButton,
|
||||||
CCard,
|
CCard,
|
||||||
CCardHeader,
|
|
||||||
CSelect,
|
|
||||||
CCol,
|
|
||||||
CRow,
|
|
||||||
CCardBody,
|
CCardBody,
|
||||||
|
CCardHeader,
|
||||||
|
CCol,
|
||||||
CDataTable,
|
CDataTable,
|
||||||
CPopover,
|
CPopover,
|
||||||
CButton,
|
CRow,
|
||||||
CLink,
|
CSelect,
|
||||||
} from '@coreui/react';
|
} 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 CIcon from '@coreui/icons-react';
|
||||||
import { capitalizeFirstLetter, prettyDate } from '../../utils/formatting';
|
import { capitalizeFirstLetter, prettyDate } from '../../utils/formatting';
|
||||||
import DeleteModal from '../DeleteModal';
|
import DeleteModal from '../DeleteModal';
|
||||||
@@ -28,6 +27,9 @@ const UserListTable = ({
|
|||||||
setPage,
|
setPage,
|
||||||
deleteUser,
|
deleteUser,
|
||||||
deleteLoading,
|
deleteLoading,
|
||||||
|
toggleCreate,
|
||||||
|
toggleEdit,
|
||||||
|
refreshUsers,
|
||||||
}) => {
|
}) => {
|
||||||
const [idToDelete, setIdToDelete] = useState('');
|
const [idToDelete, setIdToDelete] = useState('');
|
||||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||||
@@ -50,13 +52,20 @@ const UserListTable = ({
|
|||||||
{ key: 'email', label: t('user.login_id'), _style: { width: '20%' } },
|
{ key: 'email', label: t('user.login_id'), _style: { width: '20%' } },
|
||||||
{ key: 'name', label: t('user.name'), _style: { width: '20%' } },
|
{ key: 'name', label: t('user.name'), _style: { width: '20%' } },
|
||||||
{ key: 'userRole', label: t('user.user_role'), _style: { width: '5%' } },
|
{ 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: 'validated', label: t('user.validated'), _style: { width: '5%' } },
|
||||||
{ key: 'lastLogin', label: t('user.last_login'), _style: { width: '20%' } },
|
{ key: 'lastLogin', label: t('user.last_login'), _style: { width: '20%' } },
|
||||||
{
|
{
|
||||||
key: 'user_actions',
|
key: 'user_details',
|
||||||
label: '',
|
label: '',
|
||||||
_style: { width: '5%' },
|
_style: { width: '3%' },
|
||||||
|
sorter: false,
|
||||||
|
filter: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'user_delete',
|
||||||
|
label: '',
|
||||||
|
_style: { width: '3%' },
|
||||||
sorter: false,
|
sorter: false,
|
||||||
filter: false,
|
filter: false,
|
||||||
},
|
},
|
||||||
@@ -68,7 +77,10 @@ const UserListTable = ({
|
|||||||
<CCardHeader>
|
<CCardHeader>
|
||||||
<CRow>
|
<CRow>
|
||||||
<CCol />
|
<CCol />
|
||||||
<CCol xs={1}>
|
<CCol xs={2}>
|
||||||
|
<CRow>
|
||||||
|
<CCol xs={5}>
|
||||||
|
<div className="text-right">
|
||||||
<CSelect
|
<CSelect
|
||||||
custom
|
custom
|
||||||
defaultValue={usersPerPage}
|
defaultValue={usersPerPage}
|
||||||
@@ -79,6 +91,30 @@ const UserListTable = ({
|
|||||||
<option value="25">25</option>
|
<option value="25">25</option>
|
||||||
<option value="50">50</option>
|
<option value="50">50</option>
|
||||||
</CSelect>
|
</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>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
</CCardHeader>
|
</CCardHeader>
|
||||||
@@ -89,23 +125,6 @@ const UserListTable = ({
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
hover
|
hover
|
||||||
border
|
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={{
|
scopedSlots={{
|
||||||
validated: (item) => (
|
validated: (item) => (
|
||||||
<td className="text-center">
|
<td className="text-center">
|
||||||
@@ -120,23 +139,23 @@ const UserListTable = ({
|
|||||||
userRole: (item) => (
|
userRole: (item) => (
|
||||||
<td>{item.userRole ? capitalizeFirstLetter(item.userRole) : ''}</td>
|
<td>{item.userRole ? capitalizeFirstLetter(item.userRole) : ''}</td>
|
||||||
),
|
),
|
||||||
user_actions: (item) => (
|
user_details: (item) => (
|
||||||
<td className="py-2 text-center">
|
<td className="py-2 text-center">
|
||||||
<CRow>
|
<CPopover content={t('common.edit')}>
|
||||||
<CCol>
|
<CButton
|
||||||
<CPopover content={t('configuration.details')}>
|
color="primary"
|
||||||
<CLink
|
variant="outline"
|
||||||
className="c-subheader-nav-link"
|
shape="square"
|
||||||
aria-current="page"
|
size="sm"
|
||||||
to={() => `/users/${item.Id}`}
|
onClick={() => toggleEdit(item.Id)}
|
||||||
>
|
>
|
||||||
<CButton color="primary" variant="outline" shape="square" size="sm">
|
<CIcon name="cil-pencil" content={cilPencil} size="sm" />
|
||||||
<CIcon name="cil-info" content={cilInfo} size="sm" />
|
|
||||||
</CButton>
|
</CButton>
|
||||||
</CLink>
|
|
||||||
</CPopover>
|
</CPopover>
|
||||||
</CCol>
|
</td>
|
||||||
<CCol>
|
),
|
||||||
|
user_delete: (item) => (
|
||||||
|
<td className="py-2 text-center">
|
||||||
<CPopover content={t('common.delete')}>
|
<CPopover content={t('common.delete')}>
|
||||||
<CButton
|
<CButton
|
||||||
onClick={() => handleDeleteClick(item.Id)}
|
onClick={() => handleDeleteClick(item.Id)}
|
||||||
@@ -147,8 +166,6 @@ const UserListTable = ({
|
|||||||
<CIcon content={cilTrash} size="sm" />
|
<CIcon content={cilTrash} size="sm" />
|
||||||
</CButton>
|
</CButton>
|
||||||
</CPopover>
|
</CPopover>
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
</td>
|
</td>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
@@ -196,6 +213,9 @@ UserListTable.propTypes = {
|
|||||||
setPage: PropTypes.func.isRequired,
|
setPage: PropTypes.func.isRequired,
|
||||||
deleteUser: PropTypes.func.isRequired,
|
deleteUser: PropTypes.func.isRequired,
|
||||||
deleteLoading: PropTypes.bool.isRequired,
|
deleteLoading: PropTypes.bool.isRequired,
|
||||||
|
toggleCreate: PropTypes.func.isRequired,
|
||||||
|
toggleEdit: PropTypes.func.isRequired,
|
||||||
|
refreshUsers: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(UserListTable);
|
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) => {
|
(key, newValues) => {
|
||||||
setUser({
|
setUser({
|
||||||
...user,
|
...user,
|
||||||
[user]: {
|
[key]: {
|
||||||
...user[key],
|
...user[key],
|
||||||
...newValues,
|
...newValues,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ export { default as UserListTable } from './components/UserListTable';
|
|||||||
export { default as CreateUserForm } from './components/CreateUserForm';
|
export { default as CreateUserForm } from './components/CreateUserForm';
|
||||||
export { default as LoadingButton } from './components/LoadingButton';
|
export { default as LoadingButton } from './components/LoadingButton';
|
||||||
export { default as ConfirmFooter } from './components/ConfirmFooter';
|
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
|
// Pages
|
||||||
export { default as LoginPage } from './components/LoginPage';
|
export { default as LoginPage } from './components/LoginPage';
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ const Header = ({
|
|||||||
<CHeaderNav className="px-1">
|
<CHeaderNav className="px-1">
|
||||||
<CDropdown inNav className="c-header-nav-items mx-2" direction="down">
|
<CDropdown inNav className="c-header-nav-items mx-2" direction="down">
|
||||||
<CDropdownToggle className="c-header-nav-link" caret={false}>
|
<CDropdownToggle className="c-header-nav-link" caret={false}>
|
||||||
<div className="c-avatar">
|
<div className="c-avatar avatar">
|
||||||
<ImgWithFallback
|
<ImgWithFallback
|
||||||
src={user.avatar && user.avatar !== '' ? user.avatar : '/'}
|
src={user.avatar && user.avatar !== '' ? user.avatar : '/'}
|
||||||
fallback={() => emailToName(user.email)}
|
fallback={() => emailToName(user.email)}
|
||||||
@@ -70,11 +70,11 @@ const Header = ({
|
|||||||
</div>
|
</div>
|
||||||
</CDropdownToggle>
|
</CDropdownToggle>
|
||||||
<CDropdownMenu className="pt-0" placement="bottom-end">
|
<CDropdownMenu className="pt-0" placement="bottom-end">
|
||||||
<CDropdownItem>
|
<CDropdownItem to={() => '/myprofile'}>
|
||||||
<div className="px-3">My Account</div>
|
<div className="px-3">{t('user.my_profile')}</div>
|
||||||
</CDropdownItem>
|
</CDropdownItem>
|
||||||
<CDropdownItem onClick={() => logout(authToken, endpoints.ucentralsec)}>
|
<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} />
|
<CIcon name="cilAccountLogout" content={cilAccountLogout} />
|
||||||
</CDropdownItem>
|
</CDropdownItem>
|
||||||
</CDropdownMenu>
|
</CDropdownMenu>
|
||||||
|
|||||||
Reference in New Issue
Block a user