From 37ce7b08b70f883259a4e30d076f75aa3c63ce38 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 27 Feb 2022 15:26:26 -0500 Subject: [PATCH] Fix users and roles apis --- resources/scripts/api/admin/roles.ts | 103 ++++++++++ .../scripts/api/admin/roles/createRole.ts | 12 -- .../scripts/api/admin/roles/deleteRole.ts | 9 - resources/scripts/api/admin/roles/getRole.ts | 10 - resources/scripts/api/admin/roles/getRoles.ts | 49 ----- .../scripts/api/admin/roles/searchRoles.ts | 24 --- .../scripts/api/admin/roles/updateRole.ts | 12 -- .../scripts/api/admin/servers/getServers.ts | 4 +- resources/scripts/api/admin/user.ts | 16 -- resources/scripts/api/admin/users.ts | 74 +++++++ .../scripts/api/admin/users/createUser.ts | 18 -- .../scripts/api/admin/users/deleteUser.ts | 9 - resources/scripts/api/admin/users/getUser.ts | 10 - resources/scripts/api/admin/users/getUsers.ts | 81 -------- .../scripts/api/admin/users/updateUser.ts | 28 --- .../scripts/api/definitions/admin/models.d.ts | 2 +- .../components/admin/roles/NewRoleButton.tsx | 3 +- .../admin/roles/RoleDeleteButton.tsx | 2 +- .../admin/roles/RoleEditContainer.tsx | 19 +- .../components/admin/roles/RolesContainer.tsx | 2 +- .../components/admin/servers/OwnerSelect.tsx | 2 +- .../admin/users/NewUserContainer.tsx | 4 +- .../components/admin/users/RoleSelect.tsx | 14 +- .../admin/users/UserAboutContainer.tsx | 6 +- .../admin/users/UserDeleteButton.tsx | 2 +- .../components/admin/users/UserForm.tsx | 13 +- .../components/admin/users/UserRouter.tsx | 4 +- .../components/admin/users/UsersContainer.tsx | 183 ------------------ 28 files changed, 217 insertions(+), 498 deletions(-) create mode 100644 resources/scripts/api/admin/roles.ts delete mode 100644 resources/scripts/api/admin/roles/createRole.ts delete mode 100644 resources/scripts/api/admin/roles/deleteRole.ts delete mode 100644 resources/scripts/api/admin/roles/getRole.ts delete mode 100644 resources/scripts/api/admin/roles/getRoles.ts delete mode 100644 resources/scripts/api/admin/roles/searchRoles.ts delete mode 100644 resources/scripts/api/admin/roles/updateRole.ts delete mode 100644 resources/scripts/api/admin/user.ts create mode 100644 resources/scripts/api/admin/users.ts delete mode 100644 resources/scripts/api/admin/users/createUser.ts delete mode 100644 resources/scripts/api/admin/users/deleteUser.ts delete mode 100644 resources/scripts/api/admin/users/getUser.ts delete mode 100644 resources/scripts/api/admin/users/getUsers.ts delete mode 100644 resources/scripts/api/admin/users/updateUser.ts delete mode 100644 resources/scripts/components/admin/users/UsersContainer.tsx diff --git a/resources/scripts/api/admin/roles.ts b/resources/scripts/api/admin/roles.ts new file mode 100644 index 000000000..8fb5c4c85 --- /dev/null +++ b/resources/scripts/api/admin/roles.ts @@ -0,0 +1,103 @@ +import http, { getPaginationSet, PaginatedResult } from '@/api/http'; +import { Transformers, UserRole } from '@definitions/admin'; +import { useContext } from 'react'; +import useSWR from 'swr'; +import { createContext } from '@/api/admin/index'; + +export interface Filters { + id?: string; + name?: string; +} + +export const Context = createContext(); + +const createRole = (name: string, description: string | null, include: string[] = []): Promise => { + return new Promise((resolve, reject) => { + http.post('/api/application/roles', { + name, description, + }, { params: { include: include.join(',') } }) + .then(({ data }) => resolve(Transformers.toUserRole(data))) + .catch(reject); + }); +}; + +const deleteRole = (id: number): Promise => { + return new Promise((resolve, reject) => { + http.delete(`/api/application/roles/${id}`) + .then(() => resolve()) + .catch(reject); + }); +}; + +const getRole = (id: number, include: string[] = []): Promise => { + return new Promise((resolve, reject) => { + http.get(`/api/application/roles/${id}`, { params: { include: include.join(',') } }) + .then(({ data }) => resolve(Transformers.toUserRole(data))) + .catch(reject); + }); +}; + +const searchRoles = (filters?: { name?: string }): Promise => { + const params = {}; + if (filters !== undefined) { + Object.keys(filters).forEach(key => { + // @ts-ignore + params['filter[' + key + ']'] = filters[key]; + }); + } + + return new Promise((resolve, reject) => { + http.get('/api/application/roles', { params }) + .then(response => resolve( + (response.data.data || []).map(Transformers.toUserRole) + )) + .catch(reject); + }); +}; + +const updateRole = (id: number, name: string, description: string | null, include: string[] = []): Promise => { + return new Promise((resolve, reject) => { + http.patch(`/api/application/roles/${id}`, { + name, description, + }, { params: { include: include.join(',') } }) + .then(({ data }) => resolve(Transformers.toUserRole(data))) + .catch(reject); + }); +}; + +const getRoles = (include: string[] = []) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const { page, filters, sort, sortDirection } = useContext(Context); + + const params = {}; + if (filters !== null) { + Object.keys(filters).forEach(key => { + // @ts-ignore + params['filter[' + key + ']'] = filters[key]; + }); + } + + if (sort !== null) { + // @ts-ignore + params.sort = (sortDirection ? '-' : '') + sort; + } + + // eslint-disable-next-line react-hooks/rules-of-hooks + return useSWR>([ 'roles', page, filters, sort, sortDirection ], async () => { + const { data } = await http.get('/api/application/roles', { params: { include: include.join(','), page, ...params } }); + + return ({ + items: (data.data || []).map(Transformers.toUserRole), + pagination: getPaginationSet(data.meta.pagination), + }); + }); +}; + +export { + createRole, + deleteRole, + getRole, + searchRoles, + updateRole, + getRoles, +}; diff --git a/resources/scripts/api/admin/roles/createRole.ts b/resources/scripts/api/admin/roles/createRole.ts deleted file mode 100644 index 7780499bc..000000000 --- a/resources/scripts/api/admin/roles/createRole.ts +++ /dev/null @@ -1,12 +0,0 @@ -import http from '@/api/http'; -import { Role, rawDataToRole } from '@/api/admin/roles/getRoles'; - -export default (name: string, description: string | null, include: string[] = []): Promise => { - return new Promise((resolve, reject) => { - http.post('/api/application/roles', { - name, description, - }, { params: { include: include.join(',') } }) - .then(({ data }) => resolve(rawDataToRole(data))) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/admin/roles/deleteRole.ts b/resources/scripts/api/admin/roles/deleteRole.ts deleted file mode 100644 index 3452791e1..000000000 --- a/resources/scripts/api/admin/roles/deleteRole.ts +++ /dev/null @@ -1,9 +0,0 @@ -import http from '@/api/http'; - -export default (id: number): Promise => { - return new Promise((resolve, reject) => { - http.delete(`/api/application/roles/${id}`) - .then(() => resolve()) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/admin/roles/getRole.ts b/resources/scripts/api/admin/roles/getRole.ts deleted file mode 100644 index 91403ecfa..000000000 --- a/resources/scripts/api/admin/roles/getRole.ts +++ /dev/null @@ -1,10 +0,0 @@ -import http from '@/api/http'; -import { Role, rawDataToRole } from '@/api/admin/roles/getRoles'; - -export default (id: number, include: string[] = []): Promise => { - return new Promise((resolve, reject) => { - http.get(`/api/application/roles/${id}`, { params: { include: include.join(',') } }) - .then(({ data }) => resolve(rawDataToRole(data))) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/admin/roles/getRoles.ts b/resources/scripts/api/admin/roles/getRoles.ts deleted file mode 100644 index c9ceb3def..000000000 --- a/resources/scripts/api/admin/roles/getRoles.ts +++ /dev/null @@ -1,49 +0,0 @@ -import http, { FractalResponseData, getPaginationSet, PaginatedResult } from '@/api/http'; -import { useContext } from 'react'; -import useSWR from 'swr'; -import { createContext } from '@/api/admin'; - -export interface Role { - id: number; - name: string; - description?: string; -} - -export const rawDataToRole = ({ attributes }: FractalResponseData): Role => ({ - id: attributes.id, - name: attributes.name, - description: attributes.description, -}); - -export interface Filters { - id?: string; - name?: string; -} - -export const Context = createContext(); - -export default (include: string[] = []) => { - const { page, filters, sort, sortDirection } = useContext(Context); - - const params = {}; - if (filters !== null) { - Object.keys(filters).forEach(key => { - // @ts-ignore - params['filter[' + key + ']'] = filters[key]; - }); - } - - if (sort !== null) { - // @ts-ignore - params.sort = (sortDirection ? '-' : '') + sort; - } - - return useSWR>([ 'roles', page, filters, sort, sortDirection ], async () => { - const { data } = await http.get('/api/application/roles', { params: { include: include.join(','), page, ...params } }); - - return ({ - items: (data.data || []).map(rawDataToRole), - pagination: getPaginationSet(data.meta.pagination), - }); - }); -}; diff --git a/resources/scripts/api/admin/roles/searchRoles.ts b/resources/scripts/api/admin/roles/searchRoles.ts deleted file mode 100644 index 2e7bf5030..000000000 --- a/resources/scripts/api/admin/roles/searchRoles.ts +++ /dev/null @@ -1,24 +0,0 @@ -import http from '@/api/http'; -import { Role, rawDataToRole } from '@/api/admin/roles/getRoles'; - -interface Filters { - name?: string; -} - -export default (filters?: Filters): Promise => { - const params = {}; - if (filters !== undefined) { - Object.keys(filters).forEach(key => { - // @ts-ignore - params['filter[' + key + ']'] = filters[key]; - }); - } - - return new Promise((resolve, reject) => { - http.get('/api/application/roles', { params }) - .then(response => resolve( - (response.data.data || []).map(rawDataToRole) - )) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/admin/roles/updateRole.ts b/resources/scripts/api/admin/roles/updateRole.ts deleted file mode 100644 index 398859062..000000000 --- a/resources/scripts/api/admin/roles/updateRole.ts +++ /dev/null @@ -1,12 +0,0 @@ -import http from '@/api/http'; -import { Role, rawDataToRole } from '@/api/admin/roles/getRoles'; - -export default (id: number, name: string, description: string | null, include: string[] = []): Promise => { - return new Promise((resolve, reject) => { - http.patch(`/api/application/roles/${id}`, { - name, description, - }, { params: { include: include.join(',') } }) - .then(({ data }) => resolve(rawDataToRole(data))) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/admin/servers/getServers.ts b/resources/scripts/api/admin/servers/getServers.ts index e34e0a566..6d73f070b 100644 --- a/resources/scripts/api/admin/servers/getServers.ts +++ b/resources/scripts/api/admin/servers/getServers.ts @@ -5,7 +5,7 @@ import { createContext } from '@/api/admin'; import http, { FractalResponseData, FractalResponseList, getPaginationSet, PaginatedResult } from '@/api/http'; import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg'; import { Node, rawDataToNode } from '@/api/admin/nodes/getNodes'; -import { User, rawDataToUser } from '@/api/admin/users/getUsers'; +import { Transformers, User } from '@definitions/admin'; export interface ServerVariable { id: number; @@ -132,7 +132,7 @@ export const rawDataToServer = ({ attributes }: FractalResponseData): Server => allocations: ((attributes.relationships?.allocations as FractalResponseList | undefined)?.data || []).map(rawDataToAllocation), egg: attributes.relationships?.egg?.object === 'egg' ? rawDataToEgg(attributes.relationships.egg as FractalResponseData) : undefined, node: attributes.relationships?.node?.object === 'node' ? rawDataToNode(attributes.relationships.node as FractalResponseData) : undefined, - user: attributes.relationships?.user?.object === 'user' ? rawDataToUser(attributes.relationships.user as FractalResponseData) : undefined, + user: attributes.relationships?.user?.object === 'user' ? Transformers.toUser(attributes.relationships.user as FractalResponseData) : undefined, variables: ((attributes.relationships?.variables as FractalResponseList | undefined)?.data || []).map(rawDataToServerVariable), }, }) as Server; diff --git a/resources/scripts/api/admin/user.ts b/resources/scripts/api/admin/user.ts deleted file mode 100644 index 2f70e6a3b..000000000 --- a/resources/scripts/api/admin/user.ts +++ /dev/null @@ -1,16 +0,0 @@ -import http, { QueryBuilderParams, withQueryBuilderParams } from '@/api/http'; -import { Transformers, User } from '@definitions/admin'; - -export const getUser = async (id: string | number): Promise => { - const { data } = await http.get(`/api/application/users/${id}`); - - return Transformers.toUser(data.data); -}; - -export const searchUserAccounts = async (params: QueryBuilderParams<'username' | 'email'>): Promise => { - const { data } = await http.get('/api/application/users', { - params: withQueryBuilderParams(params), - }); - - return data.data.map(Transformers.toUser); -}; diff --git a/resources/scripts/api/admin/users.ts b/resources/scripts/api/admin/users.ts new file mode 100644 index 000000000..6eaa092dd --- /dev/null +++ b/resources/scripts/api/admin/users.ts @@ -0,0 +1,74 @@ +import http, { QueryBuilderParams, withQueryBuilderParams } from '@/api/http'; +import { Transformers, User } from '@definitions/admin'; + +export interface UpdateUserValues { + externalId: string; + username: string; + email: string; + password: string; + adminRoleId: number | null; + rootAdmin: boolean; +} + +const getUser = (id: number, include: string[] = []): Promise => { + return new Promise((resolve, reject) => { + http.get(`/api/application/users/${id}`, { params: { include: include.join(',') } }) + .then(({ data }) => resolve(Transformers.toUser(data))) + .catch(reject); + }); +}; + +const searchUserAccounts = async (params: QueryBuilderParams<'username' | 'email'>): Promise => { + const { data } = await http.get('/api/application/users', { + params: withQueryBuilderParams(params), + }); + + return data.data.map(Transformers.toUser); +}; + +const createUser = (values: UpdateUserValues, include: string[] = []): Promise => { + const data = {}; + Object.keys(values).forEach(k => { + // @ts-ignore + data[k.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`)] = values[k]; + }); + + return new Promise((resolve, reject) => { + http.post('/api/application/users', data, { params: { include: include.join(',') } }) + .then(({ data }) => resolve(Transformers.toUser(data))) + .catch(reject); + }); +}; + +const updateUser = (id: number, values: Partial, include: string[] = []): Promise => { + const data = {}; + Object.keys(values).forEach(k => { + // Don't set password if it is empty. + if (k === 'password' && values[k] === '') { + return; + } + // @ts-ignore + data[k.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`)] = values[k]; + }); + return new Promise((resolve, reject) => { + http.patch(`/api/application/users/${id}`, data, { params: { include: include.join(',') } }) + .then(({ data }) => resolve(Transformers.toUser(data))) + .catch(reject); + }); +}; + +const deleteUser = (id: number): Promise => { + return new Promise((resolve, reject) => { + http.delete(`/api/application/users/${id}`) + .then(() => resolve()) + .catch(reject); + }); +}; + +export { + getUser, + searchUserAccounts, + createUser, + updateUser, + deleteUser, +}; diff --git a/resources/scripts/api/admin/users/createUser.ts b/resources/scripts/api/admin/users/createUser.ts deleted file mode 100644 index fe8588017..000000000 --- a/resources/scripts/api/admin/users/createUser.ts +++ /dev/null @@ -1,18 +0,0 @@ -import http from '@/api/http'; -import { User, rawDataToUser } from '@/api/admin/users/getUsers'; -import { Values } from '@/api/admin/users/updateUser'; - -export type { Values }; - -export default (values: Values, include: string[] = []): Promise => { - const data = {}; - Object.keys(values).forEach(k => { - // @ts-ignore - data[k.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`)] = values[k]; - }); - return new Promise((resolve, reject) => { - http.post('/api/application/users', data, { params: { include: include.join(',') } }) - .then(({ data }) => resolve(rawDataToUser(data))) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/admin/users/deleteUser.ts b/resources/scripts/api/admin/users/deleteUser.ts deleted file mode 100644 index df5b2e545..000000000 --- a/resources/scripts/api/admin/users/deleteUser.ts +++ /dev/null @@ -1,9 +0,0 @@ -import http from '@/api/http'; - -export default (id: number): Promise => { - return new Promise((resolve, reject) => { - http.delete(`/api/application/users/${id}`) - .then(() => resolve()) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/admin/users/getUser.ts b/resources/scripts/api/admin/users/getUser.ts deleted file mode 100644 index db954065e..000000000 --- a/resources/scripts/api/admin/users/getUser.ts +++ /dev/null @@ -1,10 +0,0 @@ -import http from '@/api/http'; -import { User, rawDataToUser } from '@/api/admin/users/getUsers'; - -export default (id: number, include: string[] = []): Promise => { - return new Promise((resolve, reject) => { - http.get(`/api/application/users/${id}`, { params: { include: include.join(',') } }) - .then(({ data }) => resolve(rawDataToUser(data))) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/admin/users/getUsers.ts b/resources/scripts/api/admin/users/getUsers.ts deleted file mode 100644 index 51aaf8489..000000000 --- a/resources/scripts/api/admin/users/getUsers.ts +++ /dev/null @@ -1,81 +0,0 @@ -import http, { FractalResponseData, getPaginationSet, PaginatedResult } from '@/api/http'; -import { useContext } from 'react'; -import useSWR from 'swr'; -import { createContext } from '@/api/admin'; -import { rawDataToDatabase } from '@/api/admin/databases/getDatabases'; -import { Role } from '@/api/admin/roles/getRoles'; - -export interface User { - id: number; - externalId: string; - uuid: string; - username: string; - email: string; - language: string; - adminRoleId: number | null; - rootAdmin: boolean; - tfa: boolean; - avatarURL: string; - roleName: string | null; - createdAt: Date; - updatedAt: Date; - - relationships: { - role: Role | undefined; - }; -} - -export const rawDataToUser = ({ attributes }: FractalResponseData): User => ({ - id: attributes.id, - externalId: attributes.external_id, - uuid: attributes.uuid, - username: attributes.username, - email: attributes.email, - language: attributes.language, - adminRoleId: attributes.admin_role_id, - rootAdmin: attributes.root_admin, - tfa: attributes['2fa'], - avatarURL: attributes.avatar_url, - roleName: attributes.role_name, - createdAt: new Date(attributes.created_at), - updatedAt: new Date(attributes.updated_at), - - relationships: { - role: attributes.relationships?.role !== undefined && attributes.relationships?.role.object !== 'null_resource' ? rawDataToDatabase(attributes.relationships.role as FractalResponseData) : undefined, - }, -}); - -export interface Filters { - id?: string; - uuid?: string; - username?: string; - email?: string; -} - -export const Context = createContext(); - -export default (include: string[] = []) => { - const { page, filters, sort, sortDirection } = useContext(Context); - - const params = {}; - if (filters !== null) { - Object.keys(filters).forEach(key => { - // @ts-ignore - params['filter[' + key + ']'] = filters[key]; - }); - } - - if (sort !== null) { - // @ts-ignore - params.sort = (sortDirection ? '-' : '') + sort; - } - - return useSWR>([ 'users', page, filters, sort, sortDirection ], async () => { - const { data } = await http.get('/api/application/users', { params: { include: include.join(','), page, ...params } }); - - return ({ - items: (data.data || []).map(rawDataToUser), - pagination: getPaginationSet(data.meta.pagination), - }); - }); -}; diff --git a/resources/scripts/api/admin/users/updateUser.ts b/resources/scripts/api/admin/users/updateUser.ts deleted file mode 100644 index 449f7be15..000000000 --- a/resources/scripts/api/admin/users/updateUser.ts +++ /dev/null @@ -1,28 +0,0 @@ -import http from '@/api/http'; -import { User, rawDataToUser } from '@/api/admin/users/getUsers'; - -export interface Values { - externalId: string; - username: string; - email: string; - password: string; - adminRoleId: number | null; - rootAdmin: boolean; -} - -export default (id: number, values: Partial, include: string[] = []): Promise => { - const data = {}; - Object.keys(values).forEach(k => { - // Don't set password if it is empty. - if (k === 'password' && values[k] === '') { - return; - } - // @ts-ignore - data[k.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`)] = values[k]; - }); - return new Promise((resolve, reject) => { - http.patch(`/api/application/users/${id}`, data, { params: { include: include.join(',') } }) - .then(({ data }) => resolve(rawDataToUser(data))) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/definitions/admin/models.d.ts b/resources/scripts/api/definitions/admin/models.d.ts index acdedd5d1..627a448f9 100644 --- a/resources/scripts/api/definitions/admin/models.d.ts +++ b/resources/scripts/api/definitions/admin/models.d.ts @@ -23,7 +23,7 @@ interface User extends ModelWithRelationships { } interface UserRole extends ModelWithRelationships { - id: string; + id: number; name: string; description: string; } diff --git a/resources/scripts/components/admin/roles/NewRoleButton.tsx b/resources/scripts/components/admin/roles/NewRoleButton.tsx index 2d352bed0..e3a9e5d15 100644 --- a/resources/scripts/components/admin/roles/NewRoleButton.tsx +++ b/resources/scripts/components/admin/roles/NewRoleButton.tsx @@ -2,8 +2,7 @@ import { Form, Formik, FormikHelpers } from 'formik'; import React, { useState } from 'react'; import tw from 'twin.macro'; import { object, string } from 'yup'; -import createRole from '@/api/admin/roles/createRole'; -import getRoles from '@/api/admin/roles/getRoles'; +import { getRoles, createRole } from '@/api/admin/roles'; import FlashMessageRender from '@/components/FlashMessageRender'; import Button from '@/components/elements/Button'; import Field from '@/components/elements/Field'; diff --git a/resources/scripts/components/admin/roles/RoleDeleteButton.tsx b/resources/scripts/components/admin/roles/RoleDeleteButton.tsx index 964b0052c..b3b5111bd 100644 --- a/resources/scripts/components/admin/roles/RoleDeleteButton.tsx +++ b/resources/scripts/components/admin/roles/RoleDeleteButton.tsx @@ -1,7 +1,7 @@ import { Actions, useStoreActions } from 'easy-peasy'; import React, { useState } from 'react'; import tw from 'twin.macro'; -import deleteRole from '@/api/admin/roles/deleteRole'; +import { deleteRole } from '@/api/admin/roles'; import Button from '@/components/elements/Button'; import ConfirmationModal from '@/components/elements/ConfirmationModal'; import { ApplicationStore } from '@/state'; diff --git a/resources/scripts/components/admin/roles/RoleEditContainer.tsx b/resources/scripts/components/admin/roles/RoleEditContainer.tsx index 747c9a828..fcc74e685 100644 --- a/resources/scripts/components/admin/roles/RoleEditContainer.tsx +++ b/resources/scripts/components/admin/roles/RoleEditContainer.tsx @@ -5,9 +5,7 @@ import { useHistory } from 'react-router'; import { useRouteMatch } from 'react-router-dom'; import tw from 'twin.macro'; import { object, string } from 'yup'; -import { Role } from '@/api/admin/roles/getRoles'; -import getRole from '@/api/admin/roles/getRole'; -import updateRole from '@/api/admin/roles/updateRole'; +import { getRole, updateRole } from '@/api/admin/roles'; import FlashMessageRender from '@/components/FlashMessageRender'; import AdminBox from '@/components/admin/AdminBox'; import AdminContentBlock from '@/components/admin/AdminContentBlock'; @@ -17,10 +15,11 @@ import Field from '@/components/elements/Field'; import Spinner from '@/components/elements/Spinner'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; import { ApplicationStore } from '@/state'; +import { UserRole } from '@definitions/admin'; interface ctx { - role: Role | undefined; - setRole: Action; + role: UserRole | undefined; + setRole: Action; } export const Context = createContextStore({ @@ -39,7 +38,10 @@ interface Values { const EditInformationContainer = () => { const history = useHistory(); - const { clearFlashes, clearAndAddHttpError } = useStoreActions((actions: Actions) => actions.flashes); + const { + clearFlashes, + clearAndAddHttpError, + } = useStoreActions((actions: Actions) => actions.flashes); const role = Context.useStoreState(state => state.role); const setRole = Context.useStoreActions(actions => actions.setRole); @@ -125,7 +127,10 @@ const EditInformationContainer = () => { const RoleEditContainer = () => { const match = useRouteMatch<{ id?: string }>(); - const { clearFlashes, clearAndAddHttpError } = useStoreActions((actions: Actions) => actions.flashes); + const { + clearFlashes, + clearAndAddHttpError, + } = useStoreActions((actions: Actions) => actions.flashes); const [ loading, setLoading ] = useState(true); const role = Context.useStoreState(state => state.role); diff --git a/resources/scripts/components/admin/roles/RolesContainer.tsx b/resources/scripts/components/admin/roles/RolesContainer.tsx index 5404da22d..75f4dcc74 100644 --- a/resources/scripts/components/admin/roles/RolesContainer.tsx +++ b/resources/scripts/components/admin/roles/RolesContainer.tsx @@ -1,5 +1,5 @@ import React, { useContext, useEffect } from 'react'; -import getRoles, { Context as RolesContext, Filters } from '@/api/admin/roles/getRoles'; +import { getRoles, Context as RolesContext, Filters } from '@/api/admin/roles'; import { AdminContext } from '@/state/admin'; import NewRoleButton from '@/components/admin/roles/NewRoleButton'; import FlashMessageRender from '@/components/FlashMessageRender'; diff --git a/resources/scripts/components/admin/servers/OwnerSelect.tsx b/resources/scripts/components/admin/servers/OwnerSelect.tsx index 022e5b593..a0b5f043c 100644 --- a/resources/scripts/components/admin/servers/OwnerSelect.tsx +++ b/resources/scripts/components/admin/servers/OwnerSelect.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { useFormikContext } from 'formik'; import SearchableSelect, { Option } from '@/components/elements/SearchableSelect'; import { User } from '@definitions/admin'; -import { searchUserAccounts } from '@/api/admin/user'; +import { searchUserAccounts } from '@/api/admin/users'; export default ({ selected }: { selected?: User }) => { const { setFieldValue } = useFormikContext(); diff --git a/resources/scripts/components/admin/users/NewUserContainer.tsx b/resources/scripts/components/admin/users/NewUserContainer.tsx index ffd00c6b3..105d40db4 100644 --- a/resources/scripts/components/admin/users/NewUserContainer.tsx +++ b/resources/scripts/components/admin/users/NewUserContainer.tsx @@ -7,14 +7,14 @@ import { useHistory } from 'react-router-dom'; import { Actions, useStoreActions } from 'easy-peasy'; import { ApplicationStore } from '@/state'; import { FormikHelpers } from 'formik'; -import createUser, { Values } from '@/api/admin/users/createUser'; +import { createUser, UpdateUserValues } from '@/api/admin/users'; export default () => { const history = useHistory(); const { clearFlashes, clearAndAddHttpError } = useStoreActions((actions: Actions) => actions.flashes); - const submit = (values: Values, { setSubmitting }: FormikHelpers) => { + const submit = (values: UpdateUserValues, { setSubmitting }: FormikHelpers) => { clearFlashes('user:create'); createUser(values) diff --git a/resources/scripts/components/admin/users/RoleSelect.tsx b/resources/scripts/components/admin/users/RoleSelect.tsx index 7547945fb..f221de685 100644 --- a/resources/scripts/components/admin/users/RoleSelect.tsx +++ b/resources/scripts/components/admin/users/RoleSelect.tsx @@ -1,14 +1,14 @@ import React, { useState } from 'react'; import { useFormikContext } from 'formik'; -import { Role } from '@/api/admin/roles/getRoles'; -import searchRoles from '@/api/admin/roles/searchRoles'; +import { searchRoles } from '@/api/admin/roles'; import SearchableSelect, { Option } from '@/components/elements/SearchableSelect'; +import { UserRole } from '@definitions/admin'; -export default ({ selected }: { selected: Role | null }) => { +export default ({ selected }: { selected: UserRole | null }) => { const context = useFormikContext(); - const [ role, setRole ] = useState(selected); - const [ roles, setRoles ] = useState(null); + const [ role, setRole ] = useState(selected); + const [ roles, setRoles ] = useState(null); const onSearch = (query: string): Promise => { return new Promise((resolve, reject) => { @@ -21,12 +21,12 @@ export default ({ selected }: { selected: Role | null }) => { }); }; - const onSelect = (role: Role | null) => { + const onSelect = (role: UserRole | null) => { setRole(role); context.setFieldValue('adminRoleId', role?.id || null); }; - const getSelectedText = (role: Role | null): string | undefined => { + const getSelectedText = (role: UserRole | null): string | undefined => { return role?.name; }; diff --git a/resources/scripts/components/admin/users/UserAboutContainer.tsx b/resources/scripts/components/admin/users/UserAboutContainer.tsx index ac186f4da..cd62e20ed 100644 --- a/resources/scripts/components/admin/users/UserAboutContainer.tsx +++ b/resources/scripts/components/admin/users/UserAboutContainer.tsx @@ -1,4 +1,4 @@ -import updateUser, { Values } from '@/api/admin/users/updateUser'; +import { updateUser, UpdateUserValues } from '@/api/admin/users'; import UserDeleteButton from '@/components/admin/users/UserDeleteButton'; import UserForm from '@/components/admin/users/UserForm'; import { Context } from '@/components/admin/users/UserRouter'; @@ -23,7 +23,7 @@ const UserAboutContainer = () => { ); } - const submit = (values: Values, { setSubmitting }: FormikHelpers) => { + const submit = (values: UpdateUserValues, { setSubmitting }: FormikHelpers) => { clearFlashes('user'); updateUser(user.id, values) @@ -44,7 +44,7 @@ const UserAboutContainer = () => { email: user.email, adminRoleId: user.adminRoleId, password: '', - rootAdmin: user.rootAdmin, + rootAdmin: user.isRootAdmin, }} onSubmit={submit} uuid={user.uuid} diff --git a/resources/scripts/components/admin/users/UserDeleteButton.tsx b/resources/scripts/components/admin/users/UserDeleteButton.tsx index f51eca27a..0f38545b5 100644 --- a/resources/scripts/components/admin/users/UserDeleteButton.tsx +++ b/resources/scripts/components/admin/users/UserDeleteButton.tsx @@ -4,7 +4,7 @@ import { ApplicationStore } from '@/state'; import tw from 'twin.macro'; import Button from '@/components/elements/Button'; import ConfirmationModal from '@/components/elements/ConfirmationModal'; -import deleteUser from '@/api/admin/users/deleteUser'; +import { deleteUser } from '@/api/admin/users'; interface Props { userId: number; diff --git a/resources/scripts/components/admin/users/UserForm.tsx b/resources/scripts/components/admin/users/UserForm.tsx index 2a340d7df..629163a6e 100644 --- a/resources/scripts/components/admin/users/UserForm.tsx +++ b/resources/scripts/components/admin/users/UserForm.tsx @@ -5,13 +5,12 @@ import Label from '@/components/elements/Label'; import React from 'react'; import tw from 'twin.macro'; import { action, Action, createContextStore } from 'easy-peasy'; -import { User } from '@/api/admin/users/getUsers'; +import { User, UserRole } from '@definitions/admin'; import AdminBox from '@/components/admin/AdminBox'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; import { Form, Formik, FormikHelpers } from 'formik'; import { bool, object, string } from 'yup'; -import { Role } from '@/api/admin/roles/getRoles'; -import { Values } from '@/api/admin/users/updateUser'; +import { UpdateUserValues } from '@/api/admin/users'; import Button from '@/components/elements/Button'; import Field, { FieldRow } from '@/components/elements/Field'; import RoleSelect from '@/components/admin/users/RoleSelect'; @@ -31,17 +30,17 @@ export const Context = createContextStore({ export interface Params { title: string; - initialValues?: Values; + initialValues?: UpdateUserValues; children?: React.ReactNode; - onSubmit: (values: Values, helpers: FormikHelpers) => void; + onSubmit: (values: UpdateUserValues, helpers: FormikHelpers) => void; uuid?: string; - role: Role | null; + role: UserRole | null; } export default function UserForm ({ title, initialValues, children, onSubmit, uuid, role }: Params) { - const submit = (values: Values, helpers: FormikHelpers) => { + const submit = (values: UpdateUserValues, helpers: FormikHelpers) => { onSubmit(values, helpers); }; diff --git a/resources/scripts/components/admin/users/UserRouter.tsx b/resources/scripts/components/admin/users/UserRouter.tsx index d81c04331..c5228daea 100644 --- a/resources/scripts/components/admin/users/UserRouter.tsx +++ b/resources/scripts/components/admin/users/UserRouter.tsx @@ -4,14 +4,14 @@ import { useLocation } from 'react-router'; import tw from 'twin.macro'; import { Route, Switch, useRouteMatch } from 'react-router-dom'; import { action, Action, Actions, createContextStore, useStoreActions } from 'easy-peasy'; -import { User } from '@/api/admin/users/getUsers'; -import getUser from '@/api/admin/users/getUser'; +import { getUser } from '@/api/admin/users'; import AdminContentBlock from '@/components/admin/AdminContentBlock'; import Spinner from '@/components/elements/Spinner'; import FlashMessageRender from '@/components/FlashMessageRender'; import { ApplicationStore } from '@/state'; import { SubNavigation, SubNavigationLink } from '@/components/admin/SubNavigation'; import UserServers from '@/components/admin/users/UserServers'; +import { User } from '@definitions/admin'; interface ctx { user: User | undefined; diff --git a/resources/scripts/components/admin/users/UsersContainer.tsx b/resources/scripts/components/admin/users/UsersContainer.tsx deleted file mode 100644 index 533219bb7..000000000 --- a/resources/scripts/components/admin/users/UsersContainer.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import React, { useContext, useEffect } from 'react'; -import AdminCheckbox from '@/components/admin/AdminCheckbox'; -import CopyOnClick from '@/components/elements/CopyOnClick'; -import getUsers, { Context as UsersContext, Filters } from '@/api/admin/users/getUsers'; -import AdminTable, { TableBody, TableHead, TableHeader, Pagination, Loading, NoItems, ContentWrapper, useTableHooks } from '@/components/admin/AdminTable'; -import Button from '@/components/elements/Button'; -import FlashMessageRender from '@/components/FlashMessageRender'; -import useFlash from '@/plugins/useFlash'; -import { AdminContext } from '@/state/admin'; -import { NavLink, useRouteMatch } from 'react-router-dom'; -import tw from 'twin.macro'; -import AdminContentBlock from '@/components/admin/AdminContentBlock'; - -const RowCheckbox = ({ id }: { id: number }) => { - const isChecked = AdminContext.useStoreState(state => state.users.selectedUsers.indexOf(id) >= 0); - const appendSelectedUser = AdminContext.useStoreActions(actions => actions.users.appendSelectedUser); - const removeSelectedUser = AdminContext.useStoreActions(actions => actions.users.removeSelectedUser); - - return ( - ) => { - if (e.currentTarget.checked) { - appendSelectedUser(id); - } else { - removeSelectedUser(id); - } - }} - /> - ); -}; - -const UsersContainer = () => { - const match = useRouteMatch(); - - const { page, setPage, setFilters, sort, setSort, sortDirection } = useContext(UsersContext); - const { clearFlashes, clearAndAddHttpError } = useFlash(); - const { data: users, error, isValidating } = getUsers(); - - useEffect(() => { - if (!error) { - clearFlashes('users'); - return; - } - - clearAndAddHttpError({ key: 'users', error }); - }, [ error ]); - - const length = users?.items?.length || 0; - - const setSelectedUsers = AdminContext.useStoreActions(actions => actions.users.setSelectedUsers); - const selectedUserLength = AdminContext.useStoreState(state => state.users.selectedUsers.length); - - const onSelectAllClick = (e: React.ChangeEvent) => { - setSelectedUsers(e.currentTarget.checked ? (users?.items?.map(user => user.id) || []) : []); - }; - - const onSearch = (query: string): Promise => { - return new Promise((resolve) => { - if (query.length < 2) { - setFilters(null); - } else { - setFilters({ username: query }); - } - return resolve(); - }); - }; - - useEffect(() => { - setSelectedUsers([]); - }, [ page ]); - - return ( - -
-
-

Users

-

All registered users on the system.

-
- -
- - - -
-
- - - - - - -
- - - setSort('id')}/> - setSort('email')}/> - setSort('username')}/> - - setSort('admin_role_id')}/> - - - - { users !== undefined && !error && !isValidating && length > 0 && - users.items.map(user => ( - - - - - - - - - - - - - - )) - } - -
- - - - {user.id} - - - -
-
- -
- -
-
- {user.email} -
- -
- {user.uuid.split('-')[0]} -
-
-
-
-
{user.username} - - Active - - {user.roleName || 'None'}
- - { users === undefined || (error && isValidating) ? - - : - length < 1 ? - - : - null - } -
-
-
-
-
- ); -}; - -export default () => { - const hooks = useTableHooks(); - - return ( - - - - ); -};