From b8053cf063c7ab183ef39e7366183ad35c79829c Mon Sep 17 00:00:00 2001 From: tahaKhanAbdalli Date: Wed, 20 Dec 2023 14:00:35 +0500 Subject: [PATCH 01/11] inactiver user token expire after 1 hour --- package.json | 1 + src/App.tsx | 15 ++++++++++++++- yarn.lock | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c524910..e13eb17a 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "react": "^18.2.0", "react-admin": "4.13.1", "react-dom": "^18.2.0", + "react-idle-timer": "^5.7.2", "react-router-dom": "^6.9.0", "soul-cli": "^0.6.1", "vite": "^4.2.0", diff --git a/src/App.tsx b/src/App.tsx index 0d1d4f14..bfce8e81 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,7 +16,7 @@ import { VisibilityOff } from '@mui/icons-material' import { getDataProvider } from './providers/dataProvider' -import rcoAuthProvider from './providers/authProvider' +import rcoAuthProvider, { removeToken } from './providers/authProvider' import { useForm } from 'react-hook-form' import * as yup from 'yup' @@ -71,6 +71,7 @@ import { type AxiosError, isAxiosError } from 'axios' import ChangePassword from './ChangePassword' import { emitter } from './components/Layout/index' import { CHANGE_PASSWORD_EVENT } from './constants' +import { useIdleTimer } from 'react-idle-timer' const style = { backgroundColor: 'white', @@ -115,6 +116,18 @@ function App(): React.ReactElement { }) const [openChangePasswordModal, setOpenChangePasswordModal] = useState(false) + const handleOnIdle = () => { + return removeToken() + } + const handleOnAction = () => { + reset() + } + const { reset } = useIdleTimer({ + timeout: 1000 * 60 * 60, + onIdle: handleOnIdle, + onActive: handleOnAction + }) + const { register, handleSubmit, diff --git a/yarn.lock b/yarn.lock index 6545f5e4..eb7e5267 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6705,6 +6705,11 @@ react-hook-form@^7.43.9: resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.45.4.tgz#73d228b704026ae95d7e5f7b207a681b173ec62a" integrity sha512-HGDV1JOOBPZj10LB3+OZgfDBTn+IeEsNOKiq/cxbQAIbKaiJUe/KV8DBUzsx0Gx/7IG/orWqRRm736JwOfUSWQ== +react-idle-timer@^5.7.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/react-idle-timer/-/react-idle-timer-5.7.2.tgz#f506db28a86645dd1b87987116501703e512142b" + integrity sha512-+BaPfc7XEUU5JFkwZCx6fO1bLVK+RBlFH+iY4X34urvIzZiZINP6v2orePx3E6pAztJGE7t4DzvL7if2SL/0GQ== + react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" From 7d67f02012da8f16d15ad4827a4d8a660690cebc Mon Sep 17 00:00:00 2001 From: tahaKhanAbdalli Date: Wed, 20 Dec 2023 14:15:54 +0500 Subject: [PATCH 02/11] lint issues resolved --- src/App.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index bfce8e81..7ca1e0e7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -116,10 +116,10 @@ function App(): React.ReactElement { }) const [openChangePasswordModal, setOpenChangePasswordModal] = useState(false) - const handleOnIdle = () => { - return removeToken() + const handleOnIdle = (): void => { + removeToken() } - const handleOnAction = () => { + const handleOnAction = (): void => { reset() } const { reset } = useIdleTimer({ From 0293f2cbc3fb36308db4d6a15fd5bdd7d845073f Mon Sep 17 00:00:00 2001 From: tahaKhanAbdalli Date: Wed, 20 Dec 2023 16:18:35 +0500 Subject: [PATCH 03/11] udpate expiry time from 1hr to 1day --- src/providers/authProvider/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/providers/authProvider/index.ts b/src/providers/authProvider/index.ts index 697180fd..a424ac14 100644 --- a/src/providers/authProvider/index.ts +++ b/src/providers/authProvider/index.ts @@ -39,7 +39,7 @@ const getCookie = (name: string): string | null => { const setToken = (token: string): void => { const date = new Date() - date.setTime(date.getTime() + 1 * 60 * 60 * 1000) + date.setTime(date.getTime() + 24 * 60 * 60 * 1000) const expires = date.toUTCString() document.cookie = `${constants.TOKEN_KEY}=${token}; expires=${expires}; path=/ ` } From 854bda8a89d9f3a2cc16b4c88256bdd073b713c0 Mon Sep 17 00:00:00 2001 From: tahaKhanAbdalli Date: Tue, 16 Jan 2024 18:45:38 +0500 Subject: [PATCH 04/11] password reset sould clear the min password age issue resolved --- src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 0d1d4f14..0c098028 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -194,7 +194,7 @@ function App(): React.ReactElement { if ( lastUpdatedAt !== null && lastUpdatedAt !== '' && - !isDateNotInPastDays(lastUpdatedAt, 1) + !isDateNotInPastDays(lastUpdatedAt, 0) ) throw new Error( 'Password update not allowed. Please wait at least one day before updating your password again.' From fe5372702234db33998191dcf208f0faaa3f5c00 Mon Sep 17 00:00:00 2001 From: tahaKhanAbdalli Date: Tue, 16 Jan 2024 19:01:53 +0500 Subject: [PATCH 05/11] lint issues resolved --- src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 0c098028..8ab530cf 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -192,7 +192,7 @@ function App(): React.ReactElement { }) if ( - lastUpdatedAt !== null && + typeof lastUpdatedAt === 'string' && lastUpdatedAt !== '' && !isDateNotInPastDays(lastUpdatedAt, 0) ) From 00eeae3c398dbae8e5b38c2642b91493daa92e8e Mon Sep 17 00:00:00 2001 From: tahaKhanAbdalli Date: Wed, 17 Jan 2024 17:11:22 +0500 Subject: [PATCH 06/11] edit item code, cave, handle working correctly now. --- src/providers/dataProvider/index.ts | 45 +++++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/providers/dataProvider/index.ts b/src/providers/dataProvider/index.ts index a5358064..bf48cd8b 100644 --- a/src/providers/dataProvider/index.ts +++ b/src/providers/dataProvider/index.ts @@ -326,24 +326,37 @@ export const dataProvider = (apiUrl: string): DataProvider => ({ }, // Note: Deletion is not supported - delete: async (_resource: string, _params: any) => { - throw new Error('Deletion is not supported!') - // const url = `${apiUrl}/${resource}/rows/${params.id}` - - // return await axios.delete(url).then(() => { - // return { data: params.id } - // }) + delete: async (resource: string, params: any) => { + if ( + [ + constants.R_ITEMS_CODE, + constants.R_ITEMS_CAVE, + constants.R_ITEMS_HANDLE + ].includes(resource) + ) { + const url = `${apiUrl}/${resource}/rows/${params.id}` + return await axios.delete(url).then(() => ({ data: params.id })) + } else { + throw new Error('Deletion is not supported!') + } }, // Note: Deletion is not supported - deleteMany: async (_resource: string, _params: any) => { - throw new Error('Deletion is not supported!') - - // const ids = params.ids.toString() - // const url = `${apiUrl}/${resource}/rows/${ids}` - - // return await axios.delete(url).then(() => { - // return { data: params.ids } - // }) + deleteMany: async (resource: string, params: any) => { + if ( + [ + constants.R_ITEMS_CODE, + constants.R_ITEMS_CAVE, + constants.R_ITEMS_HANDLE + ].includes(resource) + ) { + const ids = params.ids.toString() + const url = `${apiUrl}/${resource}/rows/${ids}` + return await axios.delete(url).then(() => { + return { data: params.ids } + }) + } else { + throw new Error('Deletion is not supported!') + } } }) From c56094b323bf7dbf2fb557e2d27c64c41e2b8674 Mon Sep 17 00:00:00 2001 From: Ian Mayo Date: Wed, 17 Jan 2024 12:27:31 +0000 Subject: [PATCH 07/11] refactoring --- src/providers/dataProvider/index.ts | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/providers/dataProvider/index.ts b/src/providers/dataProvider/index.ts index bf48cd8b..95576b89 100644 --- a/src/providers/dataProvider/index.ts +++ b/src/providers/dataProvider/index.ts @@ -90,6 +90,11 @@ export const getDataProvider = async ( const operators = ['_neq', '_eq', '_lte', '_gte'] const SEARCH_OPERATOR = 'q' const nullOperators = ['__null', '__notnull'] +const bridgingTables = [ + constants.R_ITEMS_CODE, + constants.R_ITEMS_CAVE, + constants.R_ITEMS_HANDLE +] export const dataProvider = (apiUrl: string): DataProvider => ({ getList: async (resource: string, params: any) => { @@ -325,15 +330,9 @@ export const dataProvider = (apiUrl: string): DataProvider => ({ }) }, - // Note: Deletion is not supported + // Note: Deletion is not supported (except for bridging tables) delete: async (resource: string, params: any) => { - if ( - [ - constants.R_ITEMS_CODE, - constants.R_ITEMS_CAVE, - constants.R_ITEMS_HANDLE - ].includes(resource) - ) { + if (bridgingTables.includes(resource)) { const url = `${apiUrl}/${resource}/rows/${params.id}` return await axios.delete(url).then(() => ({ data: params.id })) } else { @@ -341,15 +340,9 @@ export const dataProvider = (apiUrl: string): DataProvider => ({ } }, - // Note: Deletion is not supported + // Note: Deletion is not supported (except for bridging tables) deleteMany: async (resource: string, params: any) => { - if ( - [ - constants.R_ITEMS_CODE, - constants.R_ITEMS_CAVE, - constants.R_ITEMS_HANDLE - ].includes(resource) - ) { + if (bridgingTables.includes(resource)) { const ids = params.ids.toString() const url = `${apiUrl}/${resource}/rows/${ids}` return await axios.delete(url).then(() => { From 81f916e8715ce31637d7feee9db567be915e450e Mon Sep 17 00:00:00 2001 From: tahaKhanAbdalli Date: Thu, 18 Jan 2024 17:11:48 +0500 Subject: [PATCH 08/11] now the correct values of code/cave/handle show without refreshing the page. --- src/components/ProtectionRefInput.tsx | 10 ++- src/hooks/useRefTable.ts | 64 +++++++++++-------- .../items/ItemForm/ItemFormToolbar.tsx | 3 +- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/src/components/ProtectionRefInput.tsx b/src/components/ProtectionRefInput.tsx index fee43902..2bcac0d2 100644 --- a/src/components/ProtectionRefInput.tsx +++ b/src/components/ProtectionRefInput.tsx @@ -17,9 +17,11 @@ import { useGetList, useRecordContext, useResourceContext, - type Identifier + type Identifier, + useRedirect } from 'react-admin' import { Box } from '@mui/system' +import { R_RICH_ITEMS } from '../constants' interface Props { reference: string @@ -66,6 +68,8 @@ export default function ProtectionRefInput< getValues, reset } = useFormContext() + const redirect = useRedirect() + const [valueLabel, setValueLabel] = useState('') type SelectedIdType = T['id'] | Array @@ -163,6 +167,10 @@ export default function ProtectionRefInput< if (record?.id) { // onValueChange(getPreviousValue()) updateRecord(record.id as number, selectedData as number[]) + .then(() => { + redirect(`/${R_RICH_ITEMS}/${record?.id}/show`) + }) + .catch(console.log) } else if (id) { createRecord(id, selectedData as number[]) } diff --git a/src/hooks/useRefTable.ts b/src/hooks/useRefTable.ts index 7a3366e4..ad5f8d52 100644 --- a/src/hooks/useRefTable.ts +++ b/src/hooks/useRefTable.ts @@ -1,14 +1,14 @@ import { useCreate, useDataProvider, - // useDeleteMany, useRedirect + // useDeleteMany, } from 'react-admin' -import { R_ITEMS } from '../constants' +import * as constants from '../constants' interface DBMethods { createRecord: (id: number, data?: number[]) => void - updateRecord: (id: number, data?: number[]) => void + updateRecord: (id: number, data?: number[]) => Promise } export default function useRefTable( @@ -18,31 +18,43 @@ export default function useRefTable( ): DBMethods { const [create] = useCreate() // const [deleteMany] = useDeleteMany() - const redirect = useRedirect() const dataProvider = useDataProvider() + const redirect = useRedirect() - const updateRecord = (id: number, data?: number[]): void => { - dataProvider - .getList(refTable, { - pagination: { page: 1, perPage: 100 }, - sort: { field: 'id', order: 'ASC' }, - filter: { [resource]: id } - }) - .then(({ data: tableData = [] }) => { - const idsToDelete = tableData.map( - (item: Record) => item.id - ) - - if (idsToDelete.length > 0) - {dataProvider.deleteMany(refTable, { ids: idsToDelete }) - .then(() => { + const updateRecord = async ( + id: number, + data?: number[] + ): Promise => { + return await new Promise((resolve, reject): void => { + dataProvider + .getList(refTable, { + pagination: { page: 1, perPage: 100 }, + sort: { field: 'id', order: 'ASC' }, + filter: { [resource]: id } + }) + .then(({ data: tableData = [] }) => { + const idsToDelete = tableData.map( + (item: Record) => item.id + ) + if (idsToDelete.length > 0) { + dataProvider + .deleteMany(refTable, { ids: idsToDelete }) + .then(() => { + createRecord(id, data) + resolve(null) + }) + .catch((err) => { + reject(err) + }) + } else { createRecord(id, data) - }) - .catch(console.log) - } - else createRecord(id, data) - }) - .catch(console.log) + resolve(null) + } + }) + .catch((err) => { + reject(err) + }) + }) } const createRecord = (id: number, data?: number[]): void => { @@ -55,7 +67,7 @@ export default function useRefTable( } }) }) - if (resource !== R_ITEMS) redirect(`/${resource}`) + if (resource !== constants.R_ITEMS) redirect(`/${resource}`) } catch (error: any) { console.log(error) } diff --git a/src/resources/items/ItemForm/ItemFormToolbar.tsx b/src/resources/items/ItemForm/ItemFormToolbar.tsx index ebb0aed0..34eb2394 100644 --- a/src/resources/items/ItemForm/ItemFormToolbar.tsx +++ b/src/resources/items/ItemForm/ItemFormToolbar.tsx @@ -37,11 +37,10 @@ interface ActionsProps { const Actions = (props: ActionsProps): React.ReactElement => { const { onSuccess, setOpenRemarks, vLocationAudits } = props - const redirect = useRedirect() + const onSuccessWithRemarksClose = (data: any): void => { onSuccess(data) setOpenRemarks(false) - redirect(`/${constants.R_RICH_ITEMS}/${data?.id}/show`) } return ( From 4948681791a918bb0b239d3ed49666583f114255 Mon Sep 17 00:00:00 2001 From: Ian Mayo Date: Thu, 18 Jan 2024 13:11:59 +0000 Subject: [PATCH 09/11] remove unused code --- src/hooks/useRefTable.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/hooks/useRefTable.ts b/src/hooks/useRefTable.ts index ad5f8d52..5f105414 100644 --- a/src/hooks/useRefTable.ts +++ b/src/hooks/useRefTable.ts @@ -1,9 +1,4 @@ -import { - useCreate, - useDataProvider, - useRedirect - // useDeleteMany, -} from 'react-admin' +import { useCreate, useDataProvider, useRedirect } from 'react-admin' import * as constants from '../constants' interface DBMethods { @@ -17,7 +12,6 @@ export default function useRefTable( resource: string ): DBMethods { const [create] = useCreate() - // const [deleteMany] = useDeleteMany() const dataProvider = useDataProvider() const redirect = useRedirect() From 82cf10f01723c04ea052f5adbe2d44f21c8461cb Mon Sep 17 00:00:00 2001 From: tahaKhanAbdalli Date: Thu, 18 Jan 2024 19:00:11 +0500 Subject: [PATCH 10/11] rco-user not able to edit any user profile --- src/providers/authProvider/permissions.ts | 3 ++- src/resources/users/UserShow.tsx | 32 +++++++++++------------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/providers/authProvider/permissions.ts b/src/providers/authProvider/permissions.ts index 9389ea4e..6298b9cf 100644 --- a/src/providers/authProvider/permissions.ts +++ b/src/providers/authProvider/permissions.ts @@ -5,7 +5,7 @@ const basePermissions = { [constants.R_BATCHES]: { read: true, write: true, delete: false }, [constants.R_ITEMS]: { read: true, write: true, delete: false }, [constants.R_ALL_ITEMS]: { read: true, write: true, delete: false }, - [constants.R_USERS]: { read: true, write: true, delete: false }, + [constants.R_USERS]: { read: true, write: false, delete: false }, [constants.R_PLATFORMS]: { read: true, write: false, delete: false }, [constants.R_VAULT_LOCATION]: { read: true, write: false, delete: false }, [constants.R_ADDRESSES]: { read: true, write: true, delete: false }, @@ -20,6 +20,7 @@ const permissions: Record = { 'rco-power-user': { ...basePermissions, [constants.R_PLATFORMS]: { read: true, write: true, delete: false }, + [constants.R_USERS]: { read: true, write: true, delete: false }, [constants.R_VAULT_LOCATION]: { read: true, write: true, delete: false }, 'reference-data': { read: true, write: true, delete: false } } diff --git a/src/resources/users/UserShow.tsx b/src/resources/users/UserShow.tsx index 65195ee7..bb8f8e75 100644 --- a/src/resources/users/UserShow.tsx +++ b/src/resources/users/UserShow.tsx @@ -375,23 +375,21 @@ export default function UserShow(): React.ReactElement { - - { - if (record) { - navigate( - `/audit?filter=${JSON.stringify({ - resource: constants.R_USERS, - dataId: record.id ?? '' - })}` - ) - } - }} - /> - - ) + + {hasWriteAccess && } + { + if (record) { + navigate( + `/audit?filter=${JSON.stringify({ + resource: constants.R_USERS, + dataId: record.id ?? '' + })}` + ) + } + }} + /> + }> From 3df9ce81298452d3beccfee43cf8c1815e576ceb Mon Sep 17 00:00:00 2001 From: Ian Mayo Date: Tue, 23 Jan 2024 12:37:55 +0000 Subject: [PATCH 11/11] hotfix - change label for `Manage addresses` --- src/resources/dispatch/DispatchForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resources/dispatch/DispatchForm.tsx b/src/resources/dispatch/DispatchForm.tsx index d6c7b02c..38752623 100644 --- a/src/resources/dispatch/DispatchForm.tsx +++ b/src/resources/dispatch/DispatchForm.tsx @@ -77,7 +77,7 @@ export default function DispatchForm(props: Props): React.ReactElement { inputProps={{ helperText: ( <> - View{' '} + Manage{' '} Addresses