ui(admin): add role select for user management
This commit is contained in:
parent
58f0bbbb9b
commit
25feeaa9f5
16 changed files with 202 additions and 52 deletions
|
@ -12,10 +12,12 @@ export default ({ selected }: { selected: Database | null }) => {
|
|||
|
||||
const onSearch = (query: string): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
searchDatabases({ name: query }).then((databases) => {
|
||||
setDatabases(databases);
|
||||
return resolve();
|
||||
}).catch(reject);
|
||||
searchDatabases({ name: query })
|
||||
.then(databases => {
|
||||
setDatabases(databases);
|
||||
return resolve();
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -24,14 +26,16 @@ export default ({ selected }: { selected: Database | null }) => {
|
|||
context.setFieldValue('databaseHostId', database?.id || null);
|
||||
};
|
||||
|
||||
const getSelectedText = (database: Database | null): string => {
|
||||
return database?.name || '';
|
||||
const getSelectedText = (database: Database | null): string | undefined => {
|
||||
return database?.name;
|
||||
};
|
||||
|
||||
return (
|
||||
<SearchableSelect
|
||||
id="database"
|
||||
name="Database"
|
||||
id={'databaseId'}
|
||||
name={'databaseId'}
|
||||
label={'Database'}
|
||||
placeholder={'Select a database...'}
|
||||
items={databases}
|
||||
selected={database}
|
||||
setSelected={setDatabase}
|
||||
|
@ -42,7 +46,7 @@ export default ({ selected }: { selected: Database | null }) => {
|
|||
nullable
|
||||
>
|
||||
{databases?.map(d => (
|
||||
<Option key={d.id} selectId="database" id={d.id} item={d} active={d.id === database?.id}>
|
||||
<Option key={d.id} selectId={'databaseId'} id={d.id} item={d} active={d.id === database?.id}>
|
||||
{d.name}
|
||||
</Option>
|
||||
))}
|
||||
|
|
|
@ -12,10 +12,12 @@ export default ({ selected }: { selected: Location | null }) => {
|
|||
|
||||
const onSearch = (query: string): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
searchLocations({ short: query }).then((locations) => {
|
||||
setLocations(locations);
|
||||
return resolve();
|
||||
}).catch(reject);
|
||||
searchLocations({ short: query })
|
||||
.then(locations => {
|
||||
setLocations(locations);
|
||||
return resolve();
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -24,14 +26,16 @@ export default ({ selected }: { selected: Location | null }) => {
|
|||
context.setFieldValue('locationId', location?.id || null);
|
||||
};
|
||||
|
||||
const getSelectedText = (location: Location | null): string => {
|
||||
return location?.short || '';
|
||||
const getSelectedText = (location: Location | null): string | undefined => {
|
||||
return location?.short;
|
||||
};
|
||||
|
||||
return (
|
||||
<SearchableSelect
|
||||
id="location"
|
||||
name="Location"
|
||||
id={'locationId'}
|
||||
name={'locationId'}
|
||||
label={'Location'}
|
||||
placeholder={'Select a location...'}
|
||||
items={locations}
|
||||
selected={location}
|
||||
setSelected={setLocation}
|
||||
|
@ -42,7 +46,7 @@ export default ({ selected }: { selected: Location | null }) => {
|
|||
nullable
|
||||
>
|
||||
{locations?.map(d => (
|
||||
<Option key={d.id} selectId="location" id={d.id} item={d} active={d.id === location?.id}>
|
||||
<Option key={d.id} selectId={'locationId'} id={d.id} item={d} active={d.id === location?.id}>
|
||||
{d.short}
|
||||
</Option>
|
||||
))}
|
||||
|
|
|
@ -30,8 +30,10 @@ export default ({ selected }: { selected: User | null }) => {
|
|||
|
||||
return (
|
||||
<SearchableSelect
|
||||
id="user"
|
||||
name="Owner"
|
||||
id={'ownerId'}
|
||||
name={'ownerId'}
|
||||
label={'Owner'}
|
||||
placeholder={'Select a user...'}
|
||||
items={users}
|
||||
selected={user}
|
||||
setSelected={setUser}
|
||||
|
@ -42,7 +44,7 @@ export default ({ selected }: { selected: User | null }) => {
|
|||
nullable
|
||||
>
|
||||
{users?.map(d => (
|
||||
<Option key={d.id} selectId="user" id={d.id} item={d} active={d.id === user?.id}>
|
||||
<Option key={d.id} selectId={'ownerId'} id={d.id} item={d} active={d.id === user?.id}>
|
||||
{d.username}
|
||||
</Option>
|
||||
))}
|
||||
|
|
|
@ -37,7 +37,7 @@ export default () => {
|
|||
|
||||
<FlashMessageRender byKey={'user:create'} css={tw`mb-4`}/>
|
||||
|
||||
<InformationContainer title={'Create User'} onSubmit={submit}/>
|
||||
<InformationContainer title={'Create User'} onSubmit={submit} role={null}/>
|
||||
</AdminContentBlock>
|
||||
);
|
||||
};
|
||||
|
|
55
resources/scripts/components/admin/users/RoleSelect.tsx
Normal file
55
resources/scripts/components/admin/users/RoleSelect.tsx
Normal file
|
@ -0,0 +1,55 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { Role } from '@/api/admin/roles/getRoles';
|
||||
import searchRoles from '@/api/admin/roles/searchRoles';
|
||||
import SearchableSelect, { Option } from '@/components/elements/SearchableSelect';
|
||||
|
||||
export default ({ selected }: { selected: Role | null }) => {
|
||||
const context = useFormikContext();
|
||||
|
||||
const [ role, setRole ] = useState<Role | null>(selected);
|
||||
const [ roles, setRoles ] = useState<Role[] | null>(null);
|
||||
|
||||
const onSearch = (query: string): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
searchRoles({ name: query })
|
||||
.then(roles => {
|
||||
setRoles(roles);
|
||||
return resolve();
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
const onSelect = (role: Role | null) => {
|
||||
setRole(role);
|
||||
context.setFieldValue('adminRoleId', role?.id || null);
|
||||
};
|
||||
|
||||
const getSelectedText = (role: Role | null): string | undefined => {
|
||||
return role?.name;
|
||||
};
|
||||
|
||||
return (
|
||||
<SearchableSelect
|
||||
id={'adminRoleId'}
|
||||
name={'adminRoleId'}
|
||||
label={'Role'}
|
||||
placeholder={'Select a role...'}
|
||||
items={roles}
|
||||
selected={role}
|
||||
setSelected={setRole}
|
||||
setItems={setRoles}
|
||||
onSearch={onSearch}
|
||||
onSelect={onSelect}
|
||||
getSelectedText={getSelectedText}
|
||||
nullable
|
||||
>
|
||||
{roles?.map(d => (
|
||||
<Option key={d.id} selectId={'adminRoleId'} id={d.id} item={d} active={d.id === role?.id}>
|
||||
{d.name}
|
||||
</Option>
|
||||
))}
|
||||
</SearchableSelect>
|
||||
);
|
||||
};
|
|
@ -12,9 +12,11 @@ import AdminBox from '@/components/admin/AdminBox';
|
|||
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
|
||||
import { Form, Formik, FormikHelpers } from 'formik';
|
||||
import { object, string } from 'yup';
|
||||
import Field from '@/components/elements/Field';
|
||||
import Button from '@/components/elements/Button';
|
||||
import { Role } from '@/api/admin/roles/getRoles';
|
||||
import updateUser, { Values } from '@/api/admin/users/updateUser';
|
||||
import Button from '@/components/elements/Button';
|
||||
import Field from '@/components/elements/Field';
|
||||
import RoleSelect from '@/components/admin/users/RoleSelect';
|
||||
import UserDeleteButton from '@/components/admin/users/UserDeleteButton';
|
||||
|
||||
interface ctx {
|
||||
|
@ -37,9 +39,11 @@ export interface Params {
|
|||
|
||||
onSubmit: (values: Values, helpers: FormikHelpers<Values>) => void;
|
||||
exists?: boolean;
|
||||
|
||||
role: Role | null;
|
||||
}
|
||||
|
||||
export function InformationContainer ({ title, initialValues, children, onSubmit, exists }: Params) {
|
||||
export function InformationContainer ({ title, initialValues, children, onSubmit, exists, role }: Params) {
|
||||
const submit = (values: Values, helpers: FormikHelpers<Values>) => {
|
||||
onSubmit(values, helpers);
|
||||
};
|
||||
|
@ -51,7 +55,7 @@ export function InformationContainer ({ title, initialValues, children, onSubmit
|
|||
firstName: '',
|
||||
lastName: '',
|
||||
password: '',
|
||||
roleId: 0,
|
||||
adminRoleId: 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -126,7 +130,9 @@ export function InformationContainer ({ title, initialValues, children, onSubmit
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div css={tw`md:w-full md:flex md:flex-col md:ml-4 mt-6 md:mt-0`}/>
|
||||
<div css={tw`md:w-full md:flex md:flex-col md:ml-4 mt-6 md:mt-0`}>
|
||||
<RoleSelect selected={role}/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div css={tw`w-full flex flex-row items-center mt-6`}>
|
||||
|
@ -180,10 +186,11 @@ function EditInformationContainer () {
|
|||
email: user.email,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
roleId: user.roleId,
|
||||
adminRoleId: user.adminRoleId,
|
||||
password: '',
|
||||
}}
|
||||
onSubmit={submit}
|
||||
role={user?.relationships.role || null}
|
||||
exists
|
||||
>
|
||||
<div css={tw`flex`}>
|
||||
|
@ -208,7 +215,7 @@ function UserEditContainer () {
|
|||
useEffect(() => {
|
||||
clearFlashes('user');
|
||||
|
||||
getUser(Number(match.params?.id))
|
||||
getUser(Number(match.params?.id), [ 'role' ])
|
||||
.then(user => setUser(user))
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue