From 42a0ae9e59437f3ab37d8c9fe758454b09a8bc56 Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Fri, 8 Dec 2023 14:54:22 -0500 Subject: [PATCH 01/11] feature/3 create Dashboard page and Uploads table, add mock data for uploads array --- web/src/Routes.tsx | 1 + web/src/components/Upload/Uploads.tsx | 85 +++++++++++++++++++ .../DashboardPage/DashboardPage.stories.tsx | 13 +++ .../DashboardPage/DashboardPage.test.tsx | 14 +++ web/src/pages/DashboardPage/DashboardPage.tsx | 59 +++++++++++++ 5 files changed, 172 insertions(+) create mode 100644 web/src/components/Upload/Uploads.tsx create mode 100644 web/src/pages/DashboardPage/DashboardPage.stories.tsx create mode 100644 web/src/pages/DashboardPage/DashboardPage.test.tsx create mode 100644 web/src/pages/DashboardPage/DashboardPage.tsx diff --git a/web/src/Routes.tsx b/web/src/Routes.tsx index 2aa4d0df..1c5b4f28 100644 --- a/web/src/Routes.tsx +++ b/web/src/Routes.tsx @@ -29,6 +29,7 @@ const Routes = () => { + diff --git a/web/src/components/Upload/Uploads.tsx b/web/src/components/Upload/Uploads.tsx new file mode 100644 index 00000000..17351b4a --- /dev/null +++ b/web/src/components/Upload/Uploads.tsx @@ -0,0 +1,85 @@ +import Button from 'react-bootstrap/Button' +import Table from 'react-bootstrap/Table' + +import { Link, routes } from '@redwoodjs/router' + +import { truncate } from 'src/lib/formatters' + +const UploadsList = () => { + const uploads = [ + { + filename: 'Test EC1-4 v20231007 - CLEAN.xlsm', + created_at: '2023-12-03T21:47:25.751Z', + reporting_period_id: 6, + user_id: 3, + agency_id: 0, + validated_at: '2023-12-03T21:47:29.460Z', + validated_by: 3, + ec_code: '1.4', + tenant_id: 1, + id: 'b4d22796-75a6-4ac3-95f4-0d07f1e12f3e', + notes: + 'This is to test two things. First, EC1.4 wording. Second, The Audit Report pulling the correct data.', + invalidated_at: null, + invalidated_by: null, + created_by: 'joecomeau01@gmail.com', + agency_code: 'USDR', + }, + { + filename: 'NEW 10002 - DHS - EC2_32 - v202306016 - CLEAN (1).xlsm', + created_at: '2023-12-01T19:19:21.458Z', + reporting_period_id: 6, + user_id: 983, + agency_id: 0, + validated_at: '2023-12-01T19:19:25.255Z', + validated_by: 983, + ec_code: '2.32', + tenant_id: 1, + id: '322f925a-5f4f-4313-a730-a0067217100d', + notes: null, + invalidated_at: null, + invalidated_by: null, + created_by: 'asridhar+staff@usdigitalresponse.org', + agency_code: 'USDR', + }, + ] + + return ( + + + + + + + + + + + + + + {uploads.map((upload) => ( + + + + + + + + + + ))} + +
IDAgencyEC CodeUploaded ByFilenameNotesValidated?
{truncate(upload.id)} + {truncate(upload.agency_code)} + {upload.ec_code}{upload.created_by} + {upload.filename}{' '} + {/* TODO: Implement file download when the API is ready */} + {/* */} + {upload.notes}{upload.invalidated_at}
+ ) +} + +export default UploadsList diff --git a/web/src/pages/DashboardPage/DashboardPage.stories.tsx b/web/src/pages/DashboardPage/DashboardPage.stories.tsx new file mode 100644 index 00000000..af6a7a4d --- /dev/null +++ b/web/src/pages/DashboardPage/DashboardPage.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import DashboardPage from './DashboardPage' + +const meta: Meta = { + component: DashboardPage, +} + +export default meta + +type Story = StoryObj + +export const Primary: Story = {} diff --git a/web/src/pages/DashboardPage/DashboardPage.test.tsx b/web/src/pages/DashboardPage/DashboardPage.test.tsx new file mode 100644 index 00000000..b6d9d375 --- /dev/null +++ b/web/src/pages/DashboardPage/DashboardPage.test.tsx @@ -0,0 +1,14 @@ +import { render } from '@redwoodjs/testing/web' + +import DashboardPage from './DashboardPage' + +// Improve this test with help from the Redwood Testing Doc: +// https://redwoodjs.com/docs/testing#testing-pages-layouts + +describe('DashboardPage', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/web/src/pages/DashboardPage/DashboardPage.tsx b/web/src/pages/DashboardPage/DashboardPage.tsx new file mode 100644 index 00000000..814944ea --- /dev/null +++ b/web/src/pages/DashboardPage/DashboardPage.tsx @@ -0,0 +1,59 @@ +import { Button, ButtonGroup } from 'react-bootstrap' + +import { Link, routes } from '@redwoodjs/router' +import { MetaTags } from '@redwoodjs/web' + +import UploadsList from '../../components/Upload/Uploads' // Import the UploadsList component + +const DashboardPage = () => { + return ( + <> + + +

Uploads

+ {/*

+ My default route is named dashboard, link to me with ` + Dashboard` +

*/} + + {/* + + + + + + + + + + */} + + + + + + + + + + + + ) +} + +export default DashboardPage From aa5251940be8854f18538aa070b5f829bdb1f363 Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Sun, 10 Dec 2023 18:14:17 -0500 Subject: [PATCH 02/11] feature/3 add CRUD pages for Uploads --- api/db/schema.prisma | 6 +- .../uploadValidations.scenarios.ts | 134 ------ .../uploadValidations.test.ts | 83 ---- api/src/services/uploads/uploads.scenarios.ts | 40 +- api/src/services/uploads/uploads.test.ts | 4 +- web/src/App.tsx | 1 + web/src/Routes.tsx | 6 + .../Upload/EditUploadCell/EditUploadCell.tsx | 85 ++++ .../components/Upload/NewUpload/NewUpload.tsx | 47 +++ web/src/components/Upload/Upload/Upload.tsx | 109 +++++ .../Upload/UploadCell/UploadCell.tsx | 33 ++ .../Upload/UploadForm/UploadForm.tsx | 156 +++++++ web/src/components/Upload/Uploads/Uploads.tsx | 102 +++++ .../Upload/UploadsCell/UploadsCell.tsx | 43 ++ .../Upload/EditUploadPage/EditUploadPage.tsx | 11 + .../Upload/NewUploadPage/NewUploadPage.tsx | 7 + .../pages/Upload/UploadPage/UploadPage.tsx | 11 + .../pages/Upload/UploadsPage/UploadsPage.tsx | 7 + web/src/scaffold.css | 397 ++++++++++++++++++ web/types/graphql.d.ts | 41 ++ 20 files changed, 1081 insertions(+), 242 deletions(-) delete mode 100644 api/src/services/uploadValidations/uploadValidations.scenarios.ts delete mode 100644 api/src/services/uploadValidations/uploadValidations.test.ts create mode 100644 web/src/components/Upload/EditUploadCell/EditUploadCell.tsx create mode 100644 web/src/components/Upload/NewUpload/NewUpload.tsx create mode 100644 web/src/components/Upload/Upload/Upload.tsx create mode 100644 web/src/components/Upload/UploadCell/UploadCell.tsx create mode 100644 web/src/components/Upload/UploadForm/UploadForm.tsx create mode 100644 web/src/components/Upload/Uploads/Uploads.tsx create mode 100644 web/src/components/Upload/UploadsCell/UploadsCell.tsx create mode 100644 web/src/pages/Upload/EditUploadPage/EditUploadPage.tsx create mode 100644 web/src/pages/Upload/NewUploadPage/NewUploadPage.tsx create mode 100644 web/src/pages/Upload/UploadPage/UploadPage.tsx create mode 100644 web/src/pages/Upload/UploadsPage/UploadsPage.tsx create mode 100644 web/src/scaffold.css diff --git a/api/db/schema.prisma b/api/db/schema.prisma index d191b673..6e7eadd8 100644 --- a/api/db/schema.prisma +++ b/api/db/schema.prisma @@ -14,7 +14,7 @@ model Agency { name String abbreviation String? code String - tenant Organization? @relation(fields: [organizationId], references: [id]) + organization Organization? @relation(fields: [organizationId], references: [id]) organizationId Int? users User[] uploads Upload[] @@ -114,7 +114,7 @@ model Upload { agencyId Int agency Agency @relation(fields: [agencyId], references: [id]) organizationId Int - organizaiton Organization @relation(fields: [organizationId], references: [id]) + organization Organization @relation(fields: [organizationId], references: [id]) reportingPeriodId Int reportingPeriod ReportingPeriod @relation(fields: [reportingPeriodId], references: [id]) expenditureCategoryId Int @@ -131,7 +131,7 @@ model UploadValidation { agencyId Int agency Agency @relation(fields: [agencyId], references: [id]) organizationId Int - organizaiton Organization @relation(fields: [organizationId], references: [id]) + organization Organization @relation(fields: [organizationId], references: [id]) inputTemplateId Int inputTemplate InputTemplate @relation(fields: [inputTemplateId], references: [id]) validationResults Json? @db.JsonB diff --git a/api/src/services/uploadValidations/uploadValidations.scenarios.ts b/api/src/services/uploadValidations/uploadValidations.scenarios.ts deleted file mode 100644 index 27e33171..00000000 --- a/api/src/services/uploadValidations/uploadValidations.scenarios.ts +++ /dev/null @@ -1,134 +0,0 @@ -import type { Prisma, UploadValidation } from '@prisma/client' -import type { ScenarioData } from '@redwoodjs/testing/api' - -export const standard = defineScenario({ - uploadValidation: { - one: { - data: { - updatedAt: '2023-12-08T21:03:20.706Z', - upload: { - create: { - filename: 'String', - updatedAt: '2023-12-08T21:03:20.706Z', - uploadedBy: { - create: { - email: 'String', - updatedAt: '2023-12-08T21:03:20.706Z', - organization: { create: { name: 'String' } }, - }, - }, - agency: { create: { name: 'String', code: 'String' } }, - organizaiton: { create: { name: 'String' } }, - reportingPeriod: { - create: { - name: 'String', - startDate: '2023-12-08T21:03:20.706Z', - endDate: '2023-12-08T21:03:20.706Z', - updatedAt: '2023-12-08T21:03:20.706Z', - inputTemplate: { - create: { - name: 'String', - version: 'String', - effectiveDate: '2023-12-08T21:03:20.706Z', - updatedAt: '2023-12-08T21:03:20.706Z', - }, - }, - outputTemplate: { - create: { - name: 'String', - version: 'String', - effectiveDate: '2023-12-08T21:03:20.706Z', - updatedAt: '2023-12-08T21:03:20.706Z', - }, - }, - }, - }, - expenditureCategory: { - create: { - name: 'String', - code: 'String', - updatedAt: '2023-12-08T21:03:20.706Z', - }, - }, - }, - }, - agency: { create: { name: 'String', code: 'String' } }, - organizaiton: { create: { name: 'String' } }, - inputTemplate: { - create: { - name: 'String', - version: 'String', - effectiveDate: '2023-12-08T21:03:20.706Z', - updatedAt: '2023-12-08T21:03:20.706Z', - }, - }, - }, - }, - two: { - data: { - updatedAt: '2023-12-08T21:03:20.706Z', - upload: { - create: { - filename: 'String', - updatedAt: '2023-12-08T21:03:20.706Z', - uploadedBy: { - create: { - email: 'String', - updatedAt: '2023-12-08T21:03:20.706Z', - organization: { create: { name: 'String' } }, - }, - }, - agency: { create: { name: 'String', code: 'String' } }, - organizaiton: { create: { name: 'String' } }, - reportingPeriod: { - create: { - name: 'String', - startDate: '2023-12-08T21:03:20.706Z', - endDate: '2023-12-08T21:03:20.706Z', - updatedAt: '2023-12-08T21:03:20.706Z', - inputTemplate: { - create: { - name: 'String', - version: 'String', - effectiveDate: '2023-12-08T21:03:20.706Z', - updatedAt: '2023-12-08T21:03:20.706Z', - }, - }, - outputTemplate: { - create: { - name: 'String', - version: 'String', - effectiveDate: '2023-12-08T21:03:20.706Z', - updatedAt: '2023-12-08T21:03:20.706Z', - }, - }, - }, - }, - expenditureCategory: { - create: { - name: 'String', - code: 'String', - updatedAt: '2023-12-08T21:03:20.706Z', - }, - }, - }, - }, - agency: { create: { name: 'String', code: 'String' } }, - organizaiton: { create: { name: 'String' } }, - inputTemplate: { - create: { - name: 'String', - version: 'String', - effectiveDate: '2023-12-08T21:03:20.706Z', - updatedAt: '2023-12-08T21:03:20.706Z', - }, - }, - }, - }, - }, -}) - -export type StandardScenario = ScenarioData< - UploadValidation, - 'uploadValidation' -> diff --git a/api/src/services/uploadValidations/uploadValidations.test.ts b/api/src/services/uploadValidations/uploadValidations.test.ts deleted file mode 100644 index 600b808f..00000000 --- a/api/src/services/uploadValidations/uploadValidations.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { UploadValidation } from '@prisma/client' - -import { - uploadValidations, - uploadValidation, - createUploadValidation, - updateUploadValidation, - deleteUploadValidation, -} from './uploadValidations' -import type { StandardScenario } from './uploadValidations.scenarios' - -// Generated boilerplate tests do not account for all circumstances -// and can fail without adjustments, e.g. Float. -// Please refer to the RedwoodJS Testing Docs: -// https://redwoodjs.com/docs/testing#testing-services -// https://redwoodjs.com/docs/testing#jest-expect-type-considerations - -describe('uploadValidations', () => { - scenario( - 'returns all uploadValidations', - async (scenario: StandardScenario) => { - const result = await uploadValidations() - - expect(result.length).toEqual( - Object.keys(scenario.uploadValidation).length - ) - } - ) - - scenario( - 'returns a single uploadValidation', - async (scenario: StandardScenario) => { - const result = await uploadValidation({ - id: scenario.uploadValidation.one.id, - }) - - expect(result).toEqual(scenario.uploadValidation.one) - } - ) - - scenario('creates a uploadValidation', async (scenario: StandardScenario) => { - const result = await createUploadValidation({ - input: { - uploadId: scenario.uploadValidation.two.uploadId, - agencyId: scenario.uploadValidation.two.agencyId, - organizationId: scenario.uploadValidation.two.organizationId, - inputTemplateId: scenario.uploadValidation.two.inputTemplateId, - updatedAt: '2023-12-08T21:03:20.590Z', - }, - }) - - expect(result.uploadId).toEqual(scenario.uploadValidation.two.uploadId) - expect(result.agencyId).toEqual(scenario.uploadValidation.two.agencyId) - expect(result.organizationId).toEqual( - scenario.uploadValidation.two.organizationId - ) - expect(result.inputTemplateId).toEqual( - scenario.uploadValidation.two.inputTemplateId - ) - expect(result.updatedAt).toEqual(new Date('2023-12-08T21:03:20.590Z')) - }) - - scenario('updates a uploadValidation', async (scenario: StandardScenario) => { - const original = (await uploadValidation({ - id: scenario.uploadValidation.one.id, - })) as UploadValidation - const result = await updateUploadValidation({ - id: original.id, - input: { updatedAt: '2023-12-09T21:03:20.590Z' }, - }) - - expect(result.updatedAt).toEqual(new Date('2023-12-09T21:03:20.590Z')) - }) - - scenario('deletes a uploadValidation', async (scenario: StandardScenario) => { - const original = (await deleteUploadValidation({ - id: scenario.uploadValidation.one.id, - })) as UploadValidation - const result = await uploadValidation({ id: original.id }) - - expect(result).toEqual(null) - }) -}) diff --git a/api/src/services/uploads/uploads.scenarios.ts b/api/src/services/uploads/uploads.scenarios.ts index 95e3d170..878039ae 100644 --- a/api/src/services/uploads/uploads.scenarios.ts +++ b/api/src/services/uploads/uploads.scenarios.ts @@ -6,11 +6,11 @@ export const standard = defineScenario({ one: { data: { filename: 'String', - updatedAt: '2023-12-08T21:03:09.638Z', + updatedAt: '2023-12-10T04:48:04.896Z', uploadedBy: { create: { email: 'String', - updatedAt: '2023-12-08T21:03:09.638Z', + updatedAt: '2023-12-10T04:48:04.896Z', organization: { create: { name: 'String' } }, }, }, @@ -19,23 +19,23 @@ export const standard = defineScenario({ reportingPeriod: { create: { name: 'String', - startDate: '2023-12-08T21:03:09.638Z', - endDate: '2023-12-08T21:03:09.638Z', - updatedAt: '2023-12-08T21:03:09.638Z', + startDate: '2023-12-10T04:48:04.896Z', + endDate: '2023-12-10T04:48:04.896Z', + updatedAt: '2023-12-10T04:48:04.896Z', inputTemplate: { create: { name: 'String', version: 'String', - effectiveDate: '2023-12-08T21:03:09.638Z', - updatedAt: '2023-12-08T21:03:09.638Z', + effectiveDate: '2023-12-10T04:48:04.896Z', + updatedAt: '2023-12-10T04:48:04.896Z', }, }, outputTemplate: { create: { name: 'String', version: 'String', - effectiveDate: '2023-12-08T21:03:09.638Z', - updatedAt: '2023-12-08T21:03:09.638Z', + effectiveDate: '2023-12-10T04:48:04.896Z', + updatedAt: '2023-12-10T04:48:04.896Z', }, }, }, @@ -44,7 +44,7 @@ export const standard = defineScenario({ create: { name: 'String', code: 'String', - updatedAt: '2023-12-08T21:03:09.638Z', + updatedAt: '2023-12-10T04:48:04.896Z', }, }, }, @@ -52,11 +52,11 @@ export const standard = defineScenario({ two: { data: { filename: 'String', - updatedAt: '2023-12-08T21:03:09.638Z', + updatedAt: '2023-12-10T04:48:04.896Z', uploadedBy: { create: { email: 'String', - updatedAt: '2023-12-08T21:03:09.638Z', + updatedAt: '2023-12-10T04:48:04.896Z', organization: { create: { name: 'String' } }, }, }, @@ -65,23 +65,23 @@ export const standard = defineScenario({ reportingPeriod: { create: { name: 'String', - startDate: '2023-12-08T21:03:09.638Z', - endDate: '2023-12-08T21:03:09.638Z', - updatedAt: '2023-12-08T21:03:09.638Z', + startDate: '2023-12-10T04:48:04.896Z', + endDate: '2023-12-10T04:48:04.896Z', + updatedAt: '2023-12-10T04:48:04.896Z', inputTemplate: { create: { name: 'String', version: 'String', - effectiveDate: '2023-12-08T21:03:09.638Z', - updatedAt: '2023-12-08T21:03:09.638Z', + effectiveDate: '2023-12-10T04:48:04.896Z', + updatedAt: '2023-12-10T04:48:04.896Z', }, }, outputTemplate: { create: { name: 'String', version: 'String', - effectiveDate: '2023-12-08T21:03:09.639Z', - updatedAt: '2023-12-08T21:03:09.639Z', + effectiveDate: '2023-12-10T04:48:04.896Z', + updatedAt: '2023-12-10T04:48:04.896Z', }, }, }, @@ -90,7 +90,7 @@ export const standard = defineScenario({ create: { name: 'String', code: 'String', - updatedAt: '2023-12-08T21:03:09.639Z', + updatedAt: '2023-12-10T04:48:04.896Z', }, }, }, diff --git a/api/src/services/uploads/uploads.test.ts b/api/src/services/uploads/uploads.test.ts index 99d72edd..4d97bfa1 100644 --- a/api/src/services/uploads/uploads.test.ts +++ b/api/src/services/uploads/uploads.test.ts @@ -37,7 +37,7 @@ describe('uploads', () => { organizationId: scenario.upload.two.organizationId, reportingPeriodId: scenario.upload.two.reportingPeriodId, expenditureCategoryId: scenario.upload.two.expenditureCategoryId, - updatedAt: '2023-12-08T21:03:09.551Z', + updatedAt: '2023-12-10T04:48:04.888Z', }, }) @@ -51,7 +51,7 @@ describe('uploads', () => { expect(result.expenditureCategoryId).toEqual( scenario.upload.two.expenditureCategoryId ) - expect(result.updatedAt).toEqual(new Date('2023-12-08T21:03:09.551Z')) + expect(result.updatedAt).toEqual(new Date('2023-12-10T04:48:04.888Z')) }) scenario('updates a upload', async (scenario: StandardScenario) => { diff --git a/web/src/App.tsx b/web/src/App.tsx index c52c9d2a..4826ba43 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -26,6 +26,7 @@ import { RedwoodApolloProvider } from '@redwoodjs/web/apollo' import FatalErrorPage from 'src/pages/FatalErrorPage' import Routes from 'src/Routes' +import './scaffold.css' import './scss/custom.scss' const App = () => ( diff --git a/web/src/Routes.tsx b/web/src/Routes.tsx index 85887125..5a7dbf3f 100644 --- a/web/src/Routes.tsx +++ b/web/src/Routes.tsx @@ -14,6 +14,12 @@ import ScaffoldLayout from 'src/layouts/ScaffoldLayout' const Routes = () => { return ( + + + + + + diff --git a/web/src/components/Upload/EditUploadCell/EditUploadCell.tsx b/web/src/components/Upload/EditUploadCell/EditUploadCell.tsx new file mode 100644 index 00000000..d5cba625 --- /dev/null +++ b/web/src/components/Upload/EditUploadCell/EditUploadCell.tsx @@ -0,0 +1,85 @@ +import type { EditUploadById, UpdateUploadInput } from 'types/graphql' + +import { navigate, routes } from '@redwoodjs/router' +import type { CellSuccessProps, CellFailureProps } from '@redwoodjs/web' +import { useMutation } from '@redwoodjs/web' +import { toast } from '@redwoodjs/web/toast' + +import UploadForm from 'src/components/Upload/UploadForm' + +export const QUERY = gql` + query EditUploadById($id: Int!) { + upload: upload(id: $id) { + id + filename + uploadedById + agencyId + organizationId + reportingPeriodId + expenditureCategoryId + createdAt + updatedAt + } + } +` +const UPDATE_UPLOAD_MUTATION = gql` + mutation UpdateUploadMutation($id: Int!, $input: UpdateUploadInput!) { + updateUpload(id: $id, input: $input) { + id + filename + uploadedById + agencyId + organizationId + reportingPeriodId + expenditureCategoryId + createdAt + updatedAt + } + } +` + +export const Loading = () =>
Loading...
+ +export const Failure = ({ error }: CellFailureProps) => ( +
{error?.message}
+) + +export const Success = ({ upload }: CellSuccessProps) => { + const [updateUpload, { loading, error }] = useMutation( + UPDATE_UPLOAD_MUTATION, + { + onCompleted: () => { + toast.success('Upload updated') + navigate(routes.uploads()) + }, + onError: (error) => { + toast.error(error.message) + }, + } + ) + + const onSave = ( + input: UpdateUploadInput, + id: EditUploadById['upload']['id'] + ) => { + updateUpload({ variables: { id, input } }) + } + + return ( +
+
+

+ Edit Upload {upload?.id} +

+
+
+ +
+
+ ) +} diff --git a/web/src/components/Upload/NewUpload/NewUpload.tsx b/web/src/components/Upload/NewUpload/NewUpload.tsx new file mode 100644 index 00000000..5ec33137 --- /dev/null +++ b/web/src/components/Upload/NewUpload/NewUpload.tsx @@ -0,0 +1,47 @@ +import { navigate, routes } from '@redwoodjs/router' +import { useMutation } from '@redwoodjs/web' +import { toast } from '@redwoodjs/web/toast' + +import UploadForm from 'src/components/Upload/UploadForm' + +import type { CreateUploadInput } from 'types/graphql' + +const CREATE_UPLOAD_MUTATION = gql` + mutation CreateUploadMutation($input: CreateUploadInput!) { + createUpload(input: $input) { + id + } + } +` + +const NewUpload = () => { + const [createUpload, { loading, error }] = useMutation( + CREATE_UPLOAD_MUTATION, + { + onCompleted: () => { + toast.success('Upload created') + navigate(routes.uploads()) + }, + onError: (error) => { + toast.error(error.message) + }, + } + ) + + const onSave = (input: CreateUploadInput) => { + createUpload({ variables: { input } }) + } + + return ( +
+
+

New Upload

+
+
+ +
+
+ ) +} + +export default NewUpload diff --git a/web/src/components/Upload/Upload/Upload.tsx b/web/src/components/Upload/Upload/Upload.tsx new file mode 100644 index 00000000..4fb8b9de --- /dev/null +++ b/web/src/components/Upload/Upload/Upload.tsx @@ -0,0 +1,109 @@ +import { Link, routes, navigate } from '@redwoodjs/router' +import { useMutation } from '@redwoodjs/web' +import { toast } from '@redwoodjs/web/toast' + +import { timeTag } from 'src/lib/formatters' + +import type { + DeleteUploadMutationVariables, + FindUploadById, +} from 'types/graphql' + +const DELETE_UPLOAD_MUTATION = gql` + mutation DeleteUploadMutation($id: Int!) { + deleteUpload(id: $id) { + id + } + } +` + +interface Props { + upload: NonNullable +} + +const Upload = ({ upload }: Props) => { + const [deleteUpload] = useMutation(DELETE_UPLOAD_MUTATION, { + onCompleted: () => { + toast.success('Upload deleted') + navigate(routes.uploads()) + }, + onError: (error) => { + toast.error(error.message) + }, + }) + + const onDeleteClick = (id: DeleteUploadMutationVariables['id']) => { + if (confirm('Are you sure you want to delete upload ' + id + '?')) { + deleteUpload({ variables: { id } }) + } + } + + return ( + <> +
+
+

+ Upload {upload.id} Detail +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Id{upload.id}
Filename{upload.filename}
Uploaded by id{upload.uploadedById}
Agency id{upload.agencyId}
Organization id{upload.organizationId}
Reporting period id{upload.reportingPeriodId}
Expenditure category id{upload.expenditureCategoryId}
Created at{timeTag(upload.createdAt)}
Updated at{timeTag(upload.updatedAt)}
+
+ + + ) +} + +export default Upload diff --git a/web/src/components/Upload/UploadCell/UploadCell.tsx b/web/src/components/Upload/UploadCell/UploadCell.tsx new file mode 100644 index 00000000..526d2f80 --- /dev/null +++ b/web/src/components/Upload/UploadCell/UploadCell.tsx @@ -0,0 +1,33 @@ +import type { FindUploadById } from 'types/graphql' + +import type { CellSuccessProps, CellFailureProps } from '@redwoodjs/web' + +import Upload from 'src/components/Upload/Upload' + +export const QUERY = gql` + query FindUploadById($id: Int!) { + upload: upload(id: $id) { + id + filename + uploadedById + agencyId + organizationId + reportingPeriodId + expenditureCategoryId + createdAt + updatedAt + } + } +` + +export const Loading = () =>
Loading...
+ +export const Empty = () =>
Upload not found
+ +export const Failure = ({ error }: CellFailureProps) => ( +
{error?.message}
+) + +export const Success = ({ upload }: CellSuccessProps) => { + return +} diff --git a/web/src/components/Upload/UploadForm/UploadForm.tsx b/web/src/components/Upload/UploadForm/UploadForm.tsx new file mode 100644 index 00000000..c54b4d45 --- /dev/null +++ b/web/src/components/Upload/UploadForm/UploadForm.tsx @@ -0,0 +1,156 @@ +import { + Form, + FormError, + FieldError, + Label, + TextField, + NumberField, + Submit, +} from '@redwoodjs/forms' + +import type { EditUploadById, UpdateUploadInput } from 'types/graphql' +import type { RWGqlError } from '@redwoodjs/forms' + +type FormUpload = NonNullable + +interface UploadFormProps { + upload?: EditUploadById['upload'] + onSave: (data: UpdateUploadInput, id?: FormUpload['id']) => void + error: RWGqlError + loading: boolean +} + +const UploadForm = (props: UploadFormProps) => { + const onSubmit = (data: FormUpload) => { + props.onSave(data, props?.upload?.id) + } + + return ( +
+ onSubmit={onSubmit} error={props.error}> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Save + +
+ +
+ ) +} + +export default UploadForm diff --git a/web/src/components/Upload/Uploads/Uploads.tsx b/web/src/components/Upload/Uploads/Uploads.tsx new file mode 100644 index 00000000..812ace72 --- /dev/null +++ b/web/src/components/Upload/Uploads/Uploads.tsx @@ -0,0 +1,102 @@ +import { Link, routes } from '@redwoodjs/router' +import { useMutation } from '@redwoodjs/web' +import { toast } from '@redwoodjs/web/toast' + +import { QUERY } from 'src/components/Upload/UploadsCell' +import { timeTag, truncate } from 'src/lib/formatters' + +import type { DeleteUploadMutationVariables, FindUploads } from 'types/graphql' + +const DELETE_UPLOAD_MUTATION = gql` + mutation DeleteUploadMutation($id: Int!) { + deleteUpload(id: $id) { + id + } + } +` + +const UploadsList = ({ uploads }: FindUploads) => { + const [deleteUpload] = useMutation(DELETE_UPLOAD_MUTATION, { + onCompleted: () => { + toast.success('Upload deleted') + }, + onError: (error) => { + toast.error(error.message) + }, + // This refetches the query on the list page. Read more about other ways to + // update the cache over here: + // https://www.apollographql.com/docs/react/data/mutations/#making-all-other-cache-updates + refetchQueries: [{ query: QUERY }], + awaitRefetchQueries: true, + }) + + const onDeleteClick = (id: DeleteUploadMutationVariables['id']) => { + if (confirm('Are you sure you want to delete upload ' + id + '?')) { + deleteUpload({ variables: { id } }) + } + } + + return ( +
+ + + + + + + + + + + + + + + + + {uploads.map((upload) => ( + + + + + + + + + + + + + ))} + +
IdFilenameUploaded by idAgency idOrganization idReporting period idExpenditure category idCreated atUpdated at 
{truncate(upload.id)}{truncate(upload.filename)}{truncate(upload.uploadedById)}{truncate(upload.agencyId)}{truncate(upload.organizationId)}{truncate(upload.reportingPeriodId)}{truncate(upload.expenditureCategoryId)}{timeTag(upload.createdAt)}{timeTag(upload.updatedAt)} + +
+
+ ) +} + +export default UploadsList diff --git a/web/src/components/Upload/UploadsCell/UploadsCell.tsx b/web/src/components/Upload/UploadsCell/UploadsCell.tsx new file mode 100644 index 00000000..5c6aaee0 --- /dev/null +++ b/web/src/components/Upload/UploadsCell/UploadsCell.tsx @@ -0,0 +1,43 @@ +import type { FindUploads } from 'types/graphql' + +import { Link, routes } from '@redwoodjs/router' +import type { CellSuccessProps, CellFailureProps } from '@redwoodjs/web' + +import Uploads from 'src/components/Upload/Uploads' + +export const QUERY = gql` + query FindUploads { + uploads { + id + filename + uploadedById + agencyId + organizationId + reportingPeriodId + expenditureCategoryId + createdAt + updatedAt + } + } +` + +export const Loading = () =>
Loading...
+ +export const Empty = () => { + return ( +
+ {'No uploads yet. '} + + {'Create one?'} + +
+ ) +} + +export const Failure = ({ error }: CellFailureProps) => ( +
{error?.message}
+) + +export const Success = ({ uploads }: CellSuccessProps) => { + return +} diff --git a/web/src/pages/Upload/EditUploadPage/EditUploadPage.tsx b/web/src/pages/Upload/EditUploadPage/EditUploadPage.tsx new file mode 100644 index 00000000..d3864c2f --- /dev/null +++ b/web/src/pages/Upload/EditUploadPage/EditUploadPage.tsx @@ -0,0 +1,11 @@ +import EditUploadCell from 'src/components/Upload/EditUploadCell' + +type UploadPageProps = { + id: number +} + +const EditUploadPage = ({ id }: UploadPageProps) => { + return +} + +export default EditUploadPage diff --git a/web/src/pages/Upload/NewUploadPage/NewUploadPage.tsx b/web/src/pages/Upload/NewUploadPage/NewUploadPage.tsx new file mode 100644 index 00000000..fc878bbf --- /dev/null +++ b/web/src/pages/Upload/NewUploadPage/NewUploadPage.tsx @@ -0,0 +1,7 @@ +import NewUpload from 'src/components/Upload/NewUpload' + +const NewUploadPage = () => { + return +} + +export default NewUploadPage diff --git a/web/src/pages/Upload/UploadPage/UploadPage.tsx b/web/src/pages/Upload/UploadPage/UploadPage.tsx new file mode 100644 index 00000000..8dd1dcac --- /dev/null +++ b/web/src/pages/Upload/UploadPage/UploadPage.tsx @@ -0,0 +1,11 @@ +import UploadCell from 'src/components/Upload/UploadCell' + +type UploadPageProps = { + id: number +} + +const UploadPage = ({ id }: UploadPageProps) => { + return +} + +export default UploadPage diff --git a/web/src/pages/Upload/UploadsPage/UploadsPage.tsx b/web/src/pages/Upload/UploadsPage/UploadsPage.tsx new file mode 100644 index 00000000..8ee63d5d --- /dev/null +++ b/web/src/pages/Upload/UploadsPage/UploadsPage.tsx @@ -0,0 +1,7 @@ +import UploadsCell from 'src/components/Upload/UploadsCell' + +const UploadsPage = () => { + return +} + +export default UploadsPage diff --git a/web/src/scaffold.css b/web/src/scaffold.css new file mode 100644 index 00000000..3a6a2155 --- /dev/null +++ b/web/src/scaffold.css @@ -0,0 +1,397 @@ +/* + normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css +*/ + +.rw-scaffold *, +.rw-scaffold ::after, +.rw-scaffold ::before { + box-sizing: inherit; +} +.rw-scaffold main { + color: #4a5568; + display: block; +} +.rw-scaffold h1, +.rw-scaffold h2 { + margin: 0; +} +.rw-scaffold a { + background-color: transparent; +} +.rw-scaffold ul { + margin: 0; + padding: 0; +} +.rw-scaffold input { + font-family: inherit; + font-size: 100%; + overflow: visible; +} +.rw-scaffold input:-ms-input-placeholder { + color: #a0aec0; +} +.rw-scaffold input::-ms-input-placeholder { + color: #a0aec0; +} +.rw-scaffold input::placeholder { + color: #a0aec0; +} +.rw-scaffold table { + border-collapse: collapse; +} + +/* + Style +*/ + +.rw-scaffold, +.rw-toast { + background-color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} +.rw-header { + display: flex; + justify-content: space-between; + padding: 1rem 2rem 1rem 2rem; +} +.rw-main { + margin-left: 1rem; + margin-right: 1rem; + padding-bottom: 1rem; +} +.rw-segment { + border-radius: 0.5rem; + border-width: 1px; + border-color: #e5e7eb; + overflow: hidden; + width: 100%; + scrollbar-color: #a1a1aa transparent; +} +.rw-segment::-webkit-scrollbar { + height: initial; +} +.rw-segment::-webkit-scrollbar-track { + background-color: transparent; + border-color: #e2e8f0; + border-style: solid; + border-radius: 0 0 10px 10px; + border-width: 1px 0 0 0; + padding: 2px; +} +.rw-segment::-webkit-scrollbar-thumb { + background-color: #a1a1aa; + background-clip: content-box; + border: 3px solid transparent; + border-radius: 10px; +} +.rw-segment-header { + background-color: #e2e8f0; + color: #4a5568; + padding: 0.75rem 1rem; +} +.rw-segment-main { + background-color: #f7fafc; + padding: 1rem; +} +.rw-link { + color: #4299e1; + text-decoration: underline; +} +.rw-link:hover { + color: #2b6cb0; +} +.rw-forgot-link { + font-size: 0.75rem; + color: #a0aec0; + text-align: right; + margin-top: 0.1rem; +} +.rw-forgot-link:hover { + font-size: 0.75rem; + color: #4299e1; +} +.rw-heading { + font-weight: 600; +} +.rw-heading.rw-heading-primary { + font-size: 1.25rem; +} +.rw-heading.rw-heading-secondary { + font-size: 0.875rem; +} +.rw-heading .rw-link { + color: #4a5568; + text-decoration: none; +} +.rw-heading .rw-link:hover { + color: #1a202c; + text-decoration: underline; +} +.rw-cell-error { + font-size: 90%; + font-weight: 600; +} +.rw-form-wrapper { + box-sizing: border-box; + font-size: 0.875rem; + margin-top: -1rem; +} +.rw-cell-error, +.rw-form-error-wrapper { + padding: 1rem; + background-color: #fff5f5; + color: #c53030; + border-width: 1px; + border-color: #feb2b2; + border-radius: 0.25rem; + margin: 1rem 0; +} +.rw-form-error-title { + margin-top: 0; + margin-bottom: 0; + font-weight: 600; +} +.rw-form-error-list { + margin-top: 0.5rem; + list-style-type: disc; + list-style-position: inside; +} +.rw-button { + border: none; + color: #718096; + cursor: pointer; + display: flex; + justify-content: center; + font-size: 0.75rem; + font-weight: 600; + padding: 0.25rem 1rem; + text-transform: uppercase; + text-decoration: none; + letter-spacing: 0.025em; + border-radius: 0.25rem; + line-height: 2; + border: 0; +} +.rw-button:hover { + background-color: #718096; + color: #fff; +} +.rw-button.rw-button-small { + font-size: 0.75rem; + border-radius: 0.125rem; + padding: 0.25rem 0.5rem; + line-height: inherit; +} +.rw-button.rw-button-green { + background-color: #48bb78; + color: #fff; +} +.rw-button.rw-button-green:hover { + background-color: #38a169; + color: #fff; +} +.rw-button.rw-button-blue { + background-color: #3182ce; + color: #fff; +} +.rw-button.rw-button-blue:hover { + background-color: #2b6cb0; +} +.rw-button.rw-button-red { + background-color: #e53e3e; + color: #fff; +} +.rw-button.rw-button-red:hover { + background-color: #c53030; +} +.rw-button-icon { + font-size: 1.25rem; + line-height: 1; + margin-right: 0.25rem; +} +.rw-button-group { + display: flex; + justify-content: center; + margin: 0.75rem 0.5rem; +} +.rw-button-group .rw-button { + margin: 0 0.25rem; +} +.rw-form-wrapper .rw-button-group { + margin-top: 2rem; + margin-bottom: 0; +} +.rw-label { + display: block; + margin-top: 1.5rem; + color: #4a5568; + font-weight: 600; + text-align: left; +} +.rw-label.rw-label-error { + color: #c53030; +} +.rw-input { + display: block; + margin-top: 0.5rem; + width: 100%; + padding: 0.5rem; + border-width: 1px; + border-style: solid; + border-color: #e2e8f0; + color: #4a5568; + border-radius: 0.25rem; + outline: none; +} +.rw-check-radio-item-none { + color: #4a5568; +} +.rw-check-radio-items { + display: flex; + justify-items: center; +} +.rw-input[type='checkbox'] { + display: inline; + width: 1rem; + margin-left: 0; + margin-right: 0.5rem; + margin-top: 0.25rem; +} +.rw-input[type='radio'] { + display: inline; + width: 1rem; + margin-left: 0; + margin-right: 0.5rem; + margin-top: 0.25rem; +} +.rw-input:focus { + border-color: #a0aec0; +} +.rw-input-error { + border-color: #c53030; + color: #c53030; +} + +.rw-input-error:focus { + outline: none; + border-color: #c53030; + box-shadow: 0 0 5px #c53030; +} + +.rw-field-error { + display: block; + margin-top: 0.25rem; + font-weight: 600; + text-transform: uppercase; + font-size: 0.75rem; + color: #c53030; +} +.rw-table-wrapper-responsive { + overflow-x: auto; +} +.rw-table-wrapper-responsive .rw-table { + min-width: 48rem; +} +.rw-table { + table-layout: auto; + width: 100%; + font-size: 0.875rem; +} +.rw-table th, +.rw-table td { + padding: 0.75rem; +} +.rw-table td { + background-color: #ffffff; + color: #1a202c; +} +.rw-table tr:nth-child(odd) td, +.rw-table tr:nth-child(odd) th { + background-color: #f7fafc; +} +.rw-table thead tr { + color: #4a5568; +} +.rw-table th { + font-weight: 600; + text-align: left; +} +.rw-table thead th { + background-color: #e2e8f0; + text-align: left; +} +.rw-table tbody th { + text-align: right; +} +@media (min-width: 768px) { + .rw-table tbody th { + width: 20%; + } +} +.rw-table tbody tr { + border-top-width: 1px; +} +.rw-table input { + margin-left: 0; +} +.rw-table-actions { + display: flex; + justify-content: flex-end; + align-items: center; + height: 17px; + padding-right: 0.25rem; +} +.rw-table-actions .rw-button { + background-color: transparent; +} +.rw-table-actions .rw-button:hover { + background-color: #718096; + color: #fff; +} +.rw-table-actions .rw-button-blue { + color: #3182ce; +} +.rw-table-actions .rw-button-blue:hover { + background-color: #3182ce; + color: #fff; +} +.rw-table-actions .rw-button-red { + color: #e53e3e; +} +.rw-table-actions .rw-button-red:hover { + background-color: #e53e3e; + color: #fff; +} +.rw-text-center { + text-align: center; +} +.rw-login-container { + display: flex; + align-items: center; + justify-content: center; + width: 24rem; + margin: 4rem auto; + flex-wrap: wrap; +} +.rw-login-container .rw-form-wrapper { + width: 100%; + text-align: center; +} +.rw-login-link { + margin-top: 1rem; + color: #4a5568; + font-size: 90%; + text-align: center; + flex-basis: 100%; +} +.rw-webauthn-wrapper { + margin: 1.5rem 1rem 1rem; + line-height: 1.4; +} +.rw-webauthn-wrapper h2 { + font-size: 150%; + font-weight: bold; + margin-bottom: 1rem; +} diff --git a/web/types/graphql.d.ts b/web/types/graphql.d.ts index 07d24a9f..e00759a4 100644 --- a/web/types/graphql.d.ts +++ b/web/types/graphql.d.ts @@ -700,3 +700,44 @@ export type ReportingPeriodsQueryVariables = Exact<{ [key: string]: never; }>; export type ReportingPeriodsQuery = { __typename?: 'Query', reportingPeriods: Array<{ __typename?: 'ReportingPeriod', id: number, startDate: string, endDate: string, isCurrentPeriod: boolean, certifiedAt?: string | null, certifiedBy?: { __typename?: 'User', email: string } | null, inputTemplate: { __typename?: 'InputTemplate', name: string } }> }; + +export type EditUploadByIdVariables = Exact<{ + id: Scalars['Int']; +}>; + + +export type EditUploadById = { __typename?: 'Query', upload?: { __typename?: 'Upload', id: number, filename: string, uploadedById: number, agencyId: number, organizationId: number, reportingPeriodId: number, expenditureCategoryId: number, createdAt: string, updatedAt: string } | null }; + +export type UpdateUploadMutationVariables = Exact<{ + id: Scalars['Int']; + input: UpdateUploadInput; +}>; + + +export type UpdateUploadMutation = { __typename?: 'Mutation', updateUpload: { __typename?: 'Upload', id: number, filename: string, uploadedById: number, agencyId: number, organizationId: number, reportingPeriodId: number, expenditureCategoryId: number, createdAt: string, updatedAt: string } }; + +export type CreateUploadMutationVariables = Exact<{ + input: CreateUploadInput; +}>; + + +export type CreateUploadMutation = { __typename?: 'Mutation', createUpload: { __typename?: 'Upload', id: number } }; + +export type DeleteUploadMutationVariables = Exact<{ + id: Scalars['Int']; +}>; + + +export type DeleteUploadMutation = { __typename?: 'Mutation', deleteUpload: { __typename?: 'Upload', id: number } }; + +export type FindUploadByIdVariables = Exact<{ + id: Scalars['Int']; +}>; + + +export type FindUploadById = { __typename?: 'Query', upload?: { __typename?: 'Upload', id: number, filename: string, uploadedById: number, agencyId: number, organizationId: number, reportingPeriodId: number, expenditureCategoryId: number, createdAt: string, updatedAt: string } | null }; + +export type FindUploadsVariables = Exact<{ [key: string]: never; }>; + + +export type FindUploads = { __typename?: 'Query', uploads: Array<{ __typename?: 'Upload', id: number, filename: string, uploadedById: number, agencyId: number, organizationId: number, reportingPeriodId: number, expenditureCategoryId: number, createdAt: string, updatedAt: string }> }; From c69daf52f408c4905a3e19a8b455464e680d0add Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Mon, 11 Dec 2023 08:18:35 -0500 Subject: [PATCH 03/11] feature/CPF-3 display Bootstrap table with Upload data, remove previous hardcoded table --- web/src/App.tsx | 1 - web/src/Routes.tsx | 3 +- web/src/components/MyUpload/MyUploads.tsx | 85 ---- web/src/components/Upload/Uploads/Uploads.tsx | 118 ++---- .../Upload/UploadsCell/UploadsCell.tsx | 16 +- .../DashboardPage/DashboardPage.stories.tsx | 13 - .../DashboardPage/DashboardPage.test.tsx | 14 - web/src/pages/DashboardPage/DashboardPage.tsx | 59 --- .../pages/Upload/UploadsPage/UploadsPage.tsx | 26 +- web/src/scaffold.css | 397 ------------------ web/src/scss/custom.scss | 4 +- web/src/scss/tables.scss | 0 web/types/graphql.d.ts | 2 +- 13 files changed, 80 insertions(+), 658 deletions(-) delete mode 100644 web/src/components/MyUpload/MyUploads.tsx delete mode 100644 web/src/pages/DashboardPage/DashboardPage.stories.tsx delete mode 100644 web/src/pages/DashboardPage/DashboardPage.test.tsx delete mode 100644 web/src/pages/DashboardPage/DashboardPage.tsx delete mode 100644 web/src/scaffold.css create mode 100644 web/src/scss/tables.scss diff --git a/web/src/App.tsx b/web/src/App.tsx index 4826ba43..c52c9d2a 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -26,7 +26,6 @@ import { RedwoodApolloProvider } from '@redwoodjs/web/apollo' import FatalErrorPage from 'src/pages/FatalErrorPage' import Routes from 'src/Routes' -import './scaffold.css' import './scss/custom.scss' const App = () => ( diff --git a/web/src/Routes.tsx b/web/src/Routes.tsx index 5a7dbf3f..a8ff9821 100644 --- a/web/src/Routes.tsx +++ b/web/src/Routes.tsx @@ -18,7 +18,7 @@ const Routes = () => { - +
@@ -35,7 +35,6 @@ const Routes = () => { - diff --git a/web/src/components/MyUpload/MyUploads.tsx b/web/src/components/MyUpload/MyUploads.tsx deleted file mode 100644 index d1cf3b65..00000000 --- a/web/src/components/MyUpload/MyUploads.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import Button from 'react-bootstrap/Button' -import Table from 'react-bootstrap/Table' - -import { Link, routes } from '@redwoodjs/router' - -import { truncate } from 'src/lib/formatters' - -const MyUploadsList = () => { - const uploads = [ - { - filename: 'Test EC1-4 v20231007 - CLEAN.xlsm', - created_at: '2023-12-03T21:47:25.751Z', - reporting_period_id: 6, - user_id: 3, - agency_id: 0, - validated_at: '2023-12-03T21:47:29.460Z', - validated_by: 3, - ec_code: '1.4', - tenant_id: 1, - id: 'b4d22796-75a6-4ac3-95f4-0d07f1e12f3e', - notes: - 'This is to test two things. First, EC1.4 wording. Second, The Audit Report pulling the correct data.', - invalidated_at: null, - invalidated_by: null, - created_by: 'joecomeau01@gmail.com', - agency_code: 'USDR', - }, - { - filename: 'NEW 10002 - DHS - EC2_32 - v202306016 - CLEAN (1).xlsm', - created_at: '2023-12-01T19:19:21.458Z', - reporting_period_id: 6, - user_id: 983, - agency_id: 0, - validated_at: '2023-12-01T19:19:25.255Z', - validated_by: 983, - ec_code: '2.32', - tenant_id: 1, - id: '322f925a-5f4f-4313-a730-a0067217100d', - notes: null, - invalidated_at: null, - invalidated_by: null, - created_by: 'asridhar+staff@usdigitalresponse.org', - agency_code: 'USDR', - }, - ] - - return ( - - - - - - - - - - - - - - {uploads.map((upload) => ( - - - - - - - - - - ))} - -
IDAgencyEC CodeUploaded ByFilenameNotesValidated?
{truncate(upload.id)} - {truncate(upload.agency_code)} - {upload.ec_code}{upload.created_by} - {upload.filename}{' '} - {/* TODO: Implement file download when the API is ready */} - {/* */} - {upload.notes}{upload.invalidated_at}
- ) -} - -export default MyUploadsList diff --git a/web/src/components/Upload/Uploads/Uploads.tsx b/web/src/components/Upload/Uploads/Uploads.tsx index 812ace72..2ec809cc 100644 --- a/web/src/components/Upload/Uploads/Uploads.tsx +++ b/web/src/components/Upload/Uploads/Uploads.tsx @@ -1,100 +1,56 @@ -import { Link, routes } from '@redwoodjs/router' -import { useMutation } from '@redwoodjs/web' -import { toast } from '@redwoodjs/web/toast' - -import { QUERY } from 'src/components/Upload/UploadsCell' -import { timeTag, truncate } from 'src/lib/formatters' +import Table from 'react-bootstrap/Table' +import type { FindUploads } from 'types/graphql' -import type { DeleteUploadMutationVariables, FindUploads } from 'types/graphql' +import { Link, routes } from '@redwoodjs/router' -const DELETE_UPLOAD_MUTATION = gql` - mutation DeleteUploadMutation($id: Int!) { - deleteUpload(id: $id) { - id - } - } -` +import { truncate } from 'src/lib/formatters' const UploadsList = ({ uploads }: FindUploads) => { - const [deleteUpload] = useMutation(DELETE_UPLOAD_MUTATION, { - onCompleted: () => { - toast.success('Upload deleted') - }, - onError: (error) => { - toast.error(error.message) - }, - // This refetches the query on the list page. Read more about other ways to - // update the cache over here: - // https://www.apollographql.com/docs/react/data/mutations/#making-all-other-cache-updates - refetchQueries: [{ query: QUERY }], - awaitRefetchQueries: true, - }) - - const onDeleteClick = (id: DeleteUploadMutationVariables['id']) => { - if (confirm('Are you sure you want to delete upload ' + id + '?')) { - deleteUpload({ variables: { id } }) - } - } - return ( -
- +
+
- - - - - - - - - - + + + + + + {uploads.map((upload) => ( - - - - - - - - - - + + + + + ))} -
IdFilenameUploaded by idAgency idOrganization idReporting period idExpenditure category idCreated atUpdated at IdAgencyEC CodeUploaded ByFilenameValidated?
{truncate(upload.id)}{truncate(upload.filename)}{truncate(upload.uploadedById)}{truncate(upload.agencyId)}{truncate(upload.organizationId)}{truncate(upload.reportingPeriodId)}{truncate(upload.expenditureCategoryId)}{timeTag(upload.createdAt)}{timeTag(upload.updatedAt)} - + + + {upload.id} + + + {truncate(upload.agency.name)} + + {truncate(upload.expenditureCategory.code)} + + {truncate(upload.uploadedBy.email)} + + {upload.filename}{' '} + {/* TODO: Add file download when the API is ready */} + {/* */} Validation here!
+
) } diff --git a/web/src/components/Upload/UploadsCell/UploadsCell.tsx b/web/src/components/Upload/UploadsCell/UploadsCell.tsx index 5c6aaee0..da804a5d 100644 --- a/web/src/components/Upload/UploadsCell/UploadsCell.tsx +++ b/web/src/components/Upload/UploadsCell/UploadsCell.tsx @@ -10,11 +10,21 @@ export const QUERY = gql` uploads { id filename - uploadedById - agencyId + uploadedBy { + id + email + } + agency { + id + name + } organizationId reportingPeriodId - expenditureCategoryId + expenditureCategory { + id + name + code + } createdAt updatedAt } diff --git a/web/src/pages/DashboardPage/DashboardPage.stories.tsx b/web/src/pages/DashboardPage/DashboardPage.stories.tsx deleted file mode 100644 index af6a7a4d..00000000 --- a/web/src/pages/DashboardPage/DashboardPage.stories.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react' - -import DashboardPage from './DashboardPage' - -const meta: Meta = { - component: DashboardPage, -} - -export default meta - -type Story = StoryObj - -export const Primary: Story = {} diff --git a/web/src/pages/DashboardPage/DashboardPage.test.tsx b/web/src/pages/DashboardPage/DashboardPage.test.tsx deleted file mode 100644 index b6d9d375..00000000 --- a/web/src/pages/DashboardPage/DashboardPage.test.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { render } from '@redwoodjs/testing/web' - -import DashboardPage from './DashboardPage' - -// Improve this test with help from the Redwood Testing Doc: -// https://redwoodjs.com/docs/testing#testing-pages-layouts - -describe('DashboardPage', () => { - it('renders successfully', () => { - expect(() => { - render() - }).not.toThrow() - }) -}) diff --git a/web/src/pages/DashboardPage/DashboardPage.tsx b/web/src/pages/DashboardPage/DashboardPage.tsx deleted file mode 100644 index 8feee626..00000000 --- a/web/src/pages/DashboardPage/DashboardPage.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { Button, ButtonGroup } from 'react-bootstrap' - -import { Link, routes } from '@redwoodjs/router' -import { MetaTags } from '@redwoodjs/web' - -import MyUploadsList from '../../components/MyUpload/MyUploads' // Import the MyUploadsList component - -const DashboardPage = () => { - return ( - <> - - -

Uploads

- {/*

- My default route is named dashboard, link to me with ` - Dashboard` -

*/} - - {/* - - - - - - - - - - */} - - - - - - - - - - - - ) -} - -export default DashboardPage diff --git a/web/src/pages/Upload/UploadsPage/UploadsPage.tsx b/web/src/pages/Upload/UploadsPage/UploadsPage.tsx index 8ee63d5d..284ab140 100644 --- a/web/src/pages/Upload/UploadsPage/UploadsPage.tsx +++ b/web/src/pages/Upload/UploadsPage/UploadsPage.tsx @@ -1,7 +1,31 @@ +import { Button, ButtonGroup } from 'react-bootstrap' + +import { MetaTags } from '@redwoodjs/web' + import UploadsCell from 'src/components/Upload/UploadsCell' const UploadsPage = () => { - return + return ( + <> + + +

Uploads

+ + + + + + + + + + ) } export default UploadsPage diff --git a/web/src/scaffold.css b/web/src/scaffold.css deleted file mode 100644 index 3a6a2155..00000000 --- a/web/src/scaffold.css +++ /dev/null @@ -1,397 +0,0 @@ -/* - normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css -*/ - -.rw-scaffold *, -.rw-scaffold ::after, -.rw-scaffold ::before { - box-sizing: inherit; -} -.rw-scaffold main { - color: #4a5568; - display: block; -} -.rw-scaffold h1, -.rw-scaffold h2 { - margin: 0; -} -.rw-scaffold a { - background-color: transparent; -} -.rw-scaffold ul { - margin: 0; - padding: 0; -} -.rw-scaffold input { - font-family: inherit; - font-size: 100%; - overflow: visible; -} -.rw-scaffold input:-ms-input-placeholder { - color: #a0aec0; -} -.rw-scaffold input::-ms-input-placeholder { - color: #a0aec0; -} -.rw-scaffold input::placeholder { - color: #a0aec0; -} -.rw-scaffold table { - border-collapse: collapse; -} - -/* - Style -*/ - -.rw-scaffold, -.rw-toast { - background-color: #fff; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, - 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', - 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; -} -.rw-header { - display: flex; - justify-content: space-between; - padding: 1rem 2rem 1rem 2rem; -} -.rw-main { - margin-left: 1rem; - margin-right: 1rem; - padding-bottom: 1rem; -} -.rw-segment { - border-radius: 0.5rem; - border-width: 1px; - border-color: #e5e7eb; - overflow: hidden; - width: 100%; - scrollbar-color: #a1a1aa transparent; -} -.rw-segment::-webkit-scrollbar { - height: initial; -} -.rw-segment::-webkit-scrollbar-track { - background-color: transparent; - border-color: #e2e8f0; - border-style: solid; - border-radius: 0 0 10px 10px; - border-width: 1px 0 0 0; - padding: 2px; -} -.rw-segment::-webkit-scrollbar-thumb { - background-color: #a1a1aa; - background-clip: content-box; - border: 3px solid transparent; - border-radius: 10px; -} -.rw-segment-header { - background-color: #e2e8f0; - color: #4a5568; - padding: 0.75rem 1rem; -} -.rw-segment-main { - background-color: #f7fafc; - padding: 1rem; -} -.rw-link { - color: #4299e1; - text-decoration: underline; -} -.rw-link:hover { - color: #2b6cb0; -} -.rw-forgot-link { - font-size: 0.75rem; - color: #a0aec0; - text-align: right; - margin-top: 0.1rem; -} -.rw-forgot-link:hover { - font-size: 0.75rem; - color: #4299e1; -} -.rw-heading { - font-weight: 600; -} -.rw-heading.rw-heading-primary { - font-size: 1.25rem; -} -.rw-heading.rw-heading-secondary { - font-size: 0.875rem; -} -.rw-heading .rw-link { - color: #4a5568; - text-decoration: none; -} -.rw-heading .rw-link:hover { - color: #1a202c; - text-decoration: underline; -} -.rw-cell-error { - font-size: 90%; - font-weight: 600; -} -.rw-form-wrapper { - box-sizing: border-box; - font-size: 0.875rem; - margin-top: -1rem; -} -.rw-cell-error, -.rw-form-error-wrapper { - padding: 1rem; - background-color: #fff5f5; - color: #c53030; - border-width: 1px; - border-color: #feb2b2; - border-radius: 0.25rem; - margin: 1rem 0; -} -.rw-form-error-title { - margin-top: 0; - margin-bottom: 0; - font-weight: 600; -} -.rw-form-error-list { - margin-top: 0.5rem; - list-style-type: disc; - list-style-position: inside; -} -.rw-button { - border: none; - color: #718096; - cursor: pointer; - display: flex; - justify-content: center; - font-size: 0.75rem; - font-weight: 600; - padding: 0.25rem 1rem; - text-transform: uppercase; - text-decoration: none; - letter-spacing: 0.025em; - border-radius: 0.25rem; - line-height: 2; - border: 0; -} -.rw-button:hover { - background-color: #718096; - color: #fff; -} -.rw-button.rw-button-small { - font-size: 0.75rem; - border-radius: 0.125rem; - padding: 0.25rem 0.5rem; - line-height: inherit; -} -.rw-button.rw-button-green { - background-color: #48bb78; - color: #fff; -} -.rw-button.rw-button-green:hover { - background-color: #38a169; - color: #fff; -} -.rw-button.rw-button-blue { - background-color: #3182ce; - color: #fff; -} -.rw-button.rw-button-blue:hover { - background-color: #2b6cb0; -} -.rw-button.rw-button-red { - background-color: #e53e3e; - color: #fff; -} -.rw-button.rw-button-red:hover { - background-color: #c53030; -} -.rw-button-icon { - font-size: 1.25rem; - line-height: 1; - margin-right: 0.25rem; -} -.rw-button-group { - display: flex; - justify-content: center; - margin: 0.75rem 0.5rem; -} -.rw-button-group .rw-button { - margin: 0 0.25rem; -} -.rw-form-wrapper .rw-button-group { - margin-top: 2rem; - margin-bottom: 0; -} -.rw-label { - display: block; - margin-top: 1.5rem; - color: #4a5568; - font-weight: 600; - text-align: left; -} -.rw-label.rw-label-error { - color: #c53030; -} -.rw-input { - display: block; - margin-top: 0.5rem; - width: 100%; - padding: 0.5rem; - border-width: 1px; - border-style: solid; - border-color: #e2e8f0; - color: #4a5568; - border-radius: 0.25rem; - outline: none; -} -.rw-check-radio-item-none { - color: #4a5568; -} -.rw-check-radio-items { - display: flex; - justify-items: center; -} -.rw-input[type='checkbox'] { - display: inline; - width: 1rem; - margin-left: 0; - margin-right: 0.5rem; - margin-top: 0.25rem; -} -.rw-input[type='radio'] { - display: inline; - width: 1rem; - margin-left: 0; - margin-right: 0.5rem; - margin-top: 0.25rem; -} -.rw-input:focus { - border-color: #a0aec0; -} -.rw-input-error { - border-color: #c53030; - color: #c53030; -} - -.rw-input-error:focus { - outline: none; - border-color: #c53030; - box-shadow: 0 0 5px #c53030; -} - -.rw-field-error { - display: block; - margin-top: 0.25rem; - font-weight: 600; - text-transform: uppercase; - font-size: 0.75rem; - color: #c53030; -} -.rw-table-wrapper-responsive { - overflow-x: auto; -} -.rw-table-wrapper-responsive .rw-table { - min-width: 48rem; -} -.rw-table { - table-layout: auto; - width: 100%; - font-size: 0.875rem; -} -.rw-table th, -.rw-table td { - padding: 0.75rem; -} -.rw-table td { - background-color: #ffffff; - color: #1a202c; -} -.rw-table tr:nth-child(odd) td, -.rw-table tr:nth-child(odd) th { - background-color: #f7fafc; -} -.rw-table thead tr { - color: #4a5568; -} -.rw-table th { - font-weight: 600; - text-align: left; -} -.rw-table thead th { - background-color: #e2e8f0; - text-align: left; -} -.rw-table tbody th { - text-align: right; -} -@media (min-width: 768px) { - .rw-table tbody th { - width: 20%; - } -} -.rw-table tbody tr { - border-top-width: 1px; -} -.rw-table input { - margin-left: 0; -} -.rw-table-actions { - display: flex; - justify-content: flex-end; - align-items: center; - height: 17px; - padding-right: 0.25rem; -} -.rw-table-actions .rw-button { - background-color: transparent; -} -.rw-table-actions .rw-button:hover { - background-color: #718096; - color: #fff; -} -.rw-table-actions .rw-button-blue { - color: #3182ce; -} -.rw-table-actions .rw-button-blue:hover { - background-color: #3182ce; - color: #fff; -} -.rw-table-actions .rw-button-red { - color: #e53e3e; -} -.rw-table-actions .rw-button-red:hover { - background-color: #e53e3e; - color: #fff; -} -.rw-text-center { - text-align: center; -} -.rw-login-container { - display: flex; - align-items: center; - justify-content: center; - width: 24rem; - margin: 4rem auto; - flex-wrap: wrap; -} -.rw-login-container .rw-form-wrapper { - width: 100%; - text-align: center; -} -.rw-login-link { - margin-top: 1rem; - color: #4a5568; - font-size: 90%; - text-align: center; - flex-basis: 100%; -} -.rw-webauthn-wrapper { - margin: 1.5rem 1rem 1rem; - line-height: 1.4; -} -.rw-webauthn-wrapper h2 { - font-size: 150%; - font-weight: bold; - margin-bottom: 1rem; -} diff --git a/web/src/scss/custom.scss b/web/src/scss/custom.scss index bc65fc96..dee7b232 100644 --- a/web/src/scss/custom.scss +++ b/web/src/scss/custom.scss @@ -68,4 +68,6 @@ span.invalid-feedback { @import '~bootstrap/scss/bootstrap'; // SET USDR FONTS -@import './fonts.scss'; \ No newline at end of file +@import './fonts.scss'; + +@import './tables.scss'; \ No newline at end of file diff --git a/web/src/scss/tables.scss b/web/src/scss/tables.scss new file mode 100644 index 00000000..e69de29b diff --git a/web/types/graphql.d.ts b/web/types/graphql.d.ts index e00759a4..5f4eb52d 100644 --- a/web/types/graphql.d.ts +++ b/web/types/graphql.d.ts @@ -740,4 +740,4 @@ export type FindUploadById = { __typename?: 'Query', upload?: { __typename?: 'Up export type FindUploadsVariables = Exact<{ [key: string]: never; }>; -export type FindUploads = { __typename?: 'Query', uploads: Array<{ __typename?: 'Upload', id: number, filename: string, uploadedById: number, agencyId: number, organizationId: number, reportingPeriodId: number, expenditureCategoryId: number, createdAt: string, updatedAt: string }> }; +export type FindUploads = { __typename?: 'Query', uploads: Array<{ __typename?: 'Upload', id: number, filename: string, organizationId: number, reportingPeriodId: number, createdAt: string, updatedAt: string, uploadedBy: { __typename?: 'User', id: number, email: string }, agency: { __typename?: 'Agency', id: number, name: string }, expenditureCategory: { __typename?: 'ExpenditureCategory', id: number, name: string, code: string } }> }; From 0f04827ef657189a2ad311da3657b3bd0c2c6516 Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Mon, 11 Dec 2023 17:55:29 -0500 Subject: [PATCH 04/11] feature/CPF-3 add sorting to columns --- package-lock.json | 1125 +++++++++++++++-- package.json | 1 + web/src/components/Upload/Uploads/Uploads.tsx | 135 +- .../Upload/UploadsCell/UploadsCell.tsx | 2 +- web/types/graphql.d.ts | 2 +- yarn.lock | 542 ++++---- 6 files changed, 1418 insertions(+), 389 deletions(-) diff --git a/package-lock.json b/package-lock.json index da142a44..4d359589 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,8 +30,11 @@ "dependencies": { "@aws-sdk/client-ssm": "^3.462.0", "@aws-sdk/rds-signer": "^3.462.0", + "@opentelemetry/instrumentation": "^0.45.1", + "@prisma/instrumentation": "^5.7.0", "@redwoodjs/api": "6.4.2", - "@redwoodjs/graphql-server": "6.4.2" + "@redwoodjs/graphql-server": "6.4.2", + "dd-trace": "^4.20.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3169,6 +3172,164 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@datadog/browser-core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@datadog/browser-core/-/browser-core-5.5.0.tgz", + "integrity": "sha512-orkbetqiXBrF3r9/WImwJG32tEtNjx2hfP7cyBvPw5qhdjOHkl87IdrKqELaadIAc7Tjgmn38TWccSmcRa1rVw==" + }, + "node_modules/@datadog/browser-rum": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@datadog/browser-rum/-/browser-rum-5.5.0.tgz", + "integrity": "sha512-nsK9hrD4yuyiSJ2B+R0KVeb61Xj4rwVIIF6mGsNYIaX4sN51Qw/lz5GkOca3YwskS0zMoyicjEWKFZnzq5Q7ew==", + "dependencies": { + "@datadog/browser-core": "5.5.0", + "@datadog/browser-rum-core": "5.5.0" + }, + "peerDependencies": { + "@datadog/browser-logs": "5.5.0" + }, + "peerDependenciesMeta": { + "@datadog/browser-logs": { + "optional": true + } + } + }, + "node_modules/@datadog/browser-rum-core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@datadog/browser-rum-core/-/browser-rum-core-5.5.0.tgz", + "integrity": "sha512-VWI91gwKYTGMycpN5a8kgJ/YCdcnvYAhU2uk6HbTLNg2xj4368FyOdSFOQgQzBvmM323AFS+G0v5u+eQgtNgfQ==", + "dependencies": { + "@datadog/browser-core": "5.5.0" + } + }, + "node_modules/@datadog/native-appsec": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@datadog/native-appsec/-/native-appsec-4.0.0.tgz", + "integrity": "sha512-myTguXJ3VQHS2E1ylNsSF1avNpDmq5t+K4Q47wdzeakGc3sDIDDyEbvuFTujl9c9wBIkup94O1mZj5DR37ajzA==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^3.9.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@datadog/native-appsec/node_modules/node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/@datadog/native-iast-rewriter": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@datadog/native-iast-rewriter/-/native-iast-rewriter-2.2.1.tgz", + "integrity": "sha512-DyZlE8gNa5AoOFNKGRJU4RYF/Y/tJzv4bIAMuVBbEnMA0xhiIYqpYQG8T3OKkALl3VSEeBMjYwuOR2fCrJ6gzA==", + "dependencies": { + "lru-cache": "^7.14.0", + "node-gyp-build": "^4.5.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@datadog/native-iast-rewriter/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/@datadog/native-iast-taint-tracking": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@datadog/native-iast-taint-tracking/-/native-iast-taint-tracking-1.6.4.tgz", + "integrity": "sha512-Owxk7hQ4Dxwv4zJAoMjRga0IvE6lhvxnNc8pJCHsemCWBXchjr/9bqg05Zy5JnMbKUWn4XuZeJD6RFZpRa8bfw==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^3.9.0" + } + }, + "node_modules/@datadog/native-iast-taint-tracking/node_modules/node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/@datadog/native-metrics": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@datadog/native-metrics/-/native-metrics-2.0.0.tgz", + "integrity": "sha512-YklGVwUtmKGYqFf1MNZuOHvTYdKuR4+Af1XkWcMD8BwOAjxmd9Z+97328rCOY8TFUJzlGUPaXzB8j2qgG/BMwA==", + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^6.1.0", + "node-gyp-build": "^3.9.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@datadog/native-metrics/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" + }, + "node_modules/@datadog/native-metrics/node_modules/node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/@datadog/pprof": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@datadog/pprof/-/pprof-4.0.1.tgz", + "integrity": "sha512-TavqyiyQZOaUM9eQB07r8+K/T1CqKyOdsUGxpN79+BF+eOQBpTj/Cte6KdlhcUSKL3h5hSjC+vlgA7uW2qtVhA==", + "hasInstallScript": true, + "dependencies": { + "delay": "^5.0.0", + "node-gyp-build": "<4.0", + "p-limit": "^3.1.0", + "pprof-format": "^2.0.7", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@datadog/pprof/node_modules/node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/@datadog/pprof/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@datadog/sketches-js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@datadog/sketches-js/-/sketches-js-2.1.0.tgz", + "integrity": "sha512-smLocSfrt3s53H/XSVP3/1kP42oqvrkjUPtyaFd1F79ux24oE31BKt+q0c6lsa6hOYrFzsIwyc5GXAI5JmfOew==" + }, "node_modules/@dependents/detective-less": { "version": "4.1.0", "dev": true, @@ -5661,7 +5822,6 @@ }, "node_modules/@opentelemetry/core": { "version": "1.15.2", - "dev": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "1.15.2" @@ -5691,6 +5851,24 @@ "@opentelemetry/api": "^1.0.0" } }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.45.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.45.1.tgz", + "integrity": "sha512-V1Cr0g8hSg35lpW3G/GYVZurrhHrQZJdmP68WyJ83f1FDn3iru+/Vnlto9kiOSm7PHhW+pZGdb9Fbv+mkQ31CA==", + "dependencies": { + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "1.4.2", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, "node_modules/@opentelemetry/otlp-exporter-base": { "version": "0.41.2", "dev": true, @@ -5836,7 +6014,6 @@ }, "node_modules/@opentelemetry/semantic-conventions": { "version": "1.15.2", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=14" @@ -6182,6 +6359,77 @@ "ts-pattern": "5.0.5" } }, + "node_modules/@prisma/instrumentation": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-5.7.0.tgz", + "integrity": "sha512-zNTC7m2bscSwtYOzWe4pg6DQC2YS5wu+ch/GqTkfh1D0x7Ys3KRw7cdg4Etpbk4yfB1Y/fL6gMswtBcImRiC7A==", + "dependencies": { + "@opentelemetry/api": "1.7.0", + "@opentelemetry/instrumentation": "0.45.1", + "@opentelemetry/sdk-trace-base": "1.18.1" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/api": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz", + "integrity": "sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/core": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.18.1.tgz", + "integrity": "sha512-kvnUqezHMhsQvdsnhnqTNfAJs3ox/isB0SVrM1dhVFw7SsB7TstuVa6fgWnN2GdPyilIFLUvvbTZoVRmx6eiRg==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.18.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/resources": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.18.1.tgz", + "integrity": "sha512-JjbcQLYMttXcIabflLRuaw5oof5gToYV9fuXbcsoOeQ0BlbwUn6DAZi++PNsSz2jjPeASfDls10iaO/8BRIPRA==", + "dependencies": { + "@opentelemetry/core": "1.18.1", + "@opentelemetry/semantic-conventions": "1.18.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.18.1.tgz", + "integrity": "sha512-tRHfDxN5dO+nop78EWJpzZwHsN1ewrZRVVwo03VJa3JQZxToRDH29/+MB24+yoa+IArerdr7INFJiX/iN4gjqg==", + "dependencies": { + "@opentelemetry/core": "1.18.1", + "@opentelemetry/resources": "1.18.1", + "@opentelemetry/semantic-conventions": "1.18.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.18.1.tgz", + "integrity": "sha512-+NLGHr6VZwcgE/2lw8zDIufOCGnzsA5CbQIMleXZTrgkBd0TanCX+MiDYJ1TOS4KL/Tqk0nFRxawnaYr6pkZkA==", + "engines": { + "node": ">=14" + } + }, "node_modules/@prisma/internals": { "version": "5.6.0", "dev": true, @@ -6295,6 +6543,60 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "node_modules/@reach/polymorphic": { "version": "0.18.0", "license": "MIT", @@ -8741,7 +9043,6 @@ }, "node_modules/@types/node": { "version": "20.10.4", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -8876,6 +9177,11 @@ "@types/node": "*" } }, + "node_modules/@types/shimmer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.0.5.tgz", + "integrity": "sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==" + }, "node_modules/@types/sockjs": { "version": "0.3.36", "dev": true, @@ -9633,7 +9939,6 @@ }, "node_modules/acorn": { "version": "8.11.2", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -9653,7 +9958,6 @@ }, "node_modules/acorn-import-assertions": { "version": "1.9.0", - "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^8" @@ -12297,7 +12601,6 @@ }, "node_modules/cjs-module-lexer": { "version": "1.2.3", - "dev": true, "license": "MIT" }, "node_modules/class-utils": { @@ -13234,6 +13537,11 @@ "node": ">=8" } }, + "node_modules/crypto-randomuuid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-randomuuid/-/crypto-randomuuid-1.0.0.tgz", + "integrity": "sha512-/RC5F4l1SCqD/jazwUF6+t34Cd8zTSAGZ7rvvZu1whZUhD2a5MOGKjSGowoGcpj/cbVZk1ZODIooJEQQq3nNAA==" + }, "node_modules/css-declaration-sorter": { "version": "6.4.1", "dev": true, @@ -13564,6 +13872,87 @@ "url": "https://opencollective.com/date-fns" } }, + "node_modules/dc-polyfill": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/dc-polyfill/-/dc-polyfill-0.1.3.tgz", + "integrity": "sha512-Wyk5n/5KUj3GfVKV2jtDbtChC/Ff9fjKsBcg4ZtYW1yQe3DXNHcGURvmoxhqQdfOQ9TwyMjnfyv1lyYcOkFkFA==", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/dd-trace": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/dd-trace/-/dd-trace-4.20.0.tgz", + "integrity": "sha512-y7IDLSSt6nww6zMdw/I8oLdfgOQADIOkERCNdfSzlBrXHz5CHimEOFfsHN87ag0mn6vusr06aoi+CQRZSNJz2g==", + "hasInstallScript": true, + "dependencies": { + "@datadog/native-appsec": "4.0.0", + "@datadog/native-iast-rewriter": "2.2.1", + "@datadog/native-iast-taint-tracking": "1.6.4", + "@datadog/native-metrics": "^2.0.0", + "@datadog/pprof": "4.0.1", + "@datadog/sketches-js": "^2.1.0", + "@opentelemetry/api": "^1.0.0", + "@opentelemetry/core": "^1.14.0", + "crypto-randomuuid": "^1.0.0", + "dc-polyfill": "^0.1.2", + "ignore": "^5.2.4", + "import-in-the-middle": "^1.4.2", + "int64-buffer": "^0.1.9", + "ipaddr.js": "^2.1.0", + "istanbul-lib-coverage": "3.2.0", + "jest-docblock": "^29.7.0", + "koalas": "^1.0.2", + "limiter": "^1.1.4", + "lodash.kebabcase": "^4.1.1", + "lodash.pick": "^4.4.0", + "lodash.sortby": "^4.7.0", + "lodash.uniq": "^4.5.0", + "lru-cache": "^7.14.0", + "methods": "^1.1.2", + "module-details-from-path": "^1.0.3", + "msgpack-lite": "^0.1.26", + "node-abort-controller": "^3.1.1", + "opentracing": ">=0.12.1", + "path-to-regexp": "^0.1.2", + "pprof-format": "^2.0.7", + "protobufjs": "^7.2.4", + "retry": "^0.13.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/dd-trace/node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/dd-trace/node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dd-trace/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/dd-trace/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, "node_modules/debounce": { "version": "1.2.1", "dev": true, @@ -13571,7 +13960,6 @@ }, "node_modules/debug": { "version": "4.3.4", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -13587,7 +13975,6 @@ }, "node_modules/debug/node_modules/ms": { "version": "2.1.2", - "dev": true, "license": "MIT" }, "node_modules/decamelize": { @@ -13800,6 +14187,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "dev": true, @@ -13872,7 +14270,6 @@ }, "node_modules/detect-newline": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -15255,6 +15652,11 @@ "node": ">= 0.6" } }, + "node_modules/event-lite": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.3.tgz", + "integrity": "sha512-8qz9nOz5VeD2z96elrEKD2U433+L3DWdUdDkOINLGOJvx1GsMBbMn0aCeu28y8/e85A6mCigBiFlYMnTBEGlSw==" + }, "node_modules/event-target-shim": { "version": "5.0.1", "license": "MIT", @@ -16252,7 +16654,6 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -17035,9 +17436,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/hasha/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/hasown": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -17397,7 +17806,6 @@ }, "node_modules/ignore": { "version": "5.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -17472,6 +17880,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-in-the-middle": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.4.2.tgz", + "integrity": "sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==", + "dependencies": { + "acorn": "^8.8.2", + "acorn-import-assertions": "^1.9.0", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "node_modules/import-local": { "version": "3.1.0", "dev": true, @@ -17571,6 +17990,11 @@ "node": ">=8" } }, + "node_modules/int64-buffer": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.1.10.tgz", + "integrity": "sha512-v7cSY1J8ydZ0GyjUHqF+1bshJ6cnEVLo9EnjB8p+4HDRPZc9N5jjmvUV7NvEsqQOKyH0pmIBFWXVQbiS0+OBbA==" + }, "node_modules/internal-slot": { "version": "1.0.6", "dev": true, @@ -17732,7 +18156,6 @@ }, "node_modules/is-core-module": { "version": "2.13.1", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.0" @@ -18177,7 +18600,6 @@ }, "node_modules/isarray": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/isexe": { @@ -18486,7 +18908,6 @@ }, "node_modules/jest-docblock": { "version": "29.7.0", - "dev": true, "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" @@ -18957,17 +19378,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/jest-watch-typeahead/node_modules/type-fest": { - "version": "3.13.1", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-watcher": { "version": "29.7.0", "dev": true, @@ -19344,6 +19754,14 @@ "node": ">=6" } }, + "node_modules/koalas": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/koalas/-/koalas-1.0.2.tgz", + "integrity": "sha512-RYhBbYaTTTHId3l6fnMZc3eGQNW6FVCqMG6AMwA5I1Mafr6AflaXeoi6x3xQuATRotGYRLk6+1ELZH4dstFNOA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "dev": true, @@ -19431,6 +19849,11 @@ "node": ">=10" } }, + "node_modules/limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, "node_modules/line-column": { "version": "1.0.2", "dev": true, @@ -19636,6 +20059,11 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "dev": true, @@ -19651,9 +20079,18 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, "node_modules/lodash.uniq": { "version": "4.5.0", - "dev": true, "license": "MIT" }, "node_modules/log-symbols": { @@ -19801,6 +20238,11 @@ "dev": true, "license": "MIT" }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, "node_modules/loose-envify": { "version": "1.4.0", "license": "MIT", @@ -19997,7 +20439,6 @@ }, "node_modules/methods": { "version": "1.1.2", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -20240,6 +20681,11 @@ "node": ">=14" } }, + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" + }, "node_modules/module-not-found-error": { "version": "1.0.1", "dev": true, @@ -20281,6 +20727,20 @@ "version": "2.1.3", "license": "MIT" }, + "node_modules/msgpack-lite": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/msgpack-lite/-/msgpack-lite-0.1.26.tgz", + "integrity": "sha512-SZ2IxeqZ1oRFGo0xFGbvBJWMp3yLIY9rlIJyxy8CGrwZn1f0ZK4r6jV/AM1r0FZMDUkWkglOk/eeKIL9g77Nxw==", + "dependencies": { + "event-lite": "^0.1.1", + "ieee754": "^1.1.8", + "int64-buffer": "^0.1.9", + "isarray": "^1.0.0" + }, + "bin": { + "msgpack": "bin/msgpack" + } + }, "node_modules/msw": { "version": "1.3.2", "dev": true, @@ -20514,6 +20974,11 @@ "tslib": "^2.0.3" } }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" + }, "node_modules/node-addon-api": { "version": "7.0.0", "dev": true, @@ -20548,7 +21013,6 @@ }, "node_modules/node-gyp-build": { "version": "4.7.1", - "dev": true, "license": "MIT", "bin": { "node-gyp-build": "bin.js", @@ -21140,6 +21604,14 @@ "opener": "bin/opener-bin.js" } }, + "node_modules/opentracing": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz", + "integrity": "sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/optimism": { "version": "0.17.5", "license": "MIT", @@ -21248,7 +21720,6 @@ }, "node_modules/p-limit": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -21262,7 +21733,6 @@ }, "node_modules/p-limit/node_modules/yocto-queue": { "version": "0.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -21564,7 +22034,6 @@ }, "node_modules/path-parse": { "version": "1.0.7", - "dev": true, "license": "MIT" }, "node_modules/path-root": { @@ -22371,6 +22840,11 @@ "postcss": "^8.2.9" } }, + "node_modules/pprof-format": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/pprof-format/-/pprof-format-2.0.7.tgz", + "integrity": "sha512-1qWaGAzwMpaXJP9opRa23nPnt2Egi7RMNoNBptEE/XwHbcn4fC2b/4U4bKc5arkGkIh2ZabpF2bEb+c5GNHEKA==" + }, "node_modules/precinct": { "version": "11.0.5", "dev": true, @@ -22596,6 +23070,29 @@ "react": ">=0.14.0" } }, + "node_modules/protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "dev": true, @@ -23007,6 +23504,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/read-pkg/node_modules/type-fest": { "version": "0.6.0", "dev": true, @@ -23419,6 +23925,19 @@ "node": ">=0.10.0" } }, + "node_modules/require-in-the-middle": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.2.0.tgz", + "integrity": "sha512-3TLx5TGyAY6AOqLBoXmHkNql0HIf2RGbuMgCDT2WO/uGVAPJs6h7Kl+bN6TIZGd9bWhWPwnDnTHGtW8Iu77sdw==", + "dependencies": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/require-main-filename": { "version": "2.0.0", "dev": true, @@ -23449,7 +23968,6 @@ }, "node_modules/resolve": { "version": "1.22.8", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", @@ -23555,7 +24073,6 @@ }, "node_modules/retry": { "version": "0.13.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -24202,6 +24719,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, "node_modules/side-channel": { "version": "1.0.4", "dev": true, @@ -24984,7 +25506,6 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -25715,11 +26236,15 @@ } }, "node_modules/type-fest": { - "version": "0.8.1", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/type-is": { @@ -25881,7 +26406,6 @@ }, "node_modules/undici-types": { "version": "5.26.5", - "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -27497,6 +28021,7 @@ "web": { "version": "0.0.0", "dependencies": { + "@datadog/browser-rum": "^5.4.0", "@redwoodjs/forms": "6.4.2", "@redwoodjs/router": "6.4.2", "@redwoodjs/web": "6.4.2", @@ -27509,6 +28034,7 @@ }, "devDependencies": { "@redwoodjs/vite": "6.4.2", + "@types/node": "^20.10.4", "@types/react": "18.2.39", "@types/react-dom": "18.2.17", "autoprefixer": "^10.4.16", @@ -29578,6 +30104,124 @@ } } }, + "@datadog/browser-core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@datadog/browser-core/-/browser-core-5.5.0.tgz", + "integrity": "sha512-orkbetqiXBrF3r9/WImwJG32tEtNjx2hfP7cyBvPw5qhdjOHkl87IdrKqELaadIAc7Tjgmn38TWccSmcRa1rVw==" + }, + "@datadog/browser-rum": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@datadog/browser-rum/-/browser-rum-5.5.0.tgz", + "integrity": "sha512-nsK9hrD4yuyiSJ2B+R0KVeb61Xj4rwVIIF6mGsNYIaX4sN51Qw/lz5GkOca3YwskS0zMoyicjEWKFZnzq5Q7ew==", + "requires": { + "@datadog/browser-core": "5.5.0", + "@datadog/browser-rum-core": "5.5.0" + } + }, + "@datadog/browser-rum-core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@datadog/browser-rum-core/-/browser-rum-core-5.5.0.tgz", + "integrity": "sha512-VWI91gwKYTGMycpN5a8kgJ/YCdcnvYAhU2uk6HbTLNg2xj4368FyOdSFOQgQzBvmM323AFS+G0v5u+eQgtNgfQ==", + "requires": { + "@datadog/browser-core": "5.5.0" + } + }, + "@datadog/native-appsec": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@datadog/native-appsec/-/native-appsec-4.0.0.tgz", + "integrity": "sha512-myTguXJ3VQHS2E1ylNsSF1avNpDmq5t+K4Q47wdzeakGc3sDIDDyEbvuFTujl9c9wBIkup94O1mZj5DR37ajzA==", + "requires": { + "node-gyp-build": "^3.9.0" + }, + "dependencies": { + "node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==" + } + } + }, + "@datadog/native-iast-rewriter": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@datadog/native-iast-rewriter/-/native-iast-rewriter-2.2.1.tgz", + "integrity": "sha512-DyZlE8gNa5AoOFNKGRJU4RYF/Y/tJzv4bIAMuVBbEnMA0xhiIYqpYQG8T3OKkALl3VSEeBMjYwuOR2fCrJ6gzA==", + "requires": { + "lru-cache": "^7.14.0", + "node-gyp-build": "^4.5.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + } + } + }, + "@datadog/native-iast-taint-tracking": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@datadog/native-iast-taint-tracking/-/native-iast-taint-tracking-1.6.4.tgz", + "integrity": "sha512-Owxk7hQ4Dxwv4zJAoMjRga0IvE6lhvxnNc8pJCHsemCWBXchjr/9bqg05Zy5JnMbKUWn4XuZeJD6RFZpRa8bfw==", + "requires": { + "node-gyp-build": "^3.9.0" + }, + "dependencies": { + "node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==" + } + } + }, + "@datadog/native-metrics": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@datadog/native-metrics/-/native-metrics-2.0.0.tgz", + "integrity": "sha512-YklGVwUtmKGYqFf1MNZuOHvTYdKuR4+Af1XkWcMD8BwOAjxmd9Z+97328rCOY8TFUJzlGUPaXzB8j2qgG/BMwA==", + "requires": { + "node-addon-api": "^6.1.0", + "node-gyp-build": "^3.9.0" + }, + "dependencies": { + "node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" + }, + "node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==" + } + } + }, + "@datadog/pprof": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@datadog/pprof/-/pprof-4.0.1.tgz", + "integrity": "sha512-TavqyiyQZOaUM9eQB07r8+K/T1CqKyOdsUGxpN79+BF+eOQBpTj/Cte6KdlhcUSKL3h5hSjC+vlgA7uW2qtVhA==", + "requires": { + "delay": "^5.0.0", + "node-gyp-build": "<4.0", + "p-limit": "^3.1.0", + "pprof-format": "^2.0.7", + "source-map": "^0.7.4" + }, + "dependencies": { + "node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==" + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" + } + } + }, + "@datadog/sketches-js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@datadog/sketches-js/-/sketches-js-2.1.0.tgz", + "integrity": "sha512-smLocSfrt3s53H/XSVP3/1kP42oqvrkjUPtyaFd1F79ux24oE31BKt+q0c6lsa6hOYrFzsIwyc5GXAI5JmfOew==" + }, "@dependents/detective-less": { "version": "4.1.0", "dev": true, @@ -31297,7 +31941,6 @@ }, "@opentelemetry/core": { "version": "1.15.2", - "dev": true, "requires": { "@opentelemetry/semantic-conventions": "1.15.2" } @@ -31313,6 +31956,18 @@ "@opentelemetry/sdk-trace-base": "1.15.2" } }, + "@opentelemetry/instrumentation": { + "version": "0.45.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.45.1.tgz", + "integrity": "sha512-V1Cr0g8hSg35lpW3G/GYVZurrhHrQZJdmP68WyJ83f1FDn3iru+/Vnlto9kiOSm7PHhW+pZGdb9Fbv+mkQ31CA==", + "requires": { + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "1.4.2", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + } + }, "@opentelemetry/otlp-exporter-base": { "version": "0.41.2", "dev": true, @@ -31393,8 +32048,7 @@ } }, "@opentelemetry/semantic-conventions": { - "version": "1.15.2", - "dev": true + "version": "1.15.2" }, "@parcel/watcher": { "version": "2.3.0", @@ -31601,6 +32255,55 @@ "ts-pattern": "5.0.5" } }, + "@prisma/instrumentation": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-5.7.0.tgz", + "integrity": "sha512-zNTC7m2bscSwtYOzWe4pg6DQC2YS5wu+ch/GqTkfh1D0x7Ys3KRw7cdg4Etpbk4yfB1Y/fL6gMswtBcImRiC7A==", + "requires": { + "@opentelemetry/api": "1.7.0", + "@opentelemetry/instrumentation": "0.45.1", + "@opentelemetry/sdk-trace-base": "1.18.1" + }, + "dependencies": { + "@opentelemetry/api": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz", + "integrity": "sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==" + }, + "@opentelemetry/core": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.18.1.tgz", + "integrity": "sha512-kvnUqezHMhsQvdsnhnqTNfAJs3ox/isB0SVrM1dhVFw7SsB7TstuVa6fgWnN2GdPyilIFLUvvbTZoVRmx6eiRg==", + "requires": { + "@opentelemetry/semantic-conventions": "1.18.1" + } + }, + "@opentelemetry/resources": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.18.1.tgz", + "integrity": "sha512-JjbcQLYMttXcIabflLRuaw5oof5gToYV9fuXbcsoOeQ0BlbwUn6DAZi++PNsSz2jjPeASfDls10iaO/8BRIPRA==", + "requires": { + "@opentelemetry/core": "1.18.1", + "@opentelemetry/semantic-conventions": "1.18.1" + } + }, + "@opentelemetry/sdk-trace-base": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.18.1.tgz", + "integrity": "sha512-tRHfDxN5dO+nop78EWJpzZwHsN1ewrZRVVwo03VJa3JQZxToRDH29/+MB24+yoa+IArerdr7INFJiX/iN4gjqg==", + "requires": { + "@opentelemetry/core": "1.18.1", + "@opentelemetry/resources": "1.18.1", + "@opentelemetry/semantic-conventions": "1.18.1" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.18.1.tgz", + "integrity": "sha512-+NLGHr6VZwcgE/2lw8zDIufOCGnzsA5CbQIMleXZTrgkBd0TanCX+MiDYJ1TOS4KL/Tqk0nFRxawnaYr6pkZkA==" + } + } + }, "@prisma/internals": { "version": "5.6.0", "dev": true, @@ -31685,6 +32388,60 @@ "version": "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee", "dev": true }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "@reach/polymorphic": { "version": "0.18.0", "requires": {} @@ -33434,7 +34191,6 @@ }, "@types/node": { "version": "20.10.4", - "dev": true, "requires": { "undici-types": "~5.26.4" } @@ -33555,6 +34311,11 @@ "@types/node": "*" } }, + "@types/shimmer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.0.5.tgz", + "integrity": "sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==" + }, "@types/sockjs": { "version": "0.3.36", "dev": true, @@ -34101,8 +34862,7 @@ } }, "acorn": { - "version": "8.11.2", - "dev": true + "version": "8.11.2" }, "acorn-globals": { "version": "7.0.1", @@ -34114,7 +34874,6 @@ }, "acorn-import-assertions": { "version": "1.9.0", - "dev": true, "requires": {} }, "acorn-jsx": { @@ -34248,8 +35007,11 @@ "requires": { "@aws-sdk/client-ssm": "^3.462.0", "@aws-sdk/rds-signer": "^3.462.0", + "@opentelemetry/instrumentation": "^0.45.1", + "@prisma/instrumentation": "^5.7.0", "@redwoodjs/api": "6.4.2", - "@redwoodjs/graphql-server": "6.4.2" + "@redwoodjs/graphql-server": "6.4.2", + "dd-trace": "^4.20.0" } }, "aproba": { @@ -35900,8 +36662,7 @@ } }, "cjs-module-lexer": { - "version": "1.2.3", - "dev": true + "version": "1.2.3" }, "class-utils": { "version": "0.3.6", @@ -36518,6 +37279,11 @@ "version": "2.0.0", "dev": true }, + "crypto-randomuuid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-randomuuid/-/crypto-randomuuid-1.0.0.tgz", + "integrity": "sha512-/RC5F4l1SCqD/jazwUF6+t34Cd8zTSAGZ7rvvZu1whZUhD2a5MOGKjSGowoGcpj/cbVZk1ZODIooJEQQq3nNAA==" + }, "css-declaration-sorter": { "version": "6.4.1", "dev": true, @@ -36717,20 +37483,85 @@ "@babel/runtime": "^7.21.0" } }, + "dc-polyfill": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/dc-polyfill/-/dc-polyfill-0.1.3.tgz", + "integrity": "sha512-Wyk5n/5KUj3GfVKV2jtDbtChC/Ff9fjKsBcg4ZtYW1yQe3DXNHcGURvmoxhqQdfOQ9TwyMjnfyv1lyYcOkFkFA==" + }, + "dd-trace": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/dd-trace/-/dd-trace-4.20.0.tgz", + "integrity": "sha512-y7IDLSSt6nww6zMdw/I8oLdfgOQADIOkERCNdfSzlBrXHz5CHimEOFfsHN87ag0mn6vusr06aoi+CQRZSNJz2g==", + "requires": { + "@datadog/native-appsec": "4.0.0", + "@datadog/native-iast-rewriter": "2.2.1", + "@datadog/native-iast-taint-tracking": "1.6.4", + "@datadog/native-metrics": "^2.0.0", + "@datadog/pprof": "4.0.1", + "@datadog/sketches-js": "^2.1.0", + "@opentelemetry/api": "^1.0.0", + "@opentelemetry/core": "^1.14.0", + "crypto-randomuuid": "^1.0.0", + "dc-polyfill": "^0.1.2", + "ignore": "^5.2.4", + "import-in-the-middle": "^1.4.2", + "int64-buffer": "^0.1.9", + "ipaddr.js": "^2.1.0", + "istanbul-lib-coverage": "3.2.0", + "jest-docblock": "^29.7.0", + "koalas": "^1.0.2", + "limiter": "^1.1.4", + "lodash.kebabcase": "^4.1.1", + "lodash.pick": "^4.4.0", + "lodash.sortby": "^4.7.0", + "lodash.uniq": "^4.5.0", + "lru-cache": "^7.14.0", + "methods": "^1.1.2", + "module-details-from-path": "^1.0.3", + "msgpack-lite": "^0.1.26", + "node-abort-controller": "^3.1.1", + "opentracing": ">=0.12.1", + "path-to-regexp": "^0.1.2", + "pprof-format": "^2.0.7", + "protobufjs": "^7.2.4", + "retry": "^0.13.1", + "semver": "^7.5.4" + }, + "dependencies": { + "ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==" + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==" + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + } + } + }, "debounce": { "version": "1.2.1", "dev": true }, "debug": { "version": "4.3.4", - "dev": true, "requires": { "ms": "2.1.2" }, "dependencies": { "ms": { - "version": "2.1.2", - "dev": true + "version": "2.1.2" } } }, @@ -36871,6 +37702,11 @@ "slash": "^3.0.0" } }, + "delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==" + }, "delayed-stream": { "version": "1.0.0", "dev": true @@ -36911,8 +37747,7 @@ "dev": true }, "detect-newline": { - "version": "3.1.0", - "dev": true + "version": "3.1.0" }, "detect-node": { "version": "2.1.0", @@ -37810,6 +38645,11 @@ "version": "1.8.1", "dev": true }, + "event-lite": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.3.tgz", + "integrity": "sha512-8qz9nOz5VeD2z96elrEKD2U433+L3DWdUdDkOINLGOJvx1GsMBbMn0aCeu28y8/e85A6mCigBiFlYMnTBEGlSw==" + }, "event-target-shim": { "version": "5.0.1" }, @@ -38507,8 +39347,7 @@ "version": "2.3.3" }, "function-bind": { - "version": "1.1.2", - "dev": true + "version": "1.1.2" }, "function.prototype.name": { "version": "1.1.6", @@ -38992,11 +39831,18 @@ "requires": { "is-stream": "^2.0.0", "type-fest": "^0.8.0" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } } }, "hasown": { "version": "2.0.0", - "dev": true, "requires": { "function-bind": "^1.1.2" } @@ -39223,8 +40069,7 @@ "dev": true }, "ignore": { - "version": "5.3.0", - "dev": true + "version": "5.3.0" }, "ignore-by-default": { "version": "1.0.1", @@ -39268,6 +40113,17 @@ "version": "4.0.0", "dev": true }, + "import-in-the-middle": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.4.2.tgz", + "integrity": "sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==", + "requires": { + "acorn": "^8.8.2", + "acorn-import-assertions": "^1.9.0", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "import-local": { "version": "3.1.0", "dev": true, @@ -39336,6 +40192,11 @@ } } }, + "int64-buffer": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.1.10.tgz", + "integrity": "sha512-v7cSY1J8ydZ0GyjUHqF+1bshJ6cnEVLo9EnjB8p+4HDRPZc9N5jjmvUV7NvEsqQOKyH0pmIBFWXVQbiS0+OBbA==" + }, "internal-slot": { "version": "1.0.6", "dev": true, @@ -39434,7 +40295,6 @@ }, "is-core-module": { "version": "2.13.1", - "dev": true, "requires": { "hasown": "^2.0.0" } @@ -39680,8 +40540,7 @@ } }, "isarray": { - "version": "1.0.0", - "dev": true + "version": "1.0.0" }, "isexe": { "version": "2.0.0", @@ -39875,7 +40734,6 @@ }, "jest-docblock": { "version": "29.7.0", - "dev": true, "requires": { "detect-newline": "^3.0.0" } @@ -40190,10 +41048,6 @@ "requires": { "ansi-regex": "^6.0.1" } - }, - "type-fest": { - "version": "3.13.1", - "dev": true } } }, @@ -40449,6 +41303,11 @@ "version": "4.1.5", "dev": true }, + "koalas": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/koalas/-/koalas-1.0.2.tgz", + "integrity": "sha512-RYhBbYaTTTHId3l6fnMZc3eGQNW6FVCqMG6AMwA5I1Mafr6AflaXeoi6x3xQuATRotGYRLk6+1ELZH4dstFNOA==" + }, "language-subtag-registry": { "version": "0.3.22", "dev": true @@ -40511,6 +41370,11 @@ "version": "2.1.0", "dev": true }, + "limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, "line-column": { "version": "1.0.2", "dev": true, @@ -40635,6 +41499,11 @@ "version": "4.2.0", "dev": true }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==" + }, "lodash.memoize": { "version": "4.1.2", "dev": true @@ -40647,9 +41516,18 @@ "version": "4.6.2", "dev": true }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==" + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, "lodash.uniq": { - "version": "4.5.0", - "dev": true + "version": "4.5.0" }, "log-symbols": { "version": "4.1.0", @@ -40727,6 +41605,11 @@ "version": "1.0.9", "dev": true }, + "long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, "loose-envify": { "version": "1.4.0", "requires": { @@ -40850,8 +41733,7 @@ "requires": {} }, "methods": { - "version": "1.1.2", - "dev": true + "version": "1.1.2" }, "micromatch": { "version": "4.0.5", @@ -41001,6 +41883,11 @@ "node-source-walk": "^6.0.1" } }, + "module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" + }, "module-not-found-error": { "version": "1.0.1", "dev": true @@ -41033,6 +41920,17 @@ "ms": { "version": "2.1.3" }, + "msgpack-lite": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/msgpack-lite/-/msgpack-lite-0.1.26.tgz", + "integrity": "sha512-SZ2IxeqZ1oRFGo0xFGbvBJWMp3yLIY9rlIJyxy8CGrwZn1f0ZK4r6jV/AM1r0FZMDUkWkglOk/eeKIL9g77Nxw==", + "requires": { + "event-lite": "^0.1.1", + "ieee754": "^1.1.8", + "int64-buffer": "^0.1.9", + "isarray": "^1.0.0" + } + }, "msw": { "version": "1.3.2", "dev": true, @@ -41184,6 +42082,11 @@ "tslib": "^2.0.3" } }, + "node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" + }, "node-addon-api": { "version": "7.0.0", "dev": true @@ -41200,8 +42103,7 @@ "dev": true }, "node-gyp-build": { - "version": "4.7.1", - "dev": true + "version": "4.7.1" }, "node-int64": { "version": "0.4.0", @@ -41585,6 +42487,11 @@ "version": "1.5.2", "dev": true }, + "opentracing": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz", + "integrity": "sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q==" + }, "optimism": { "version": "0.17.5", "requires": { @@ -41658,14 +42565,12 @@ }, "p-limit": { "version": "3.1.0", - "dev": true, "requires": { "yocto-queue": "^0.1.0" }, "dependencies": { "yocto-queue": { - "version": "0.1.0", - "dev": true + "version": "0.1.0" } } }, @@ -41860,8 +42765,7 @@ "dev": true }, "path-parse": { - "version": "1.0.7", - "dev": true + "version": "1.0.7" }, "path-root": { "version": "0.1.1", @@ -42312,6 +43216,11 @@ "quote-unquote": "^1.0.0" } }, + "pprof-format": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/pprof-format/-/pprof-format-2.0.7.tgz", + "integrity": "sha512-1qWaGAzwMpaXJP9opRa23nPnt2Egi7RMNoNBptEE/XwHbcn4fC2b/4U4bKc5arkGkIh2ZabpF2bEb+c5GNHEKA==" + }, "precinct": { "version": "11.0.5", "dev": true, @@ -42451,6 +43360,25 @@ "warning": "^4.0.0" } }, + "protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + } + }, "proxy-addr": { "version": "2.0.7", "dev": true, @@ -42723,6 +43651,14 @@ "find-up": "^4.1.0", "read-pkg": "^5.2.0", "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } } }, "readable-stream": { @@ -43002,6 +43938,16 @@ "version": "2.0.2", "dev": true }, + "require-in-the-middle": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.2.0.tgz", + "integrity": "sha512-3TLx5TGyAY6AOqLBoXmHkNql0HIf2RGbuMgCDT2WO/uGVAPJs6h7Kl+bN6TIZGd9bWhWPwnDnTHGtW8Iu77sdw==", + "requires": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.1" + } + }, "require-main-filename": { "version": "2.0.0", "dev": true @@ -43024,7 +43970,6 @@ }, "resolve": { "version": "1.22.8", - "dev": true, "requires": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -43090,8 +44035,7 @@ "dev": true }, "retry": { - "version": "0.13.1", - "dev": true + "version": "0.13.1" }, "reusify": { "version": "1.0.4", @@ -43506,6 +44450,11 @@ "version": "1.8.1", "dev": true }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, "side-channel": { "version": "1.0.4", "dev": true, @@ -44061,8 +45010,7 @@ } }, "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "dev": true + "version": "1.0.0" }, "svgo": { "version": "3.0.5", @@ -44522,7 +45470,9 @@ "dev": true }, "type-fest": { - "version": "0.8.1", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", "dev": true }, "type-is": { @@ -44614,8 +45564,7 @@ } }, "undici-types": { - "version": "5.26.5", - "dev": true + "version": "5.26.5" }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -45170,10 +46119,12 @@ "web": { "version": "file:web", "requires": { + "@datadog/browser-rum": "^5.4.0", "@redwoodjs/forms": "6.4.2", "@redwoodjs/router": "6.4.2", "@redwoodjs/vite": "6.4.2", "@redwoodjs/web": "6.4.2", + "@types/node": "^20.10.4", "@types/react": "18.2.39", "@types/react-dom": "18.2.17", "autoprefixer": "^10.4.16", diff --git a/package.json b/package.json index 0950844c..a0cbcfeb 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "seed": "yarn rw exec seed" }, "dependencies": { + "@tanstack/react-table": "^8.10.7", "fsevents": "^2.3.3" }, "packageManager": "yarn@3.7.0", diff --git a/web/src/components/Upload/Uploads/Uploads.tsx b/web/src/components/Upload/Uploads/Uploads.tsx index 2ec809cc..7f497b89 100644 --- a/web/src/components/Upload/Uploads/Uploads.tsx +++ b/web/src/components/Upload/Uploads/Uploads.tsx @@ -1,52 +1,113 @@ +import { + useReactTable, + getCoreRowModel, + getPaginationRowModel, + getSortedRowModel, + createColumnHelper, + flexRender, +} from '@tanstack/react-table' import Table from 'react-bootstrap/Table' import type { FindUploads } from 'types/graphql' import { Link, routes } from '@redwoodjs/router' -import { truncate } from 'src/lib/formatters' - const UploadsList = ({ uploads }: FindUploads) => { + const data = React.useMemo(() => uploads, [uploads]) + + const [sorting, setSorting] = React.useState([]) + + const columnHelper = createColumnHelper() + + const columns = [ + columnHelper.accessor('id', { + cell: (info) => { + const id = info.getValue() as number + + return ( + + {id} + + ) + }, + header: () => ID, + }), + columnHelper.accessor('agency.code', { + cell: (info) => info.getValue(), + header: () => Agency, + }), + columnHelper.accessor('expenditureCategory.code', { + cell: (info) => info.getValue(), + header: () => EC Code, + }), + columnHelper.accessor('uploadedBy.email', { + cell: (info) => info.getValue(), + header: () => Uploaded By, + }), + columnHelper.accessor('filename', { + cell: (info) => info.getValue(), + header: () => Filename, + }), + columnHelper.accessor('validated_at', { + cell: (info) => info.getValue(), + header: () => Validated?, + }), + ] + + const tableInstance = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + state: { + sorting, + }, + onSortingChange: setSorting, + }) + return (
- - - - - - - - + {tableInstance.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + ) + })} + + ))} - {uploads.map((upload) => ( - - - - - - - + {tableInstance.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + ))} ))} diff --git a/web/src/components/Upload/UploadsCell/UploadsCell.tsx b/web/src/components/Upload/UploadsCell/UploadsCell.tsx index da804a5d..c75fa37c 100644 --- a/web/src/components/Upload/UploadsCell/UploadsCell.tsx +++ b/web/src/components/Upload/UploadsCell/UploadsCell.tsx @@ -16,7 +16,7 @@ export const QUERY = gql` } agency { id - name + code } organizationId reportingPeriodId diff --git a/web/types/graphql.d.ts b/web/types/graphql.d.ts index 5f4eb52d..80ac5c0b 100644 --- a/web/types/graphql.d.ts +++ b/web/types/graphql.d.ts @@ -740,4 +740,4 @@ export type FindUploadById = { __typename?: 'Query', upload?: { __typename?: 'Up export type FindUploadsVariables = Exact<{ [key: string]: never; }>; -export type FindUploads = { __typename?: 'Query', uploads: Array<{ __typename?: 'Upload', id: number, filename: string, organizationId: number, reportingPeriodId: number, createdAt: string, updatedAt: string, uploadedBy: { __typename?: 'User', id: number, email: string }, agency: { __typename?: 'Agency', id: number, name: string }, expenditureCategory: { __typename?: 'ExpenditureCategory', id: number, name: string, code: string } }> }; +export type FindUploads = { __typename?: 'Query', uploads: Array<{ __typename?: 'Upload', id: number, filename: string, organizationId: number, reportingPeriodId: number, createdAt: string, updatedAt: string, uploadedBy: { __typename?: 'User', id: number, email: string }, agency: { __typename?: 'Agency', id: number, code: string }, expenditureCategory: { __typename?: 'ExpenditureCategory', id: number, name: string, code: string } }> }; diff --git a/yarn.lock b/yarn.lock index b863449f..cd91b55a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -185,35 +185,35 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-cognito-identity@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/client-cognito-identity@npm:3.468.0" +"@aws-sdk/client-cognito-identity@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/client-cognito-identity@npm:3.470.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.468.0 + "@aws-sdk/client-sts": 3.470.0 "@aws-sdk/core": 3.468.0 - "@aws-sdk/credential-provider-node": 3.468.0 + "@aws-sdk/credential-provider-node": 3.470.0 "@aws-sdk/middleware-host-header": 3.468.0 "@aws-sdk/middleware-logger": 3.468.0 "@aws-sdk/middleware-recursion-detection": 3.468.0 "@aws-sdk/middleware-signing": 3.468.0 - "@aws-sdk/middleware-user-agent": 3.468.0 - "@aws-sdk/region-config-resolver": 3.468.0 + "@aws-sdk/middleware-user-agent": 3.470.0 + "@aws-sdk/region-config-resolver": 3.470.0 "@aws-sdk/types": 3.468.0 - "@aws-sdk/util-endpoints": 3.468.0 + "@aws-sdk/util-endpoints": 3.470.0 "@aws-sdk/util-user-agent-browser": 3.468.0 - "@aws-sdk/util-user-agent-node": 3.468.0 - "@smithy/config-resolver": ^2.0.20 + "@aws-sdk/util-user-agent-node": 3.470.0 + "@smithy/config-resolver": ^2.0.21 "@smithy/fetch-http-handler": ^2.3.1 "@smithy/hash-node": ^2.0.17 "@smithy/invalid-dependency": ^2.0.15 "@smithy/middleware-content-length": ^2.0.17 - "@smithy/middleware-endpoint": ^2.2.2 - "@smithy/middleware-retry": ^2.0.23 + "@smithy/middleware-endpoint": ^2.2.3 + "@smithy/middleware-retry": ^2.0.24 "@smithy/middleware-serde": ^2.0.15 "@smithy/middleware-stack": ^2.0.9 - "@smithy/node-config-provider": ^2.1.7 + "@smithy/node-config-provider": ^2.1.8 "@smithy/node-http-handler": ^2.2.1 "@smithy/protocol-http": ^3.0.11 "@smithy/smithy-client": ^2.1.18 @@ -223,44 +223,44 @@ __metadata: "@smithy/util-body-length-browser": ^2.0.1 "@smithy/util-body-length-node": ^2.1.0 "@smithy/util-defaults-mode-browser": ^2.0.22 - "@smithy/util-defaults-mode-node": ^2.0.28 - "@smithy/util-endpoints": ^1.0.6 + "@smithy/util-defaults-mode-node": ^2.0.29 + "@smithy/util-endpoints": ^1.0.7 "@smithy/util-retry": ^2.0.8 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: de0748c26267454fd3b405408b402fd40ef0dfc1bfeed0315956f21bf625b3f3d70780fe2a1acc280205f639351d8990185c6fc744f30e38aa1acd400ac48748 + checksum: 32e555654a243c690c3e6703d5cf296a799b14fad4a31c4d7b4943383c482b810e0e7f2fbf45a896407f6f3d9c002fd843d65fd515c364f52e09f80cf05afed1 languageName: node linkType: hard "@aws-sdk/client-ssm@npm:^3.462.0": - version: 3.468.0 - resolution: "@aws-sdk/client-ssm@npm:3.468.0" + version: 3.470.0 + resolution: "@aws-sdk/client-ssm@npm:3.470.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.468.0 + "@aws-sdk/client-sts": 3.470.0 "@aws-sdk/core": 3.468.0 - "@aws-sdk/credential-provider-node": 3.468.0 + "@aws-sdk/credential-provider-node": 3.470.0 "@aws-sdk/middleware-host-header": 3.468.0 "@aws-sdk/middleware-logger": 3.468.0 "@aws-sdk/middleware-recursion-detection": 3.468.0 "@aws-sdk/middleware-signing": 3.468.0 - "@aws-sdk/middleware-user-agent": 3.468.0 - "@aws-sdk/region-config-resolver": 3.468.0 + "@aws-sdk/middleware-user-agent": 3.470.0 + "@aws-sdk/region-config-resolver": 3.470.0 "@aws-sdk/types": 3.468.0 - "@aws-sdk/util-endpoints": 3.468.0 + "@aws-sdk/util-endpoints": 3.470.0 "@aws-sdk/util-user-agent-browser": 3.468.0 - "@aws-sdk/util-user-agent-node": 3.468.0 - "@smithy/config-resolver": ^2.0.20 + "@aws-sdk/util-user-agent-node": 3.470.0 + "@smithy/config-resolver": ^2.0.21 "@smithy/fetch-http-handler": ^2.3.1 "@smithy/hash-node": ^2.0.17 "@smithy/invalid-dependency": ^2.0.15 "@smithy/middleware-content-length": ^2.0.17 - "@smithy/middleware-endpoint": ^2.2.2 - "@smithy/middleware-retry": ^2.0.23 + "@smithy/middleware-endpoint": ^2.2.3 + "@smithy/middleware-retry": ^2.0.24 "@smithy/middleware-serde": ^2.0.15 "@smithy/middleware-stack": ^2.0.9 - "@smithy/node-config-provider": ^2.1.7 + "@smithy/node-config-provider": ^2.1.8 "@smithy/node-http-handler": ^2.2.1 "@smithy/protocol-http": ^3.0.11 "@smithy/smithy-client": ^2.1.18 @@ -270,20 +270,20 @@ __metadata: "@smithy/util-body-length-browser": ^2.0.1 "@smithy/util-body-length-node": ^2.1.0 "@smithy/util-defaults-mode-browser": ^2.0.22 - "@smithy/util-defaults-mode-node": ^2.0.28 - "@smithy/util-endpoints": ^1.0.6 + "@smithy/util-defaults-mode-node": ^2.0.29 + "@smithy/util-endpoints": ^1.0.7 "@smithy/util-retry": ^2.0.8 "@smithy/util-utf8": ^2.0.2 "@smithy/util-waiter": ^2.0.15 tslib: ^2.5.0 uuid: ^8.3.2 - checksum: 6e64dc74757769f6cc1e52b7eeed0787ae1fadd531c5b578fff4bb102f8e4e60fd62f70df88e84647b0ea78feb3a13cf4afd96f0d07d506cc84858ea7e2cc7b6 + checksum: 43ffe1d9062a26d831a6c86f5de2f4cef9f5b1309aba343afc64e803899c95d5e215a126cb1abaa0a436d8a63f71512bddddae270d5db7233dbd3aa2da6cae8f languageName: node linkType: hard -"@aws-sdk/client-sso@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/client-sso@npm:3.468.0" +"@aws-sdk/client-sso@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/client-sso@npm:3.470.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 @@ -291,22 +291,22 @@ __metadata: "@aws-sdk/middleware-host-header": 3.468.0 "@aws-sdk/middleware-logger": 3.468.0 "@aws-sdk/middleware-recursion-detection": 3.468.0 - "@aws-sdk/middleware-user-agent": 3.468.0 - "@aws-sdk/region-config-resolver": 3.468.0 + "@aws-sdk/middleware-user-agent": 3.470.0 + "@aws-sdk/region-config-resolver": 3.470.0 "@aws-sdk/types": 3.468.0 - "@aws-sdk/util-endpoints": 3.468.0 + "@aws-sdk/util-endpoints": 3.470.0 "@aws-sdk/util-user-agent-browser": 3.468.0 - "@aws-sdk/util-user-agent-node": 3.468.0 - "@smithy/config-resolver": ^2.0.20 + "@aws-sdk/util-user-agent-node": 3.470.0 + "@smithy/config-resolver": ^2.0.21 "@smithy/fetch-http-handler": ^2.3.1 "@smithy/hash-node": ^2.0.17 "@smithy/invalid-dependency": ^2.0.15 "@smithy/middleware-content-length": ^2.0.17 - "@smithy/middleware-endpoint": ^2.2.2 - "@smithy/middleware-retry": ^2.0.23 + "@smithy/middleware-endpoint": ^2.2.3 + "@smithy/middleware-retry": ^2.0.24 "@smithy/middleware-serde": ^2.0.15 "@smithy/middleware-stack": ^2.0.9 - "@smithy/node-config-provider": ^2.1.7 + "@smithy/node-config-provider": ^2.1.8 "@smithy/node-http-handler": ^2.2.1 "@smithy/protocol-http": ^3.0.11 "@smithy/smithy-client": ^2.1.18 @@ -316,44 +316,44 @@ __metadata: "@smithy/util-body-length-browser": ^2.0.1 "@smithy/util-body-length-node": ^2.1.0 "@smithy/util-defaults-mode-browser": ^2.0.22 - "@smithy/util-defaults-mode-node": ^2.0.28 - "@smithy/util-endpoints": ^1.0.6 + "@smithy/util-defaults-mode-node": ^2.0.29 + "@smithy/util-endpoints": ^1.0.7 "@smithy/util-retry": ^2.0.8 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 42c7df0a1ce24b8cd8564e3dd038d474334c67f2655fcfb9bb357bdd1af3fe80d71ca7e27efb098afab32af86ea70e61395f751aa6f843ae527b884ed20ca55c + checksum: 2b3d04db4e3c5d569a88933b670ba073be78ca528a9f590c2cb5b3f898251fb933e0f6272600180d992060a7caf88786d06bdb60f687373e940bdf694852e80a languageName: node linkType: hard -"@aws-sdk/client-sts@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/client-sts@npm:3.468.0" +"@aws-sdk/client-sts@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/client-sts@npm:3.470.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 "@aws-sdk/core": 3.468.0 - "@aws-sdk/credential-provider-node": 3.468.0 + "@aws-sdk/credential-provider-node": 3.470.0 "@aws-sdk/middleware-host-header": 3.468.0 "@aws-sdk/middleware-logger": 3.468.0 "@aws-sdk/middleware-recursion-detection": 3.468.0 "@aws-sdk/middleware-sdk-sts": 3.468.0 "@aws-sdk/middleware-signing": 3.468.0 - "@aws-sdk/middleware-user-agent": 3.468.0 - "@aws-sdk/region-config-resolver": 3.468.0 + "@aws-sdk/middleware-user-agent": 3.470.0 + "@aws-sdk/region-config-resolver": 3.470.0 "@aws-sdk/types": 3.468.0 - "@aws-sdk/util-endpoints": 3.468.0 + "@aws-sdk/util-endpoints": 3.470.0 "@aws-sdk/util-user-agent-browser": 3.468.0 - "@aws-sdk/util-user-agent-node": 3.468.0 - "@smithy/config-resolver": ^2.0.20 + "@aws-sdk/util-user-agent-node": 3.470.0 + "@smithy/config-resolver": ^2.0.21 "@smithy/fetch-http-handler": ^2.3.1 "@smithy/hash-node": ^2.0.17 "@smithy/invalid-dependency": ^2.0.15 "@smithy/middleware-content-length": ^2.0.17 - "@smithy/middleware-endpoint": ^2.2.2 - "@smithy/middleware-retry": ^2.0.23 + "@smithy/middleware-endpoint": ^2.2.3 + "@smithy/middleware-retry": ^2.0.24 "@smithy/middleware-serde": ^2.0.15 "@smithy/middleware-stack": ^2.0.9 - "@smithy/node-config-provider": ^2.1.7 + "@smithy/node-config-provider": ^2.1.8 "@smithy/node-http-handler": ^2.2.1 "@smithy/protocol-http": ^3.0.11 "@smithy/smithy-client": ^2.1.18 @@ -363,13 +363,13 @@ __metadata: "@smithy/util-body-length-browser": ^2.0.1 "@smithy/util-body-length-node": ^2.1.0 "@smithy/util-defaults-mode-browser": ^2.0.22 - "@smithy/util-defaults-mode-node": ^2.0.28 - "@smithy/util-endpoints": ^1.0.6 + "@smithy/util-defaults-mode-node": ^2.0.29 + "@smithy/util-endpoints": ^1.0.7 "@smithy/util-retry": ^2.0.8 "@smithy/util-utf8": ^2.0.2 fast-xml-parser: 4.2.5 tslib: ^2.5.0 - checksum: 4355c8fed2d0dfd99f03b4cddc275bcc13bc7bf2869a23aa32c26c17227181003fcc496a82e233984715f8d2a1582d34f8c0244450cc4b742e99e4d266733a03 + checksum: 70159cb477a8dd42687d8b4064cdce8b324cccb51b16dfbe98bc239648a9dfd6e10093c26a44761493d3fdde7af2cac5b90fe61f3353141b4e66a211d4e8cd70 languageName: node linkType: hard @@ -383,16 +383,16 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-cognito-identity@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.468.0" +"@aws-sdk/credential-provider-cognito-identity@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.470.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.468.0 + "@aws-sdk/client-cognito-identity": 3.470.0 "@aws-sdk/types": 3.468.0 "@smithy/property-provider": ^2.0.0 "@smithy/types": ^2.7.0 tslib: ^2.5.0 - checksum: 54e7485ab25eca613739183999b46e2e871a075822d98e3e66f28175056467173e2ee167ae67720b6926d01a2700b9a32325bd3e5f2a36bf05fbf3703be41f92 + checksum: bfba501769b2ea95e604aec9d19e067321c1f2b579f825a43284919ffbf013ea5f7c577d62bfe25eb9baaf3aaea590944826d3b4e34ecce3e58f52eee1c6dc27 languageName: node linkType: hard @@ -425,13 +425,13 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-ini@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/credential-provider-ini@npm:3.468.0" +"@aws-sdk/credential-provider-ini@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.470.0" dependencies: "@aws-sdk/credential-provider-env": 3.468.0 "@aws-sdk/credential-provider-process": 3.468.0 - "@aws-sdk/credential-provider-sso": 3.468.0 + "@aws-sdk/credential-provider-sso": 3.470.0 "@aws-sdk/credential-provider-web-identity": 3.468.0 "@aws-sdk/types": 3.468.0 "@smithy/credential-provider-imds": ^2.0.0 @@ -439,18 +439,18 @@ __metadata: "@smithy/shared-ini-file-loader": ^2.0.6 "@smithy/types": ^2.7.0 tslib: ^2.5.0 - checksum: 888c4aa6ea41c965b64715c53dd7b322011b0ebd788bbc5125fb3c06d4efe7e847058ce5215517dbaf3b4cc6749f269aec21fb7af21335abbef51d1632a1a3a0 + checksum: bfce4b31421a2465ca430e01138ce6bc0a0803ce0e38c82c3a11908f30caae760ae6b9871c6c5da0abadb2ff1793aa27ffb1c4d44eea29611cc00fbd50ebb187 languageName: node linkType: hard -"@aws-sdk/credential-provider-node@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/credential-provider-node@npm:3.468.0" +"@aws-sdk/credential-provider-node@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.470.0" dependencies: "@aws-sdk/credential-provider-env": 3.468.0 - "@aws-sdk/credential-provider-ini": 3.468.0 + "@aws-sdk/credential-provider-ini": 3.470.0 "@aws-sdk/credential-provider-process": 3.468.0 - "@aws-sdk/credential-provider-sso": 3.468.0 + "@aws-sdk/credential-provider-sso": 3.470.0 "@aws-sdk/credential-provider-web-identity": 3.468.0 "@aws-sdk/types": 3.468.0 "@smithy/credential-provider-imds": ^2.0.0 @@ -458,7 +458,7 @@ __metadata: "@smithy/shared-ini-file-loader": ^2.0.6 "@smithy/types": ^2.7.0 tslib: ^2.5.0 - checksum: 59203e103fcd6610554692b4e57723ab84038b61fd32c22a848c297fa45991e66abd3d080108ecca94c386d0c76019c8da652ed298e3829212cb39041b00f63f + checksum: c7a4bd164d133c813bb90edbecd4747f04ad876b65adc8c15f14fe05f485920a5a177d88a8206bd052b21104dceb42aa128354c3f876e7d7675046d1f3de658c languageName: node linkType: hard @@ -475,18 +475,18 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/credential-provider-sso@npm:3.468.0" +"@aws-sdk/credential-provider-sso@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.470.0" dependencies: - "@aws-sdk/client-sso": 3.468.0 - "@aws-sdk/token-providers": 3.468.0 + "@aws-sdk/client-sso": 3.470.0 + "@aws-sdk/token-providers": 3.470.0 "@aws-sdk/types": 3.468.0 "@smithy/property-provider": ^2.0.0 "@smithy/shared-ini-file-loader": ^2.0.6 "@smithy/types": ^2.7.0 tslib: ^2.5.0 - checksum: 2582bfab641f608d9598f5bc6bd685a80ff51d199952f5843d2ea417554376ad69d533145b01b8726ce991fb0c4f9264252e7c0cea9fa7e61e0df0a98d426ede + checksum: aa5c8af481d9d9d3b8484836e8a4cdaabdc0924ea264cb5854c96256a9d17e375c6235f2cfa62dfa5dec73156a67bc4015c8e959830bbdcf9351c18697f9102c languageName: node linkType: hard @@ -502,27 +502,27 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-providers@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/credential-providers@npm:3.468.0" +"@aws-sdk/credential-providers@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/credential-providers@npm:3.470.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.468.0 - "@aws-sdk/client-sso": 3.468.0 - "@aws-sdk/client-sts": 3.468.0 - "@aws-sdk/credential-provider-cognito-identity": 3.468.0 + "@aws-sdk/client-cognito-identity": 3.470.0 + "@aws-sdk/client-sso": 3.470.0 + "@aws-sdk/client-sts": 3.470.0 + "@aws-sdk/credential-provider-cognito-identity": 3.470.0 "@aws-sdk/credential-provider-env": 3.468.0 "@aws-sdk/credential-provider-http": 3.468.0 - "@aws-sdk/credential-provider-ini": 3.468.0 - "@aws-sdk/credential-provider-node": 3.468.0 + "@aws-sdk/credential-provider-ini": 3.470.0 + "@aws-sdk/credential-provider-node": 3.470.0 "@aws-sdk/credential-provider-process": 3.468.0 - "@aws-sdk/credential-provider-sso": 3.468.0 + "@aws-sdk/credential-provider-sso": 3.470.0 "@aws-sdk/credential-provider-web-identity": 3.468.0 "@aws-sdk/types": 3.468.0 "@smithy/credential-provider-imds": ^2.0.0 "@smithy/property-provider": ^2.0.0 "@smithy/types": ^2.7.0 tslib: ^2.5.0 - checksum: ab2b5659ac295bed016911cd275c8605b16fe3a7faa0fe6019526727d288e51e058b46343cf4c07d4abed6088ba64bc99618efcd909954978eb159cea36d8c6a + checksum: c78bfb6947dce84ff88444c805f81e61754a387e826e8d0369712d4fdad69466f5bbcb757d376e214c89d4060e8f2e77341566b4caa0f768d1ab3bc9a4bbc72f languageName: node linkType: hard @@ -588,77 +588,77 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-user-agent@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/middleware-user-agent@npm:3.468.0" +"@aws-sdk/middleware-user-agent@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.470.0" dependencies: "@aws-sdk/types": 3.468.0 - "@aws-sdk/util-endpoints": 3.468.0 + "@aws-sdk/util-endpoints": 3.470.0 "@smithy/protocol-http": ^3.0.11 "@smithy/types": ^2.7.0 tslib: ^2.5.0 - checksum: 87ccf4bb8a1bfcb9f90e9efbc27993d284aa9b950ef27efdb4a7df24403c3e91a6bae4aff15ff65027b2b84fb3fa75358d492ab7d894ec83a5c2b0597c275f71 + checksum: 92cc9642e73a4747d3a5e6351722cb0b7545b93370dfcffa714c2ea9b7091eab4e052f74fb3bf65aaf336dc2b183cd43bb7095ed03f082c30872d52b19db4ea9 languageName: node linkType: hard "@aws-sdk/rds-signer@npm:^3.462.0": - version: 3.468.0 - resolution: "@aws-sdk/rds-signer@npm:3.468.0" + version: 3.470.0 + resolution: "@aws-sdk/rds-signer@npm:3.470.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/credential-providers": 3.468.0 + "@aws-sdk/credential-providers": 3.470.0 "@aws-sdk/util-format-url": 3.468.0 - "@smithy/config-resolver": ^2.0.20 + "@smithy/config-resolver": ^2.0.21 "@smithy/hash-node": ^2.0.17 "@smithy/invalid-dependency": ^2.0.15 - "@smithy/node-config-provider": ^2.1.7 + "@smithy/node-config-provider": ^2.1.8 "@smithy/protocol-http": ^3.0.11 "@smithy/signature-v4": ^2.0.0 "@smithy/types": ^2.7.0 tslib: ^2.5.0 - checksum: 3f2ea49e5f896977fef9c6a165c166c5581d8f13605034c5ab9bbe978632b394413ece765db337fffa0a6e5e38d2f868a13002a4270209e32fd1e75b7fddff8a + checksum: c63d2812582e92566ddffacdc818485c9c4b5774e17115f015520918ed8bf500d6c2a96753c6ccd210a6dc8a2c4cf4cbd084da96336e9129952efe08123baad0 languageName: node linkType: hard -"@aws-sdk/region-config-resolver@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/region-config-resolver@npm:3.468.0" +"@aws-sdk/region-config-resolver@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/region-config-resolver@npm:3.470.0" dependencies: - "@smithy/node-config-provider": ^2.1.7 + "@smithy/node-config-provider": ^2.1.8 "@smithy/types": ^2.7.0 "@smithy/util-config-provider": ^2.0.0 "@smithy/util-middleware": ^2.0.8 tslib: ^2.5.0 - checksum: 16a178fd20dc389f9d09494d477aae12da93d82b272a6f6ea02ece540b16407ae648f561c8063ba5ecc6ec0c8b0dab996a6acab1f7a8419777c62a588f000182 + checksum: d995aff7da0c18e497fedeb2b32961b3c3558f0b08b2efd6e4550ee07814c49e53c8ec06bb70d27b4bb9a0564c2ffbf2772ed7a396e8f93cc0d6b8dc4d5ec056 languageName: node linkType: hard -"@aws-sdk/token-providers@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/token-providers@npm:3.468.0" +"@aws-sdk/token-providers@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/token-providers@npm:3.470.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 "@aws-sdk/middleware-host-header": 3.468.0 "@aws-sdk/middleware-logger": 3.468.0 "@aws-sdk/middleware-recursion-detection": 3.468.0 - "@aws-sdk/middleware-user-agent": 3.468.0 - "@aws-sdk/region-config-resolver": 3.468.0 + "@aws-sdk/middleware-user-agent": 3.470.0 + "@aws-sdk/region-config-resolver": 3.470.0 "@aws-sdk/types": 3.468.0 - "@aws-sdk/util-endpoints": 3.468.0 + "@aws-sdk/util-endpoints": 3.470.0 "@aws-sdk/util-user-agent-browser": 3.468.0 - "@aws-sdk/util-user-agent-node": 3.468.0 - "@smithy/config-resolver": ^2.0.20 + "@aws-sdk/util-user-agent-node": 3.470.0 + "@smithy/config-resolver": ^2.0.21 "@smithy/fetch-http-handler": ^2.3.1 "@smithy/hash-node": ^2.0.17 "@smithy/invalid-dependency": ^2.0.15 "@smithy/middleware-content-length": ^2.0.17 - "@smithy/middleware-endpoint": ^2.2.2 - "@smithy/middleware-retry": ^2.0.23 + "@smithy/middleware-endpoint": ^2.2.3 + "@smithy/middleware-retry": ^2.0.24 "@smithy/middleware-serde": ^2.0.15 "@smithy/middleware-stack": ^2.0.9 - "@smithy/node-config-provider": ^2.1.7 + "@smithy/node-config-provider": ^2.1.8 "@smithy/node-http-handler": ^2.2.1 "@smithy/property-provider": ^2.0.0 "@smithy/protocol-http": ^3.0.11 @@ -670,12 +670,12 @@ __metadata: "@smithy/util-body-length-browser": ^2.0.1 "@smithy/util-body-length-node": ^2.1.0 "@smithy/util-defaults-mode-browser": ^2.0.22 - "@smithy/util-defaults-mode-node": ^2.0.28 - "@smithy/util-endpoints": ^1.0.6 + "@smithy/util-defaults-mode-node": ^2.0.29 + "@smithy/util-endpoints": ^1.0.7 "@smithy/util-retry": ^2.0.8 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 1703db819b032f96e23021deb514eb0668b2102453559c8e5e1504d771bbc07b17f08d5227ab2963456016f15333ed0714b9fdcfce75cc8599ebac6a8d52235a + checksum: 061bc007db3eb38879f3bb431b7f1c2e325291b1a89f42efe9000eacb278b1306ee201ec72d6939c64170157ab0735c09059380bbbd985030888d45cdc0b4a13 languageName: node linkType: hard @@ -689,14 +689,14 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-endpoints@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/util-endpoints@npm:3.468.0" +"@aws-sdk/util-endpoints@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/util-endpoints@npm:3.470.0" dependencies: "@aws-sdk/types": 3.468.0 - "@smithy/util-endpoints": ^1.0.6 + "@smithy/util-endpoints": ^1.0.7 tslib: ^2.5.0 - checksum: 967d8b4a161732d28cd1ad87efeebd16cf0c5e3fe4349c0584c282afe49d1da4f60349af49d3fd16ff1bdec3bd770dc5c48b1566395809ed13ec4839829ce752 + checksum: 3c1fb01db4d2ddd3429e50b9660f3f3729f5a73404f86642aa07f44fb84c253311a32eca74a2ec7e1940d7b4d63decf7e330497187813980af841645c71f88c3 languageName: node linkType: hard @@ -733,12 +733,12 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-user-agent-node@npm:3.468.0": - version: 3.468.0 - resolution: "@aws-sdk/util-user-agent-node@npm:3.468.0" +"@aws-sdk/util-user-agent-node@npm:3.470.0": + version: 3.470.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.470.0" dependencies: "@aws-sdk/types": 3.468.0 - "@smithy/node-config-provider": ^2.1.7 + "@smithy/node-config-provider": ^2.1.8 "@smithy/types": ^2.7.0 tslib: ^2.5.0 peerDependencies: @@ -746,7 +746,7 @@ __metadata: peerDependenciesMeta: aws-crt: optional: true - checksum: 00c53050be0898b74a22eb3d55dc49f87a945795037e79e4eb5f0d2e191ba8e6d46bdc71654224432cad8374277429f11ec7622b1204f1783683707769f7c9f6 + checksum: 11fe4ae2e437edb9bb0cb34bce60ea4d4fb2f6108b3c45918f67aa5c93b14292df278e878d9b5dbc5a27ceec73b33d51d044975d16cc031d2b431044f6893629 languageName: node linkType: hard @@ -796,7 +796,7 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.23.3, @babel/compat-data@npm:^7.23.5": +"@babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.3, @babel/compat-data@npm:^7.23.5": version: 7.23.5 resolution: "@babel/compat-data@npm:7.23.5" checksum: 06ce244cda5763295a0ea924728c09bae57d35713b675175227278896946f922a63edf803c322f855a3878323d48d0255a2a3023409d2a123483c8a69ebb4744 @@ -804,25 +804,25 @@ __metadata: linkType: hard "@babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.12.9, @babel/core@npm:^7.14.0, @babel/core@npm:^7.22.20, @babel/core@npm:^7.23.2": - version: 7.23.5 - resolution: "@babel/core@npm:7.23.5" + version: 7.23.6 + resolution: "@babel/core@npm:7.23.6" dependencies: "@ampproject/remapping": ^2.2.0 "@babel/code-frame": ^7.23.5 - "@babel/generator": ^7.23.5 - "@babel/helper-compilation-targets": ^7.22.15 + "@babel/generator": ^7.23.6 + "@babel/helper-compilation-targets": ^7.23.6 "@babel/helper-module-transforms": ^7.23.3 - "@babel/helpers": ^7.23.5 - "@babel/parser": ^7.23.5 + "@babel/helpers": ^7.23.6 + "@babel/parser": ^7.23.6 "@babel/template": ^7.22.15 - "@babel/traverse": ^7.23.5 - "@babel/types": ^7.23.5 + "@babel/traverse": ^7.23.6 + "@babel/types": ^7.23.6 convert-source-map: ^2.0.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 json5: ^2.2.3 semver: ^6.3.1 - checksum: 5e5dfb1e61f298676f1fca18c646dbf6fb164ca1056b0169b8d42b7f5c35e026d81823582ccb2358e93a61b035e22b3ad37e2abaae4bf43f1ffb93b6ce19466e + checksum: 4bddd1b80394a64b2ee33eeb216e8a2a49ad3d74f0ca9ba678c84a37f4502b2540662d72530d78228a2a349fda837fa852eea5cd3ae28465d1188acc6055868e languageName: node linkType: hard @@ -852,15 +852,15 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.14.0, @babel/generator@npm:^7.18.13, @babel/generator@npm:^7.23.5, @babel/generator@npm:^7.7.2": - version: 7.23.5 - resolution: "@babel/generator@npm:7.23.5" +"@babel/generator@npm:^7.14.0, @babel/generator@npm:^7.18.13, @babel/generator@npm:^7.23.6, @babel/generator@npm:^7.7.2": + version: 7.23.6 + resolution: "@babel/generator@npm:7.23.6" dependencies: - "@babel/types": ^7.23.5 + "@babel/types": ^7.23.6 "@jridgewell/gen-mapping": ^0.3.2 "@jridgewell/trace-mapping": ^0.3.17 jsesc: ^2.5.1 - checksum: 845ddda7cf38a3edf4be221cc8a439dee9ea6031355146a1a74047aa8007bc030305b27d8c68ec9e311722c910610bde38c0e13a9ce55225251e7cb7e7f3edc8 + checksum: 1a1a1c4eac210f174cd108d479464d053930a812798e09fee069377de39a893422df5b5b146199ead7239ae6d3a04697b45fc9ac6e38e0f6b76374390f91fc6c languageName: node linkType: hard @@ -882,22 +882,22 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.22.6": - version: 7.22.15 - resolution: "@babel/helper-compilation-targets@npm:7.22.15" +"@babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/helper-compilation-targets@npm:7.23.6" dependencies: - "@babel/compat-data": ^7.22.9 - "@babel/helper-validator-option": ^7.22.15 - browserslist: ^4.21.9 + "@babel/compat-data": ^7.23.5 + "@babel/helper-validator-option": ^7.23.5 + browserslist: ^4.22.2 lru-cache: ^5.1.1 semver: ^6.3.1 - checksum: ce85196769e091ae54dd39e4a80c2a9df1793da8588e335c383d536d54f06baf648d0a08fc873044f226398c4ded15c4ae9120ee18e7dfd7c639a68e3cdc9980 + checksum: c630b98d4527ac8fe2c58d9a06e785dfb2b73ec71b7c4f2ddf90f814b5f75b547f3c015f110a010fd31f76e3864daaf09f3adcd2f6acdbfb18a8de3a48717590 languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.22.15, @babel/helper-create-class-features-plugin@npm:^7.23.5": - version: 7.23.5 - resolution: "@babel/helper-create-class-features-plugin@npm:7.23.5" +"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.22.15, @babel/helper-create-class-features-plugin@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/helper-create-class-features-plugin@npm:7.23.6" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 "@babel/helper-environment-visitor": ^7.22.20 @@ -910,7 +910,7 @@ __metadata: semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0 - checksum: fe7c6c0baca1838bba76ac1330df47b661d932354115ea9e2ea65b179f80b717987d3c3da7e1525fd648e5f2d86c620efc959cabda4d7562b125a27c3ac780d0 + checksum: 356b71b9f4a3a95917432bf6a452f475a292d394d9310e9c8b23c8edb564bee91e40d4290b8aa8779d2987a7c39ae717b2d76edc7c952078b8952df1a20259e3 languageName: node linkType: hard @@ -1102,14 +1102,14 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.23.5": - version: 7.23.5 - resolution: "@babel/helpers@npm:7.23.5" +"@babel/helpers@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/helpers@npm:7.23.6" dependencies: "@babel/template": ^7.22.15 - "@babel/traverse": ^7.23.5 - "@babel/types": ^7.23.5 - checksum: c16dc8a3bb3d0e02c7ee1222d9d0865ed4b92de44fb8db43ff5afd37a0fc9ea5e2906efa31542c95b30c1a3a9540d66314663c9a23b5bb9b5ec76e8ebc896064 + "@babel/traverse": ^7.23.6 + "@babel/types": ^7.23.6 + checksum: c5ba62497e1d717161d107c4b3de727565c68b6b9f50f59d6298e613afeca8895799b227c256e06d362e565aec34e26fb5c675b9c3d25055c52b945a21c21e21 languageName: node linkType: hard @@ -1124,12 +1124,12 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.1.6, @babel/parser@npm:^7.14.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.8, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.8, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.22.16, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.23.5, @babel/parser@npm:^7.3.2": - version: 7.23.5 - resolution: "@babel/parser@npm:7.23.5" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.1.6, @babel/parser@npm:^7.14.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.8, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.8, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.22.16, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.23.6, @babel/parser@npm:^7.3.2": + version: 7.23.6 + resolution: "@babel/parser@npm:7.23.6" bin: parser: ./bin/babel-parser.js - checksum: ea763629310f71580c4a3ea9d3705195b7ba994ada2cc98f9a584ebfdacf54e92b2735d351672824c2c2b03c7f19206899f4d95650d85ce514a822b19a8734c7 + checksum: 140801c43731a6c41fd193f5c02bc71fd647a0360ca616b23d2db8be4b9739b9f951a03fc7c2db4f9b9214f4b27c1074db0f18bc3fa653783082d5af7c8860d5 languageName: node linkType: hard @@ -1646,14 +1646,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-for-of@npm:^7.0.0, @babel/plugin-transform-for-of@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-for-of@npm:7.23.3" +"@babel/plugin-transform-for-of@npm:^7.0.0, @babel/plugin-transform-for-of@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/plugin-transform-for-of@npm:7.23.6" dependencies: "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: a6288122a5091d96c744b9eb23dc1b2d4cce25f109ac1e26a0ea03c4ea60330e6f3cc58530b33ba7369fa07163b71001399a145238b7e92bff6270ef3b9c32a0 + checksum: 228c060aa61f6aa89dc447170075f8214863b94f830624e74ade99c1a09316897c12d76e848460b0b506593e58dbc42739af6dc4cb0fe9b84dffe4a596050a36 languageName: node linkType: hard @@ -2081,16 +2082,16 @@ __metadata: linkType: hard "@babel/plugin-transform-typescript@npm:^7.22.15, @babel/plugin-transform-typescript@npm:^7.23.3": - version: 7.23.5 - resolution: "@babel/plugin-transform-typescript@npm:7.23.5" + version: 7.23.6 + resolution: "@babel/plugin-transform-typescript@npm:7.23.6" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.23.5 + "@babel/helper-create-class-features-plugin": ^7.23.6 "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-typescript": ^7.23.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d77b5cc22cf48fe461de07e4f058dc9c0d8c4e3ca49de0e3a336a94ab39bfa4f4732598e36c479bec0dd1bf4aff9154bc2dcbfbe3145a751e4771ccae5afaaf8 + checksum: 0462241843d14dff9f1a4c49ab182a6f01a5f7679957c786b08165dac3e8d49184011f05ca204183d164c54b9d3496d1b3005f904fa8708e394e6f15bf5548e6 languageName: node linkType: hard @@ -2142,11 +2143,11 @@ __metadata: linkType: hard "@babel/preset-env@npm:^7.22.20": - version: 7.23.5 - resolution: "@babel/preset-env@npm:7.23.5" + version: 7.23.6 + resolution: "@babel/preset-env@npm:7.23.6" dependencies: "@babel/compat-data": ^7.23.5 - "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-compilation-targets": ^7.23.6 "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-validator-option": ^7.23.5 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.23.3 @@ -2186,7 +2187,7 @@ __metadata: "@babel/plugin-transform-dynamic-import": ^7.23.4 "@babel/plugin-transform-exponentiation-operator": ^7.23.3 "@babel/plugin-transform-export-namespace-from": ^7.23.4 - "@babel/plugin-transform-for-of": ^7.23.3 + "@babel/plugin-transform-for-of": ^7.23.6 "@babel/plugin-transform-function-name": ^7.23.3 "@babel/plugin-transform-json-strings": ^7.23.4 "@babel/plugin-transform-literals": ^7.23.3 @@ -2227,7 +2228,7 @@ __metadata: semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: adddd58d14fc1b2e5f8cf90995f522879362a0543e316afe9e5783f1bd715bb1e92300cd49d7ce3a95c64a96d60788d0089651e2cf4cac937f5469aac1087bb1 + checksum: 130262f263c8a76915ff5361f78afa9e63b4ecbf3ade8e833dc7546db7b9552ab507835bdea0feb5e70861345ca128a31327fd2e187084a215fc9dd1cc0ed38e languageName: node linkType: hard @@ -2308,11 +2309,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.23.5 - resolution: "@babel/runtime@npm:7.23.5" + version: 7.23.6 + resolution: "@babel/runtime@npm:7.23.6" dependencies: regenerator-runtime: ^0.14.0 - checksum: 164d9802424f06908e62d29b8fd3a87db55accf82f46f964ac481dcead11ff7df8391e3696e5fa91a8ca10ea8845bf650acd730fa88cf13f8026cd8d5eec6936 + checksum: 1a8eaf3d3a103ef5227b60ca7ab5c589118c36ca65ef2d64e65380b32a98a3f3b5b3ef96660fa0471b079a18b619a8317f3e7f03ab2b930c45282a8b69ed9a16 languageName: node linkType: hard @@ -2327,21 +2328,21 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.22.20, @babel/traverse@npm:^7.23.5": - version: 7.23.5 - resolution: "@babel/traverse@npm:7.23.5" +"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.22.20, @babel/traverse@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/traverse@npm:7.23.6" dependencies: "@babel/code-frame": ^7.23.5 - "@babel/generator": ^7.23.5 + "@babel/generator": ^7.23.6 "@babel/helper-environment-visitor": ^7.22.20 "@babel/helper-function-name": ^7.23.0 "@babel/helper-hoist-variables": ^7.22.5 "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/parser": ^7.23.5 - "@babel/types": ^7.23.5 - debug: ^4.1.0 + "@babel/parser": ^7.23.6 + "@babel/types": ^7.23.6 + debug: ^4.3.1 globals: ^11.1.0 - checksum: 0558b05360850c3ad6384e85bd55092126a8d5f93e29a8e227dd58fa1f9e1a4c25fd337c07c7ae509f0983e7a2b1e761ffdcfaa77a1e1bedbc867058e1de5a7d + checksum: 48f2eac0e86b6cb60dab13a5ea6a26ba45c450262fccdffc334c01089e75935f7546be195e260e97f6e43cea419862eda095018531a2718fef8189153d479f88 languageName: node linkType: hard @@ -2356,14 +2357,14 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.1.6, @babel/types@npm:^7.16.8, @babel/types@npm:^7.18.13, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.23.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.23.5 - resolution: "@babel/types@npm:7.23.5" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.1.6, @babel/types@npm:^7.16.8, @babel/types@npm:^7.18.13, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.23.6, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.23.6 + resolution: "@babel/types@npm:7.23.6" dependencies: "@babel/helper-string-parser": ^7.23.4 "@babel/helper-validator-identifier": ^7.22.20 to-fast-properties: ^2.0.0 - checksum: 3d21774480a459ef13b41c2e32700d927af649e04b70c5d164814d8e04ab584af66a93330602c2925e1a6925c2b829cc153418a613a4e7d79d011be1f29ad4b2 + checksum: 68187dbec0d637f79bc96263ac95ec8b06d424396678e7e225492be866414ce28ebc918a75354d4c28659be6efe30020b4f0f6df81cc418a2d30645b690a8de0 languageName: node linkType: hard @@ -2425,34 +2426,34 @@ __metadata: languageName: node linkType: hard -"@datadog/browser-core@npm:5.4.0": - version: 5.4.0 - resolution: "@datadog/browser-core@npm:5.4.0" - checksum: 3427d496cef27a5d1ba0180cc935a4ba1d1f3ca812799079e28ad956c801516d81eed80c2eeeb0edda0484c025e2525b7117eda311785b43aeaf8b77517663de +"@datadog/browser-core@npm:5.5.0": + version: 5.5.0 + resolution: "@datadog/browser-core@npm:5.5.0" + checksum: beff1d0aeb75027f2382d8ef5abaf0320ebd6e6a92ae2c293483b4c00a47619f132d5c45009fadc2648a13c161aec6d269796ccf6b416e9066ce88746f7dab9a languageName: node linkType: hard -"@datadog/browser-rum-core@npm:5.4.0": - version: 5.4.0 - resolution: "@datadog/browser-rum-core@npm:5.4.0" +"@datadog/browser-rum-core@npm:5.5.0": + version: 5.5.0 + resolution: "@datadog/browser-rum-core@npm:5.5.0" dependencies: - "@datadog/browser-core": 5.4.0 - checksum: 49c7b5cfd5972daf73d137c671b39097977623eb16f7d273c9a83d667b86b53b0036bc9ac6f454a9b876403e4ec5a47cb0e8736daed340813fec781787687973 + "@datadog/browser-core": 5.5.0 + checksum: 9eae269435bed9dfb2ad4b556bb2ebad0ee079c2c25866819655e67ba38f1984efb4855a83bcc79955611812ee445bccdf374bfd7e2cc4481a20a03f9b21867f languageName: node linkType: hard "@datadog/browser-rum@npm:^5.4.0": - version: 5.4.0 - resolution: "@datadog/browser-rum@npm:5.4.0" + version: 5.5.0 + resolution: "@datadog/browser-rum@npm:5.5.0" dependencies: - "@datadog/browser-core": 5.4.0 - "@datadog/browser-rum-core": 5.4.0 + "@datadog/browser-core": 5.5.0 + "@datadog/browser-rum-core": 5.5.0 peerDependencies: - "@datadog/browser-logs": 5.4.0 + "@datadog/browser-logs": 5.5.0 peerDependenciesMeta: "@datadog/browser-logs": optional: true - checksum: d863fe90c30176328cbaeaf444f1084dd79b3ba862911b332536ed401bbe13b3a2d43e7add6c1c7b3477d1316ead863339219063e3548ec699cc1be330a92ec6 + checksum: 5616fda121c9ccf13b2908a9ada9e3dc8913bb36afbacae73fe11ab9fb613cfffd4184302f3342a407c064c5a17623be6f3c62be054874ac35f96201a1a26c8c languageName: node linkType: hard @@ -4447,6 +4448,13 @@ __metadata: languageName: node linkType: hard +"@kamilkisiela/fast-url-parser@npm:^1.1.4": + version: 1.1.4 + resolution: "@kamilkisiela/fast-url-parser@npm:1.1.4" + checksum: 921d305eff1fce5c7c669aee5cfe39e50109968addb496c23f0a42253d030e3cd5865eb01b13245915923bee452db75ba8a8254e69b0d0575d3c168efce7091e + languageName: node + linkType: hard + "@leichtgewicht/ip-codec@npm:^2.0.1": version: 2.0.4 resolution: "@leichtgewicht/ip-codec@npm:2.0.4" @@ -5994,13 +6002,13 @@ __metadata: linkType: hard "@restart/hooks@npm:^0.4.9": - version: 0.4.14 - resolution: "@restart/hooks@npm:0.4.14" + version: 0.4.15 + resolution: "@restart/hooks@npm:0.4.15" dependencies: dequal: ^2.0.3 peerDependencies: react: ">=16.8.0" - checksum: 13e87b535af0993a941fb362c4c3883f501230ed0e6dd8843fe998e9fe8ca060a2f9cfa0535efd246bf7b6fc39cfda950314fd021529910e9dc33c01da162741 + checksum: 26787aa7e824999921d8a33e5969137cf0473c6d30f938566fa2497d1135ac9410ea88303bc6082726981561aa439e388d1d72e4c3cd846847e2efb483e9500b languageName: node linkType: hard @@ -6093,7 +6101,7 @@ __metadata: languageName: node linkType: hard -"@smithy/config-resolver@npm:^2.0.20, @smithy/config-resolver@npm:^2.0.21": +"@smithy/config-resolver@npm:^2.0.21": version: 2.0.21 resolution: "@smithy/config-resolver@npm:2.0.21" dependencies: @@ -6186,7 +6194,7 @@ __metadata: languageName: node linkType: hard -"@smithy/middleware-endpoint@npm:^2.2.2": +"@smithy/middleware-endpoint@npm:^2.2.3": version: 2.2.3 resolution: "@smithy/middleware-endpoint@npm:2.2.3" dependencies: @@ -6201,7 +6209,7 @@ __metadata: languageName: node linkType: hard -"@smithy/middleware-retry@npm:^2.0.23": +"@smithy/middleware-retry@npm:^2.0.24": version: 2.0.24 resolution: "@smithy/middleware-retry@npm:2.0.24" dependencies: @@ -6238,7 +6246,7 @@ __metadata: languageName: node linkType: hard -"@smithy/node-config-provider@npm:^2.1.7, @smithy/node-config-provider@npm:^2.1.8": +"@smithy/node-config-provider@npm:^2.1.8": version: 2.1.8 resolution: "@smithy/node-config-provider@npm:2.1.8" dependencies: @@ -6431,7 +6439,7 @@ __metadata: languageName: node linkType: hard -"@smithy/util-defaults-mode-node@npm:^2.0.28": +"@smithy/util-defaults-mode-node@npm:^2.0.29": version: 2.0.29 resolution: "@smithy/util-defaults-mode-node@npm:2.0.29" dependencies: @@ -6446,7 +6454,7 @@ __metadata: languageName: node linkType: hard -"@smithy/util-endpoints@npm:^1.0.6": +"@smithy/util-endpoints@npm:^1.0.7": version: 1.0.7 resolution: "@smithy/util-endpoints@npm:1.0.7" dependencies: @@ -6551,6 +6559,25 @@ __metadata: languageName: node linkType: hard +"@tanstack/react-table@npm:^8.10.7": + version: 8.10.7 + resolution: "@tanstack/react-table@npm:8.10.7" + dependencies: + "@tanstack/table-core": 8.10.7 + peerDependencies: + react: ">=16" + react-dom: ">=16" + checksum: f8f19ae3ad8531e0f3cb838b61213d9acd0b64b27d1a8a05a699e6ed50e25c9d3c9478ae3f6d20883288f601eec06e8264fac9503b36122471c2f8778782e1e2 + languageName: node + linkType: hard + +"@tanstack/table-core@npm:8.10.7": + version: 8.10.7 + resolution: "@tanstack/table-core@npm:8.10.7" + checksum: 2a364917e7ab051ef3f33d6f18e5e1ddb75cfed4b5ee0e2b9c74a8cb72d3b86cdd4ffbab67565c68b4333f761b6fde9a7215196387a9a3b3d5811119d8859bad + languageName: node + linkType: hard + "@testing-library/dom@npm:^8.11.1": version: 8.20.1 resolution: "@testing-library/dom@npm:8.20.1" @@ -7170,13 +7197,13 @@ __metadata: linkType: hard "@types/react@npm:*, @types/react@npm:>=16.9.11": - version: 18.2.42 - resolution: "@types/react@npm:18.2.42" + version: 18.2.43 + resolution: "@types/react@npm:18.2.43" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: d2019afdf48303a3a598a97cc9dd2284e3c04b369e791f6ba3c33232b7f8645daff97b093a19f8b3ce75ac8a261b47552cb4513226ab16d843eb9443b0f91844 + checksum: e7e4da18c7b14e4b8b1ea630d1d8224835698f2bb2485766455bfb9dea93b8ee6cc549a9fe1cb10c984e62685db44fcfb61e8fac913b008cd30a92087f25b9df languageName: node linkType: hard @@ -7991,25 +8018,25 @@ __metadata: linkType: hard "@whatwg-node/node-fetch@npm:^0.5.0": - version: 0.5.1 - resolution: "@whatwg-node/node-fetch@npm:0.5.1" + version: 0.5.2 + resolution: "@whatwg-node/node-fetch@npm:0.5.2" dependencies: + "@kamilkisiela/fast-url-parser": ^1.1.4 "@whatwg-node/events": ^0.1.0 busboy: ^1.6.0 fast-querystring: ^1.1.1 - fast-url-parser: ^1.1.3 tslib: ^2.3.1 - checksum: eb0dd14ed97fb906b1c1c6b6dbfb153c8a07d75f2170a9dae2d92649349a8204bb92e07ca70921460948f015ce3b994749519683176ef6904aab38baf0b716a1 + checksum: 2a07dbe8fd50c69f36190570fcd639b13555060facee6a98871bbf1183d92cfe3435db56b225a43704ee38f9b3290bcbac2738cefc97673578c5b8fdb7c73031 languageName: node linkType: hard "@whatwg-node/server@npm:^0.9.1": - version: 0.9.18 - resolution: "@whatwg-node/server@npm:0.9.18" + version: 0.9.20 + resolution: "@whatwg-node/server@npm:0.9.20" dependencies: "@whatwg-node/fetch": ^0.9.10 tslib: ^2.3.1 - checksum: 1899a58f1ede93ef02a6b44bcc59a1290a7ab5c4d1057bfe2f032c439c6e5c53545406db58ac008f70ca0b44e1f3eaa73758b5b146c87eba23d7a8e7df904fce + checksum: ca2660260eaa4fd969072e2e63a1296708200faa03a6cbe09ded91d0c19e2c498cd0e8c54a6db4c6f41e21b24799ce2488157314ca2605ab27808d311ab90584 languageName: node linkType: hard @@ -9447,7 +9474,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.21.9, browserslist@npm:^4.22.2": +"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.22.2": version: 4.22.2 resolution: "browserslist@npm:4.22.2" dependencies: @@ -9696,9 +9723,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001565": - version: 1.0.30001566 - resolution: "caniuse-lite@npm:1.0.30001566" - checksum: 0f9084bf9f7d5c0a9ddb200c2baddb25dd2ad5a2f205f01e7b971f3e98e9a7bb23c2d86bae48237e9bc9782b682cffaaf3406d936937ab9844987dbe2a6401f2 + version: 1.0.30001568 + resolution: "caniuse-lite@npm:1.0.30001568" + checksum: 7092aaa246dc8531fbca5b47be91e92065db7e5c04cc9e3d864e848f8f1be769ac6754429e843a5e939f7331a771e8b0a1bc3b13495c66b748c65e2f5bdb1220 languageName: node linkType: hard @@ -11841,9 +11868,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.4.601": - version: 1.4.607 - resolution: "electron-to-chromium@npm:1.4.607" - checksum: cc31233eaf2a6bb6268f97365861a4411db6823bec59126658245d4aec742cfeacb09135ada6321d27cfe74f1b72f04ff53cf2f5ac675c1b81deab035f97ab28 + version: 1.4.609 + resolution: "electron-to-chromium@npm:1.4.609" + checksum: 4ef3c32b11adc01ed8227d7bdbe0978b436b817e6b3bd09f19b42afbf9affdb6ddf99f4d20a3b28a494772a2985df12ec95abca849a38cccb217c4ee338561bb languageName: node linkType: hard @@ -13877,11 +13904,11 @@ __metadata: linkType: hard "globals@npm:^13.19.0": - version: 13.23.0 - resolution: "globals@npm:13.23.0" + version: 13.24.0 + resolution: "globals@npm:13.24.0" dependencies: type-fest: ^0.20.2 - checksum: 194c97cf8d1ef6ba59417234c2386549c4103b6e5f24b1ff1952de61a4753e5d2069435ba629de711a6480b1b1d114a98e2ab27f85e966d5a10c319c3bbd3dc3 + checksum: 56066ef058f6867c04ff203b8a44c15b038346a62efbc3060052a1016be9f56f4cf0b2cd45b74b22b81e521a889fc7786c73691b0549c2f3a6e825b3d394f43c languageName: node linkType: hard @@ -14666,7 +14693,7 @@ __metadata: languageName: node linkType: hard -"import-in-the-middle@npm:1.4.2": +"import-in-the-middle@npm:1.4.2, import-in-the-middle@npm:^1.4.2": version: 1.4.2 resolution: "import-in-the-middle@npm:1.4.2" dependencies: @@ -14678,18 +14705,6 @@ __metadata: languageName: node linkType: hard -"import-in-the-middle@npm:^1.4.2": - version: 1.5.0 - resolution: "import-in-the-middle@npm:1.5.0" - dependencies: - acorn: ^8.8.2 - acorn-import-assertions: ^1.9.0 - cjs-module-lexer: ^1.2.2 - module-details-from-path: ^1.0.3 - checksum: e58a105aef1b8098b418768c1bd108e09c07ab6b34d7458f50ce710e045dedd7e7dc440e6de2c89fde167604801b26c4625f3c7e19cd2d389a7744d46bc24c22 - languageName: node - linkType: hard - "import-local@npm:^3.0.2": version: 3.1.0 resolution: "import-local@npm:3.1.0" @@ -20397,6 +20412,7 @@ __metadata: dependencies: "@netlify/zip-it-and-ship-it": ^9.27.0 "@redwoodjs/core": 6.4.2 + "@tanstack/react-table": ^8.10.7 fsevents: ^2.3.3 languageName: unknown linkType: soft @@ -21409,12 +21425,12 @@ __metadata: linkType: hard "streamx@npm:^2.15.0": - version: 2.15.5 - resolution: "streamx@npm:2.15.5" + version: 2.15.6 + resolution: "streamx@npm:2.15.6" dependencies: fast-fifo: ^1.1.0 queue-tick: ^1.0.1 - checksum: 52e0ec94026d67c9e2e2e1090f05e5b138c2f2822462d9a8ef4a4805625a31d103e55ea5267fcd9bfe041374926424e42aec2dda28a85cb9de42c2a16d416d94 + checksum: 37a245f5cee4c33fcb8b018ccb935bad6eab423f05b0d14d018e63dbd2670bb109a69442e961a195b750c2c774f613c19476d11bd727d645eedb655d2dba234b languageName: node linkType: hard @@ -21693,8 +21709,8 @@ __metadata: linkType: hard "svgo@npm:^3.0.2": - version: 3.0.5 - resolution: "svgo@npm:3.0.5" + version: 3.1.0 + resolution: "svgo@npm:3.1.0" dependencies: "@trysound/sax": 0.2.0 commander: ^7.2.0 @@ -21705,7 +21721,7 @@ __metadata: picocolors: ^1.0.0 bin: svgo: ./bin/svgo - checksum: f6f4dcb704e58b47d3aea9370b967138cc02c16dfcb1df2b8ceeb08e35bca283a9396f225868d53f1e73dbb0f4109f6c0b9dead487562f2fc4ecce7c4c3c6e2b + checksum: c07d49757264d9122090e8b6c674c25d25608feec7eb5df5276f8c8e3ec113e9b515ffc3cb5b57a4c24942980b15b5078321105a15f379650271dc1f25b05eb6 languageName: node linkType: hard @@ -23655,8 +23671,8 @@ __metadata: linkType: hard "ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.4.2": - version: 8.14.2 - resolution: "ws@npm:8.14.2" + version: 8.15.0 + resolution: "ws@npm:8.15.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -23665,7 +23681,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 3ca0dad26e8cc6515ff392b622a1467430814c463b3368b0258e33696b1d4bed7510bc7030f7b72838b9fdeb8dbd8839cbf808367d6aae2e1d668ce741d4308b + checksum: ca15c590aa49bc0197223b8ab7d15e7362ae6c4011d91ed0e5cd5867cdd5497fd71470ea36314833b4b078929fe64dc4ba7748b1e58e50a0f8e41f147db2b464 languageName: node linkType: hard From f735a33412b2abf4f13e859a3d7b5e5b26fc2856 Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Mon, 11 Dec 2023 21:46:52 -0500 Subject: [PATCH 05/11] feature/CPF-3 move column helper functions into a separate file, clean up Uploads table, add Bootstrap sorting icons --- package-lock.json | 21 ++++ package.json | 1 - web/package.json | 2 + web/src/components/Upload/Uploads/Uploads.tsx | 98 ++++++------------- web/src/components/Upload/Uploads/columns.tsx | 46 +++++++++ web/src/scss/custom.scss | 6 ++ yarn.lock | 60 +++++++----- 7 files changed, 141 insertions(+), 93 deletions(-) create mode 100644 web/src/components/Upload/Uploads/columns.tsx diff --git a/package-lock.json b/package-lock.json index 4d359589..510cc0b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "version": "3.7.0", "dependencies": { "@tanstack/react-table": "^8.10.7", + "bootstrap-icons": "^1.11.2", "fsevents": "^2.3.3" }, "devDependencies": { @@ -11956,6 +11957,21 @@ "@popperjs/core": "^2.11.8" } }, + "node_modules/bootstrap-icons": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.2.tgz", + "integrity": "sha512-TgdiPv+IM9tgDb+dsxrnGIyocsk85d2M7T0qIgkvPedZeoZfyeG/j+yiAE4uHCEayKef2RP05ahQ0/e9Sv75Wg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ] + }, "node_modules/bowser": { "version": "2.11.0", "license": "MIT" @@ -36234,6 +36250,11 @@ "version": "5.3.2", "requires": {} }, + "bootstrap-icons": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.2.tgz", + "integrity": "sha512-TgdiPv+IM9tgDb+dsxrnGIyocsk85d2M7T0qIgkvPedZeoZfyeG/j+yiAE4uHCEayKef2RP05ahQ0/e9Sv75Wg==" + }, "bowser": { "version": "2.11.0" }, diff --git a/package.json b/package.json index a0cbcfeb..0950844c 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "seed": "yarn rw exec seed" }, "dependencies": { - "@tanstack/react-table": "^8.10.7", "fsevents": "^2.3.3" }, "packageManager": "yarn@3.7.0", diff --git a/web/package.json b/web/package.json index 8a6145d5..27cbc1b6 100644 --- a/web/package.json +++ b/web/package.json @@ -15,7 +15,9 @@ "@redwoodjs/forms": "6.4.2", "@redwoodjs/router": "6.4.2", "@redwoodjs/web": "6.4.2", + "@tanstack/react-table": "^8.10.7", "bootstrap": "^5.3.2", + "bootstrap-icons": "^1.11.2", "humanize-string": "2.1.0", "prop-types": "15.8.1", "react": "18.2.0", diff --git a/web/src/components/Upload/Uploads/Uploads.tsx b/web/src/components/Upload/Uploads/Uploads.tsx index 7f497b89..956563e2 100644 --- a/web/src/components/Upload/Uploads/Uploads.tsx +++ b/web/src/components/Upload/Uploads/Uploads.tsx @@ -3,62 +3,21 @@ import { getCoreRowModel, getPaginationRowModel, getSortedRowModel, - createColumnHelper, flexRender, } from '@tanstack/react-table' import Table from 'react-bootstrap/Table' import type { FindUploads } from 'types/graphql' -import { Link, routes } from '@redwoodjs/router' +import { columnDefs } from './columns' const UploadsList = ({ uploads }: FindUploads) => { const data = React.useMemo(() => uploads, [uploads]) const [sorting, setSorting] = React.useState([]) - const columnHelper = createColumnHelper() - - const columns = [ - columnHelper.accessor('id', { - cell: (info) => { - const id = info.getValue() as number - - return ( - - {id} - - ) - }, - header: () => ID, - }), - columnHelper.accessor('agency.code', { - cell: (info) => info.getValue(), - header: () => Agency, - }), - columnHelper.accessor('expenditureCategory.code', { - cell: (info) => info.getValue(), - header: () => EC Code, - }), - columnHelper.accessor('uploadedBy.email', { - cell: (info) => info.getValue(), - header: () => Uploaded By, - }), - columnHelper.accessor('filename', { - cell: (info) => info.getValue(), - header: () => Filename, - }), - columnHelper.accessor('validated_at', { - cell: (info) => info.getValue(), - header: () => Validated?, - }), - ] - const tableInstance = useReactTable({ data, - columns, + columns: columnDefs, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), @@ -68,35 +27,42 @@ const UploadsList = ({ uploads }: FindUploads) => { onSortingChange: setSorting, }) + const createColumnHeader = (header) => { + const renderIcon = (sortDirection: 'asc' | 'desc' | null) => { + const iconClass = sortDirection === 'asc' ? 'bi-sort-up' : 'bi-sort-down' + const classNames = `bi ${ + sortDirection ? iconClass : 'bi-sort-up inactive' + }` + + return ( + + {' '} + {' '} + + ) + } + + return ( + + ) + } + return (
IdAgencyEC CodeUploaded ByFilenameValidated?
+ {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + {header.column.getIsSorted() === 'asc' ? ( + 🔼 // For ascending order + ) : header.column.getIsSorted() === 'desc' ? ( + 🔽 // For descending order + ) : null} +
- - {upload.id} - - - {truncate(upload.agency.name)} - - {truncate(upload.expenditureCategory.code)} - - {truncate(upload.uploadedBy.email)} - - {upload.filename}{' '} - {/* TODO: Add file download when the API is ready */} - {/* */} - Validation here!
+ {flexRender(cell.column.columnDef.cell, cell.getContext())} +
+ {renderIcon(header.column.getIsSorted())} + {!header.isPlaceholder && + flexRender(header.column.columnDef.header, header.getContext())} +
{tableInstance.getHeaderGroups().map((headerGroup) => ( - {headerGroup.headers.map((header) => { - return ( - - ) - })} + {headerGroup.headers.map((header) => createColumnHeader(header))} ))} diff --git a/web/src/components/Upload/Uploads/columns.tsx b/web/src/components/Upload/Uploads/columns.tsx new file mode 100644 index 00000000..ed08bcde --- /dev/null +++ b/web/src/components/Upload/Uploads/columns.tsx @@ -0,0 +1,46 @@ +import { createColumnHelper } from '@tanstack/react-table' + +import { Link, routes } from '@redwoodjs/router' + +const columnHelper = createColumnHelper() + +function valueAsLink(cell): JSX.Element { + const value = cell.getValue() + + return ( + + {value} + + ) +} + +export const columnDefs = [ + columnHelper.accessor('id', { + cell: valueAsLink, + header: 'ID', + }), + columnHelper.accessor('agency.code', { + cell: (info) => info.getValue(), + header: 'Agency', + }), + columnHelper.accessor('expenditureCategory.code', { + cell: (info) => info.getValue(), + header: 'EC Code', + }), + columnHelper.accessor('uploadedBy.email', { + cell: (info) => info.getValue(), + header: 'Uploaded By', + }), + columnHelper.accessor('filename', { + cell: (info) => info.getValue(), + header: 'Filename', + }), + columnHelper.accessor('validated_at', { + cell: (info) => info.getValue(), + header: 'Validated?', + }), +] diff --git a/web/src/scss/custom.scss b/web/src/scss/custom.scss index dee7b232..2b197905 100644 --- a/web/src/scss/custom.scss +++ b/web/src/scss/custom.scss @@ -65,7 +65,13 @@ span.invalid-feedback { display: block; } +// Gray out inactive icons +.bi.inactive { + color: $raw-gray-400; +} + @import '~bootstrap/scss/bootstrap'; +@import 'bootstrap-icons/font/bootstrap-icons.css'; // SET USDR FONTS @import './fonts.scss'; diff --git a/yarn.lock b/yarn.lock index cd91b55a..53588613 100644 --- a/yarn.lock +++ b/yarn.lock @@ -927,9 +927,9 @@ __metadata: languageName: node linkType: hard -"@babel/helper-define-polyfill-provider@npm:^0.4.3": - version: 0.4.3 - resolution: "@babel/helper-define-polyfill-provider@npm:0.4.3" +"@babel/helper-define-polyfill-provider@npm:^0.4.4": + version: 0.4.4 + resolution: "@babel/helper-define-polyfill-provider@npm:0.4.4" dependencies: "@babel/helper-compilation-targets": ^7.22.6 "@babel/helper-plugin-utils": ^7.22.5 @@ -938,7 +938,7 @@ __metadata: resolve: ^1.14.2 peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 5d21e3f47b320e4b5b644195ec405e7ebc3739e48e65899efc808c5fa9c3bf5b06ce0d8ff5246ca99d1411e368f4557bc66730196c5781a5c4e986ee703bee79 + checksum: 2453cdd79f18a4cb8653d8a7e06b2eb0d8e31bae0d35070fc5abadbddca246a36d82b758064b421cca49b48d0e696d331d54520ba8582c1d61fb706d6d831817 languageName: node linkType: hard @@ -6332,8 +6332,8 @@ __metadata: linkType: hard "@smithy/signature-v4@npm:^2.0.0": - version: 2.0.17 - resolution: "@smithy/signature-v4@npm:2.0.17" + version: 2.0.18 + resolution: "@smithy/signature-v4@npm:2.0.18" dependencies: "@smithy/eventstream-codec": ^2.0.15 "@smithy/is-array-buffer": ^2.0.0 @@ -6343,7 +6343,7 @@ __metadata: "@smithy/util-uri-escape": ^2.0.0 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 8449ae428dc6f3c98ad09b11b769776ba2980d7c06d2d891c5c15f26615b28dd6737056be3a0e0304f3042f2d853a7c0812260be5c5ecf436d4a22bcc8a0c216 + checksum: 3e4c41fb4c6aacda8f795d1b4d8075774b241a8e3d69b40fa1530ec9e195b4562300d3023c1dca4ae9e0d07f3262c451708f07869d0c6386bcfdabe976f020da languageName: node linkType: hard @@ -8031,12 +8031,12 @@ __metadata: linkType: hard "@whatwg-node/server@npm:^0.9.1": - version: 0.9.20 - resolution: "@whatwg-node/server@npm:0.9.20" + version: 0.9.21 + resolution: "@whatwg-node/server@npm:0.9.21" dependencies: "@whatwg-node/fetch": ^0.9.10 tslib: ^2.3.1 - checksum: ca2660260eaa4fd969072e2e63a1296708200faa03a6cbe09ded91d0c19e2c498cd0e8c54a6db4c6f41e21b24799ce2488157314ca2605ab27808d311ab90584 + checksum: 5371af1eb3ff12fcd694dd2cfb93cf3c5baaf21fc2dd500022b9953f8af23bf65c552087c122a7990aced3f01a2083b490601ce52ccc96c0778f584fdd8f4766 languageName: node linkType: hard @@ -9040,38 +9040,38 @@ __metadata: linkType: hard "babel-plugin-polyfill-corejs2@npm:^0.4.6": - version: 0.4.6 - resolution: "babel-plugin-polyfill-corejs2@npm:0.4.6" + version: 0.4.7 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.7" dependencies: "@babel/compat-data": ^7.22.6 - "@babel/helper-define-polyfill-provider": ^0.4.3 + "@babel/helper-define-polyfill-provider": ^0.4.4 semver: ^6.3.1 peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 08896811df31530be6a9bcdd630cb9fd4b5ae5181039d18db3796efbc54e38d57a42af460845c10a04434e1bc45c0d47743c7e6c860383cc6b141083cde22030 + checksum: b3c84ce44d00211c919a94f76453fb2065861612f3e44862eb7acf854e325c738a7441ad82690deba2b6fddfa2ad2cf2c46960f46fab2e3b17c6ed4fd2d73b38 languageName: node linkType: hard "babel-plugin-polyfill-corejs3@npm:^0.8.5": - version: 0.8.6 - resolution: "babel-plugin-polyfill-corejs3@npm:0.8.6" + version: 0.8.7 + resolution: "babel-plugin-polyfill-corejs3@npm:0.8.7" dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.3 + "@babel/helper-define-polyfill-provider": ^0.4.4 core-js-compat: ^3.33.1 peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 36951c2edac42ac0f05b200502e90d77bf66ccee5b52e2937d23496c6ef2372cce31b8c64144da374b77bd3eb65e2721703a52eac56cad16a152326c092cbf77 + checksum: 51bc215ab0c062bbb2225d912f69f8a6705d1837c8e01f9651307b5b937804287c1d73ebd8015689efcc02c3c21f37688b9ee6f5997635619b7a9cc4b7d9908d languageName: node linkType: hard "babel-plugin-polyfill-regenerator@npm:^0.5.3": - version: 0.5.3 - resolution: "babel-plugin-polyfill-regenerator@npm:0.5.3" + version: 0.5.4 + resolution: "babel-plugin-polyfill-regenerator@npm:0.5.4" dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.3 + "@babel/helper-define-polyfill-provider": ^0.4.4 peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 2bb546582cda1870d19e646a7183baeb2cccd56e0ef3e4eaeabd28e120daf17cb87399194a9ccdcf32506bcaa68d23e73440fc8ab990a7a0f8c5a77c12d5d4bc + checksum: 461b735c6c0eca3c7b4434d14bfa98c2ab80f00e2bdc1c69eb46d1d300092a9786d76bbd3ee55e26d2d1a2380c14592d8d638e271dfd2a2b78a9eacffa3645d1 languageName: node linkType: hard @@ -9316,6 +9316,13 @@ __metadata: languageName: node linkType: hard +"bootstrap-icons@npm:^1.11.2": + version: 1.11.2 + resolution: "bootstrap-icons@npm:1.11.2" + checksum: 3dfd4601bf8a48450310a8bffe1ab9f74ca3b19336257bb9dbc1400bd72a4252e60422e08062a0afa0f4cf51b60749e46958f7dc38a26a12f92b15ec866ea4cd + languageName: node + linkType: hard + "bootstrap@npm:^5.3.2": version: 5.3.2 resolution: "bootstrap@npm:5.3.2" @@ -11868,9 +11875,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.4.601": - version: 1.4.609 - resolution: "electron-to-chromium@npm:1.4.609" - checksum: 4ef3c32b11adc01ed8227d7bdbe0978b436b817e6b3bd09f19b42afbf9affdb6ddf99f4d20a3b28a494772a2985df12ec95abca849a38cccb217c4ee338561bb + version: 1.4.610 + resolution: "electron-to-chromium@npm:1.4.610" + checksum: 30e57a1483717e6e27882e7e35b167258b669f44a4e66f4f40460825b77c12646140d220f5e1f95668890fc76dd511c93fa73c6374cbf443fc78077d9634864d languageName: node linkType: hard @@ -20412,7 +20419,6 @@ __metadata: dependencies: "@netlify/zip-it-and-ship-it": ^9.27.0 "@redwoodjs/core": 6.4.2 - "@tanstack/react-table": ^8.10.7 fsevents: ^2.3.3 languageName: unknown linkType: soft @@ -23113,11 +23119,13 @@ __metadata: "@redwoodjs/router": 6.4.2 "@redwoodjs/vite": 6.4.2 "@redwoodjs/web": 6.4.2 + "@tanstack/react-table": ^8.10.7 "@types/node": ^20.10.4 "@types/react": 18.2.39 "@types/react-dom": 18.2.17 autoprefixer: ^10.4.16 bootstrap: ^5.3.2 + bootstrap-icons: ^1.11.2 humanize-string: 2.1.0 postcss: ^8.4.31 postcss-loader: ^7.3.3 From ae09c5265a6c025a235d85f031ea31267edb6e72 Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Mon, 11 Dec 2023 23:48:50 -0500 Subject: [PATCH 06/11] feature/3 replace bootstrap icons for sort, WIP filter --- .../Upload/Uploads/DebouncedInput.tsx | 32 +++++++++++++++++++ web/src/components/Upload/Uploads/Uploads.tsx | 23 +++++++++---- web/src/scss/custom.scss | 4 +++ 3 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 web/src/components/Upload/Uploads/DebouncedInput.tsx diff --git a/web/src/components/Upload/Uploads/DebouncedInput.tsx b/web/src/components/Upload/Uploads/DebouncedInput.tsx new file mode 100644 index 00000000..398a65b0 --- /dev/null +++ b/web/src/components/Upload/Uploads/DebouncedInput.tsx @@ -0,0 +1,32 @@ +import { useState, useEffect } from 'react' + +function DebouncedInput({ + value: initialValue, + onChange, + debounce = 500, + ...props +}) { + const [value, setValue] = useState(initialValue) + + useEffect(() => { + setValue(initialValue) + }, [initialValue]) + + useEffect(() => { + const timeout = setTimeout(() => { + onChange(value) + }, debounce) + + return () => clearTimeout(timeout) + }, [value]) + + return ( + setValue(e.target.value)} + /> + ) +} + +export default DebouncedInput diff --git a/web/src/components/Upload/Uploads/Uploads.tsx b/web/src/components/Upload/Uploads/Uploads.tsx index 956563e2..0d10b168 100644 --- a/web/src/components/Upload/Uploads/Uploads.tsx +++ b/web/src/components/Upload/Uploads/Uploads.tsx @@ -3,6 +3,7 @@ import { getCoreRowModel, getPaginationRowModel, getSortedRowModel, + getFilteredRowModel, flexRender, } from '@tanstack/react-table' import Table from 'react-bootstrap/Table' @@ -14,6 +15,7 @@ const UploadsList = ({ uploads }: FindUploads) => { const data = React.useMemo(() => uploads, [uploads]) const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState([]) const tableInstance = useReactTable({ data, @@ -23,21 +25,30 @@ const UploadsList = ({ uploads }: FindUploads) => { getSortedRowModel: getSortedRowModel(), state: { sorting, + columnFilters, }, + onColumnFiltersChange: setColumnFilters, onSortingChange: setSorting, + getFilteredRowModel: getFilteredRowModel(), }) const createColumnHeader = (header) => { const renderIcon = (sortDirection: 'asc' | 'desc' | null) => { - const iconClass = sortDirection === 'asc' ? 'bi-sort-up' : 'bi-sort-down' - const classNames = `bi ${ - sortDirection ? iconClass : 'bi-sort-up inactive' - }` + const iconMapping = { + asc: 'bi-arrow-up', + desc: 'bi-arrow-down', + inactive: 'bi-arrow-down-up inactive', + } + + const iconClass = sortDirection + ? iconMapping[sortDirection] + : iconMapping['inactive'] + + const classNames = `bi ${iconClass} me-1` return ( - {' '} - {' '} + ) } diff --git a/web/src/scss/custom.scss b/web/src/scss/custom.scss index 2b197905..8d153d9c 100644 --- a/web/src/scss/custom.scss +++ b/web/src/scss/custom.scss @@ -70,6 +70,10 @@ span.invalid-feedback { color: $raw-gray-400; } +.bi-arrow-down-up { + font-size: 0.9rem; +} + @import '~bootstrap/scss/bootstrap'; @import 'bootstrap-icons/font/bootstrap-icons.css'; From bdf327c0f8e8306a8b806d9e286e69262584856c Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Wed, 13 Dec 2023 14:40:00 -0500 Subject: [PATCH 07/11] feature/CPF-3 separate TableBuilder headers and columns into their own components, cleanup --- .../TableBuilder/DebouncedInput.tsx | 36 ++++ .../components/TableBuilder/TableBuilder.tsx | 102 +++++++++++ .../components/TableBuilder/TableHeader.tsx | 56 ++++++ web/src/components/TableBuilder/TableRow.tsx | 15 ++ .../components/Upload/NewUpload/NewUpload.tsx | 4 +- .../components/Upload/Uploads/OldUploads.tsx | 164 ++++++++++++++++++ web/src/components/Upload/Uploads/Uploads.tsx | 102 ++--------- web/src/components/Upload/Uploads/columns.tsx | 77 ++++++-- .../Upload/UploadsCell/UploadsCell.tsx | 3 + web/src/scss/custom.scss | 2 +- web/src/scss/tables.scss | 7 + 11 files changed, 463 insertions(+), 105 deletions(-) create mode 100644 web/src/components/TableBuilder/DebouncedInput.tsx create mode 100644 web/src/components/TableBuilder/TableBuilder.tsx create mode 100644 web/src/components/TableBuilder/TableHeader.tsx create mode 100644 web/src/components/TableBuilder/TableRow.tsx create mode 100644 web/src/components/Upload/Uploads/OldUploads.tsx diff --git a/web/src/components/TableBuilder/DebouncedInput.tsx b/web/src/components/TableBuilder/DebouncedInput.tsx new file mode 100644 index 00000000..570d8c51 --- /dev/null +++ b/web/src/components/TableBuilder/DebouncedInput.tsx @@ -0,0 +1,36 @@ +/* + This component provides a debounced input field, + delaying the onChange event until a specified timeout + to optimize performance in scenarios like filtering table data. +*/ + +function DebouncedInput({ + value: initialValue, + onChange, + debounce = 500, + ...props +}) { + const [value, setValue] = React.useState(initialValue) + + React.useEffect(() => { + setValue(initialValue) + }, [initialValue]) + + React.useEffect(() => { + const timeout = setTimeout(() => { + onChange(value) + }, debounce) + + return () => clearTimeout(timeout) + }, [value]) + + return ( + setValue(e.target.value)} + /> + ) +} + +export default DebouncedInput diff --git a/web/src/components/TableBuilder/TableBuilder.tsx b/web/src/components/TableBuilder/TableBuilder.tsx new file mode 100644 index 00000000..5d3bb8da --- /dev/null +++ b/web/src/components/TableBuilder/TableBuilder.tsx @@ -0,0 +1,102 @@ +import { useMemo, useState } from 'react' + +import { + useReactTable, + getCoreRowModel, + getSortedRowModel, + getFilteredRowModel, +} from '@tanstack/react-table' +import { Button } from 'react-bootstrap' +import Table from 'react-bootstrap/Table' + +import TableHeader from './TableHeader' +import TableRow from './TableRow' + +function TableBuilder({ data, columns, filterableInputs = [] }) { + const [filters, setFilters] = useState({}) + const [sorting, setSorting] = React.useState([]) + + const filteredData = useMemo(() => { + if (!filterableInputs) return data + + return data.filter((row) => + filterableInputs.every((input) => { + console.log('Row', row) + + let value = '' + + // if (typeof input === 'function') { + // value = input(row) + // } + // else { + + const rawValue = row[input] + // Check if the value is not undefined and is a string or can be converted to a string + value = + typeof rawValue === 'string' || typeof rawValue === 'number' + ? rawValue.toString() + : '' + + // console.log(value.includes(filters[input.toString()])) + // Check if value is not undefined before calling .toString() + return value.includes(filters[input.toString()] || '') + }) + ) + }, [data, filters, filterableInputs]) + + const table = useReactTable({ + data: filteredData, + columns: columns, + state: { + sorting, + // columnFilters, // should be used + }, + getSortedRowModel: getSortedRowModel(), + onSortingChange: setSorting, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + }) + + const handleFilterChange = + (accessor: string) => (e: React.ChangeEvent) => { + setFilters({ ...filters, [accessor]: e.target.value }) + } + + return ( +
+
- {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext() - )} - - {header.column.getIsSorted() === 'asc' ? ( - 🔼 // For ascending order - ) : header.column.getIsSorted() === 'desc' ? ( - 🔽 // For descending order - ) : null} -
+ + {!!filterableInputs.length && ( + + + + )} + {table.getHeaderGroups().map((headerGroup) => ( + + ))} + + + {table.getRowModel().rows.map((row) => ( + + ))} + +
+ +
+
+ ) +} + +export default TableBuilder diff --git a/web/src/components/TableBuilder/TableHeader.tsx b/web/src/components/TableBuilder/TableHeader.tsx new file mode 100644 index 00000000..39610b14 --- /dev/null +++ b/web/src/components/TableBuilder/TableHeader.tsx @@ -0,0 +1,56 @@ +import { flexRender } from '@tanstack/react-table' + +const TableHeader = ({ + headerGroup, + filters, + filterableInputs, + handleFilterChange, +}) => { + const renderSortingIcon = (sortDirection: 'asc' | 'desc' | null) => { + const iconMapping = { + asc: 'bi-arrow-up', + desc: 'bi-arrow-down', + inactive: 'bi-arrow-down-up inactive', + } + + const iconClass = sortDirection + ? iconMapping[sortDirection] + : iconMapping['inactive'] + + return + } + + const createColumnHeader = (header) => { + return ( + + ) + } + + return ( + + {headerGroup.headers.map((header) => ( + + {createColumnHeader(header)} + {/* {console.log('Header def', header.column)} */} + + {filterableInputs.includes(header.id.toString()) && ( + + )} + + ))} + + ) +} + +export default TableHeader diff --git a/web/src/components/TableBuilder/TableRow.tsx b/web/src/components/TableBuilder/TableRow.tsx new file mode 100644 index 00000000..f5093ab8 --- /dev/null +++ b/web/src/components/TableBuilder/TableRow.tsx @@ -0,0 +1,15 @@ +import { flexRender } from '@tanstack/react-table' + +const TableRow = ({ row }) => { + return ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + ) +} + +export default TableRow diff --git a/web/src/components/Upload/NewUpload/NewUpload.tsx b/web/src/components/Upload/NewUpload/NewUpload.tsx index 5ec33137..b1e30872 100644 --- a/web/src/components/Upload/NewUpload/NewUpload.tsx +++ b/web/src/components/Upload/NewUpload/NewUpload.tsx @@ -1,11 +1,11 @@ +import type { CreateUploadInput } from 'types/graphql' + import { navigate, routes } from '@redwoodjs/router' import { useMutation } from '@redwoodjs/web' import { toast } from '@redwoodjs/web/toast' import UploadForm from 'src/components/Upload/UploadForm' -import type { CreateUploadInput } from 'types/graphql' - const CREATE_UPLOAD_MUTATION = gql` mutation CreateUploadMutation($input: CreateUploadInput!) { createUpload(input: $input) { diff --git a/web/src/components/Upload/Uploads/OldUploads.tsx b/web/src/components/Upload/Uploads/OldUploads.tsx new file mode 100644 index 00000000..33897e32 --- /dev/null +++ b/web/src/components/Upload/Uploads/OldUploads.tsx @@ -0,0 +1,164 @@ +import React from 'react' + +import { + useReactTable, + getCoreRowModel, + getPaginationRowModel, + getSortedRowModel, + getFilteredRowModel, + flexRender, +} from '@tanstack/react-table' +import Table from 'react-bootstrap/Table' +import type { FindUploads } from 'types/graphql' + +import DebouncedInput from 'src/components/Upload/Uploads/DebouncedInput' + +import { columnDefs } from './columns' + +const Filter = ({ column, table }: any) => { + const columnFilterValue = column.getFilterValue() + + const sortedUniqueValues = React.useMemo( + () => Array.from(column.getFacetedUniqueValues().keys()).sort(), + [column.getFacetedUniqueValues()] + ) + + return ( + <> + + {sortedUniqueValues.slice(0, 5000).map((value: any) => ( + +

{column.name}

+ column.setFilterValue(value)} + placeholder={column.name} + className="" + list={column.id + 'list'} + /> + + ) +} + +const UploadsList = ({ uploads }: FindUploads) => { + const data = React.useMemo(() => uploads, [uploads]) + + const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState([]) + + const tableInstance = useReactTable({ + data, + columns: columnDefs, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + state: { + sorting, + columnFilters, + }, + onColumnFiltersChange: setColumnFilters, + onSortingChange: setSorting, + getFilteredRowModel: getFilteredRowModel(), + }) + + const createColumnHeader = (header) => { + const renderIcon = (sortDirection: 'asc' | 'desc' | null) => { + const iconMapping = { + asc: 'bi-arrow-up', + desc: 'bi-arrow-down', + inactive: 'bi-arrow-down-up inactive', + } + + const iconClass = sortDirection + ? iconMapping[sortDirection] + : iconMapping['inactive'] + + const classNames = `bi ${iconClass} me-1` + + return ( + + + + ) + } + + return ( + + {renderIcon(header.column.getIsSorted())} + {!header.isPlaceholder && + flexRender(header.column.columnDef.header, header.getContext())} + + ) + } + + return ( +
+ + + {tableInstance.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header: any) => { + // Always create the column header + const columnHeaderElement = createColumnHeader(header) + + // Conditionally create the filter element + const filterElement = header.column.getCanFilter() ? ( +
+ +
+ ) : null + + // Return a fragment containing both the column header and the filter element (if applicable) + return ( + + {columnHeaderElement} + {filterElement} + + ) + })} + + ))} + + {/* Working but 2 loops */} + {/* {tableInstance.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return createColumnHeader(header) + })} + + {headerGroup.headers.map((header: any) => + header.column.getCanFilter() ? ( +
+ +
+ ) : null + )} + + + ))} */} + + + {tableInstance.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + ))} + + ))} + +
+ {flexRender(cell.column.columnDef.cell, cell.getContext())} +
+
+ ) +} + +export default UploadsList diff --git a/web/src/components/Upload/Uploads/Uploads.tsx b/web/src/components/Upload/Uploads/Uploads.tsx index 0d10b168..89dc0b6e 100644 --- a/web/src/components/Upload/Uploads/Uploads.tsx +++ b/web/src/components/Upload/Uploads/Uploads.tsx @@ -1,95 +1,27 @@ -import { - useReactTable, - getCoreRowModel, - getPaginationRowModel, - getSortedRowModel, - getFilteredRowModel, - flexRender, -} from '@tanstack/react-table' -import Table from 'react-bootstrap/Table' +import React from 'react' + import type { FindUploads } from 'types/graphql' +import TableBuilder from 'src/components/TableBuilder/TableBuilder' + import { columnDefs } from './columns' const UploadsList = ({ uploads }: FindUploads) => { - const data = React.useMemo(() => uploads, [uploads]) - - const [sorting, setSorting] = React.useState([]) - const [columnFilters, setColumnFilters] = React.useState([]) - - const tableInstance = useReactTable({ - data, - columns: columnDefs, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - state: { - sorting, - columnFilters, - }, - onColumnFiltersChange: setColumnFilters, - onSortingChange: setSorting, - getFilteredRowModel: getFilteredRowModel(), - }) - - const createColumnHeader = (header) => { - const renderIcon = (sortDirection: 'asc' | 'desc' | null) => { - const iconMapping = { - asc: 'bi-arrow-up', - desc: 'bi-arrow-down', - inactive: 'bi-arrow-down-up inactive', - } - - const iconClass = sortDirection - ? iconMapping[sortDirection] - : iconMapping['inactive'] - - const classNames = `bi ${iconClass} me-1` - - return ( - - - - ) - } - - return ( - - {renderIcon(header.column.getIsSorted())} - {!header.isPlaceholder && - flexRender(header.column.columnDef.header, header.getContext())} - - ) - } + const filterableInputs = [ + 'id', + 'agency_code', + 'agency.code', + 'expenditureCategory.code', + 'uploadedBy.email', + 'filename', + ] return ( -
- - - {tableInstance.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => createColumnHeader(header))} - - ))} - - - {tableInstance.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - ))} - - ))} - -
- {flexRender(cell.column.columnDef.cell, cell.getContext())} -
-
+ ) } diff --git a/web/src/components/Upload/Uploads/columns.tsx b/web/src/components/Upload/Uploads/columns.tsx index ed08bcde..e16e9f97 100644 --- a/web/src/components/Upload/Uploads/columns.tsx +++ b/web/src/components/Upload/Uploads/columns.tsx @@ -18,29 +18,72 @@ function valueAsLink(cell): JSX.Element { ) } +// export const columnDefs = [ +// columnHelper.accessor('id', { +// cell: valueAsLink, +// header: 'ID', +// }), +// columnHelper.accessor('agency.code', { +// cell: (info) => info.getValue(), +// header: 'Agency', +// }), +// columnHelper.accessor('expenditureCategory.code', { +// cell: (info) => info.getValue(), +// header: 'EC Code', +// }), +// columnHelper.accessor('uploadedBy.email', { +// cell: (info) => info.getValue(), +// header: 'Uploaded By', +// }), +// columnHelper.accessor('filename', { +// cell: (info) => info.getValue(), +// header: 'Filename', +// }), +// columnHelper.accessor('validated_at', { +// cell: (info) => info.getValue(), +// header: 'Validated?', +// }), +// ] + export const columnDefs = [ - columnHelper.accessor('id', { + { + accessorKey: 'id', cell: valueAsLink, - header: 'ID', - }), - columnHelper.accessor('agency.code', { + header: () => ID, + }, + { + accessorFn: (row) => row.agency.code, + id: 'agency_code', cell: (info) => info.getValue(), - header: 'Agency', - }), - columnHelper.accessor('expenditureCategory.code', { - cell: (info) => info.getValue(), - header: 'EC Code', - }), - columnHelper.accessor('uploadedBy.email', { + header: () => Agency, + }, + { + accessorFn: (row) => row.agency.code, + id: 'agency.code', cell: (info) => info.getValue(), - header: 'Uploaded By', - }), + header: () => Agency.Code, + }, + // { + // accessorFn: (row) => row.agency.code, + // id: "Agency", + // cell: (info) => info.getValue(), + // header: () => Agency, + // }, + + // columnHelper.accessor('expenditureCategory.code', { + // cell: (info) => info.getValue(), + // header: 'EC Code', + // }), + // columnHelper.accessor('uploadedBy.email', { + // cell: (info) => info.getValue(), + // header: 'Uploaded By', + // }), columnHelper.accessor('filename', { cell: (info) => info.getValue(), header: 'Filename', }), - columnHelper.accessor('validated_at', { - cell: (info) => info.getValue(), - header: 'Validated?', - }), + // columnHelper.accessor('validated_at', { + // cell: (info) => info.getValue(), + // header: 'Validated?', + // }), ] diff --git a/web/src/components/Upload/UploadsCell/UploadsCell.tsx b/web/src/components/Upload/UploadsCell/UploadsCell.tsx index c75fa37c..7795f951 100644 --- a/web/src/components/Upload/UploadsCell/UploadsCell.tsx +++ b/web/src/components/Upload/UploadsCell/UploadsCell.tsx @@ -18,6 +18,9 @@ export const QUERY = gql` id code } + agency_code: agency { + code + } organizationId reportingPeriodId expenditureCategory { diff --git a/web/src/scss/custom.scss b/web/src/scss/custom.scss index 8d153d9c..f42d8860 100644 --- a/web/src/scss/custom.scss +++ b/web/src/scss/custom.scss @@ -67,7 +67,7 @@ span.invalid-feedback { // Gray out inactive icons .bi.inactive { - color: $raw-gray-400; + color: $raw-gray-300; } .bi-arrow-down-up { diff --git a/web/src/scss/tables.scss b/web/src/scss/tables.scss index e69de29b..d77286ac 100644 --- a/web/src/scss/tables.scss +++ b/web/src/scss/tables.scss @@ -0,0 +1,7 @@ +// Sorting buttons +.table .btn-sort { + width: 100%; + font-weight: bold; + padding: 0; + border: none; +} \ No newline at end of file From 622b7ce00439ef1127fe5a488f784f2e05dacfb1 Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Wed, 13 Dec 2023 16:30:24 -0500 Subject: [PATCH 08/11] feature/CPF-3 add resetColumnFilters to reset button, add conditional styling if no filter is present --- .../TableBuilder/DebouncedInput.tsx | 1 + web/src/components/TableBuilder/Filter.tsx | 16 ++++ .../components/TableBuilder/TableBuilder.tsx | 51 +++--------- .../components/TableBuilder/TableHeader.tsx | 44 ++++++----- web/src/components/Upload/Uploads/Uploads.tsx | 5 +- web/src/components/Upload/Uploads/columns.tsx | 77 ++++--------------- .../Upload/UploadsCell/UploadsCell.tsx | 3 - web/src/scss/tables.scss | 6 ++ 8 files changed, 77 insertions(+), 126 deletions(-) create mode 100644 web/src/components/TableBuilder/Filter.tsx diff --git a/web/src/components/TableBuilder/DebouncedInput.tsx b/web/src/components/TableBuilder/DebouncedInput.tsx index 570d8c51..9f34c761 100644 --- a/web/src/components/TableBuilder/DebouncedInput.tsx +++ b/web/src/components/TableBuilder/DebouncedInput.tsx @@ -27,6 +27,7 @@ function DebouncedInput({ return ( setValue(e.target.value)} /> diff --git a/web/src/components/TableBuilder/Filter.tsx b/web/src/components/TableBuilder/Filter.tsx new file mode 100644 index 00000000..9d45af57 --- /dev/null +++ b/web/src/components/TableBuilder/Filter.tsx @@ -0,0 +1,16 @@ +import DebouncedInput from './DebouncedInput' + +function Filter({ column }) { + const columnFilterValue = column.getFilterValue() + + return ( + column.setFilterValue(value)} + placeholder="Search..." + /> + ) +} + +export default Filter diff --git a/web/src/components/TableBuilder/TableBuilder.tsx b/web/src/components/TableBuilder/TableBuilder.tsx index 5d3bb8da..b38ddeff 100644 --- a/web/src/components/TableBuilder/TableBuilder.tsx +++ b/web/src/components/TableBuilder/TableBuilder.tsx @@ -1,10 +1,11 @@ -import { useMemo, useState } from 'react' +import { useState } from 'react' import { useReactTable, getCoreRowModel, getSortedRowModel, getFilteredRowModel, + ColumnFiltersState, } from '@tanstack/react-table' import { Button } from 'react-bootstrap' import Table from 'react-bootstrap/Table' @@ -13,54 +14,26 @@ import TableHeader from './TableHeader' import TableRow from './TableRow' function TableBuilder({ data, columns, filterableInputs = [] }) { - const [filters, setFilters] = useState({}) - const [sorting, setSorting] = React.useState([]) - - const filteredData = useMemo(() => { - if (!filterableInputs) return data - - return data.filter((row) => - filterableInputs.every((input) => { - console.log('Row', row) - - let value = '' - - // if (typeof input === 'function') { - // value = input(row) - // } - // else { - - const rawValue = row[input] - // Check if the value is not undefined and is a string or can be converted to a string - value = - typeof rawValue === 'string' || typeof rawValue === 'number' - ? rawValue.toString() - : '' - - // console.log(value.includes(filters[input.toString()])) - // Check if value is not undefined before calling .toString() - return value.includes(filters[input.toString()] || '') - }) - ) - }, [data, filters, filterableInputs]) + const [columnFilters, setColumnFilters] = useState([]) + const [sorting, setSorting] = useState([]) const table = useReactTable({ - data: filteredData, + data, columns: columns, state: { sorting, - // columnFilters, // should be used + columnFilters, }, + onColumnFiltersChange: setColumnFilters, getSortedRowModel: getSortedRowModel(), onSortingChange: setSorting, getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), }) - const handleFilterChange = - (accessor: string) => (e: React.ChangeEvent) => { - setFilters({ ...filters, [accessor]: e.target.value }) - } + const resetColumnFilters = () => { + table.resetColumnFilters() + } return (
@@ -72,7 +45,7 @@ function TableBuilder({ data, columns, filterableInputs = [] }) { @@ -83,9 +56,7 @@ function TableBuilder({ data, columns, filterableInputs = [] }) { ))} diff --git a/web/src/components/TableBuilder/TableHeader.tsx b/web/src/components/TableBuilder/TableHeader.tsx index 39610b14..40a28068 100644 --- a/web/src/components/TableBuilder/TableHeader.tsx +++ b/web/src/components/TableBuilder/TableHeader.tsx @@ -1,11 +1,8 @@ import { flexRender } from '@tanstack/react-table' -const TableHeader = ({ - headerGroup, - filters, - filterableInputs, - handleFilterChange, -}) => { +import Filter from './Filter' + +const TableHeader = ({ headerGroup, filterableInputs }) => { const renderSortingIcon = (sortDirection: 'asc' | 'desc' | null) => { const iconMapping = { asc: 'bi-arrow-up', @@ -35,20 +32,27 @@ const TableHeader = ({ return ( - {headerGroup.headers.map((header) => ( - - {createColumnHeader(header)} - {/* {console.log('Header def', header.column)} */} - - {filterableInputs.includes(header.id.toString()) && ( - - )} - - ))} + {headerGroup.headers.map((header) => { + const hasFilter = + filterableInputs.includes(header.id.toString()) && + header.column.getCanFilter() + + return ( + + {createColumnHeader(header)} + + {hasFilter ? ( +
+ +
+ ) : null} + + ) + })} ) } diff --git a/web/src/components/Upload/Uploads/Uploads.tsx b/web/src/components/Upload/Uploads/Uploads.tsx index 89dc0b6e..8ece4921 100644 --- a/web/src/components/Upload/Uploads/Uploads.tsx +++ b/web/src/components/Upload/Uploads/Uploads.tsx @@ -10,9 +10,8 @@ const UploadsList = ({ uploads }: FindUploads) => { const filterableInputs = [ 'id', 'agency_code', - 'agency.code', - 'expenditureCategory.code', - 'uploadedBy.email', + 'expenditureCategory_code', + 'uploadedBy_email', 'filename', ] diff --git a/web/src/components/Upload/Uploads/columns.tsx b/web/src/components/Upload/Uploads/columns.tsx index e16e9f97..ed08bcde 100644 --- a/web/src/components/Upload/Uploads/columns.tsx +++ b/web/src/components/Upload/Uploads/columns.tsx @@ -18,72 +18,29 @@ function valueAsLink(cell): JSX.Element { ) } -// export const columnDefs = [ -// columnHelper.accessor('id', { -// cell: valueAsLink, -// header: 'ID', -// }), -// columnHelper.accessor('agency.code', { -// cell: (info) => info.getValue(), -// header: 'Agency', -// }), -// columnHelper.accessor('expenditureCategory.code', { -// cell: (info) => info.getValue(), -// header: 'EC Code', -// }), -// columnHelper.accessor('uploadedBy.email', { -// cell: (info) => info.getValue(), -// header: 'Uploaded By', -// }), -// columnHelper.accessor('filename', { -// cell: (info) => info.getValue(), -// header: 'Filename', -// }), -// columnHelper.accessor('validated_at', { -// cell: (info) => info.getValue(), -// header: 'Validated?', -// }), -// ] - export const columnDefs = [ - { - accessorKey: 'id', + columnHelper.accessor('id', { cell: valueAsLink, - header: () => ID, - }, - { - accessorFn: (row) => row.agency.code, - id: 'agency_code', + header: 'ID', + }), + columnHelper.accessor('agency.code', { cell: (info) => info.getValue(), - header: () => Agency, - }, - { - accessorFn: (row) => row.agency.code, - id: 'agency.code', + header: 'Agency', + }), + columnHelper.accessor('expenditureCategory.code', { cell: (info) => info.getValue(), - header: () => Agency.Code, - }, - // { - // accessorFn: (row) => row.agency.code, - // id: "Agency", - // cell: (info) => info.getValue(), - // header: () => Agency, - // }, - - // columnHelper.accessor('expenditureCategory.code', { - // cell: (info) => info.getValue(), - // header: 'EC Code', - // }), - // columnHelper.accessor('uploadedBy.email', { - // cell: (info) => info.getValue(), - // header: 'Uploaded By', - // }), + header: 'EC Code', + }), + columnHelper.accessor('uploadedBy.email', { + cell: (info) => info.getValue(), + header: 'Uploaded By', + }), columnHelper.accessor('filename', { cell: (info) => info.getValue(), header: 'Filename', }), - // columnHelper.accessor('validated_at', { - // cell: (info) => info.getValue(), - // header: 'Validated?', - // }), + columnHelper.accessor('validated_at', { + cell: (info) => info.getValue(), + header: 'Validated?', + }), ] diff --git a/web/src/components/Upload/UploadsCell/UploadsCell.tsx b/web/src/components/Upload/UploadsCell/UploadsCell.tsx index 7795f951..c75fa37c 100644 --- a/web/src/components/Upload/UploadsCell/UploadsCell.tsx +++ b/web/src/components/Upload/UploadsCell/UploadsCell.tsx @@ -18,9 +18,6 @@ export const QUERY = gql` id code } - agency_code: agency { - code - } organizationId reportingPeriodId expenditureCategory { diff --git a/web/src/scss/tables.scss b/web/src/scss/tables.scss index d77286ac..3d2d4b14 100644 --- a/web/src/scss/tables.scss +++ b/web/src/scss/tables.scss @@ -4,4 +4,10 @@ font-weight: bold; padding: 0; border: none; +} + +.testt { + // display: flex; + // justify-content: flex-start; + vertical-align:top } \ No newline at end of file From 57c28981b2bf6e6ec7672503f89e3ce9a483b0ee Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Wed, 13 Dec 2023 20:42:39 -0500 Subject: [PATCH 09/11] feature/CPF-3 extract latest valid and invalid validation for upload, create a date converter util, disable sorting for Validation column --- .../components/TableBuilder/TableBuilder.tsx | 7 +- .../components/TableBuilder/TableHeader.tsx | 14 +- .../components/Upload/Uploads/OldUploads.tsx | 164 ------------------ web/src/components/Upload/Uploads/Uploads.tsx | 42 ++++- web/src/components/Upload/Uploads/columns.tsx | 25 ++- .../Upload/UploadsCell/UploadsCell.tsx | 7 +- web/src/scss/tables.scss | 6 - web/src/utils/index.ts | 38 ++++ 8 files changed, 117 insertions(+), 186 deletions(-) delete mode 100644 web/src/components/Upload/Uploads/OldUploads.tsx create mode 100644 web/src/utils/index.ts diff --git a/web/src/components/TableBuilder/TableBuilder.tsx b/web/src/components/TableBuilder/TableBuilder.tsx index b38ddeff..267f1dd6 100644 --- a/web/src/components/TableBuilder/TableBuilder.tsx +++ b/web/src/components/TableBuilder/TableBuilder.tsx @@ -13,6 +13,11 @@ import Table from 'react-bootstrap/Table' import TableHeader from './TableHeader' import TableRow from './TableRow' +/* + This component uses TanStack Table to add filtering + and sorting functionality. + For documentation, visit: https://tanstack.com/table/v8/docs/guide/introduction +*/ function TableBuilder({ data, columns, filterableInputs = [] }) { const [columnFilters, setColumnFilters] = useState([]) const [sorting, setSorting] = useState([]) @@ -54,8 +59,8 @@ function TableBuilder({ data, columns, filterableInputs = [] }) { )} {table.getHeaderGroups().map((headerGroup) => ( ))} diff --git a/web/src/components/TableBuilder/TableHeader.tsx b/web/src/components/TableBuilder/TableHeader.tsx index 40a28068..6a1c29dd 100644 --- a/web/src/components/TableBuilder/TableHeader.tsx +++ b/web/src/components/TableBuilder/TableHeader.tsx @@ -18,14 +18,16 @@ const TableHeader = ({ headerGroup, filterableInputs }) => { } const createColumnHeader = (header) => { + const columnData = header.column + return ( ) } @@ -45,11 +47,7 @@ const TableHeader = ({ headerGroup, filterableInputs }) => { > {createColumnHeader(header)} - {hasFilter ? ( -
- -
- ) : null} + {hasFilter && } ) })} diff --git a/web/src/components/Upload/Uploads/OldUploads.tsx b/web/src/components/Upload/Uploads/OldUploads.tsx deleted file mode 100644 index 33897e32..00000000 --- a/web/src/components/Upload/Uploads/OldUploads.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import React from 'react' - -import { - useReactTable, - getCoreRowModel, - getPaginationRowModel, - getSortedRowModel, - getFilteredRowModel, - flexRender, -} from '@tanstack/react-table' -import Table from 'react-bootstrap/Table' -import type { FindUploads } from 'types/graphql' - -import DebouncedInput from 'src/components/Upload/Uploads/DebouncedInput' - -import { columnDefs } from './columns' - -const Filter = ({ column, table }: any) => { - const columnFilterValue = column.getFilterValue() - - const sortedUniqueValues = React.useMemo( - () => Array.from(column.getFacetedUniqueValues().keys()).sort(), - [column.getFacetedUniqueValues()] - ) - - return ( - <> - - {sortedUniqueValues.slice(0, 5000).map((value: any) => ( - -

{column.name}

- column.setFilterValue(value)} - placeholder={column.name} - className="" - list={column.id + 'list'} - /> - - ) -} - -const UploadsList = ({ uploads }: FindUploads) => { - const data = React.useMemo(() => uploads, [uploads]) - - const [sorting, setSorting] = React.useState([]) - const [columnFilters, setColumnFilters] = React.useState([]) - - const tableInstance = useReactTable({ - data, - columns: columnDefs, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - state: { - sorting, - columnFilters, - }, - onColumnFiltersChange: setColumnFilters, - onSortingChange: setSorting, - getFilteredRowModel: getFilteredRowModel(), - }) - - const createColumnHeader = (header) => { - const renderIcon = (sortDirection: 'asc' | 'desc' | null) => { - const iconMapping = { - asc: 'bi-arrow-up', - desc: 'bi-arrow-down', - inactive: 'bi-arrow-down-up inactive', - } - - const iconClass = sortDirection - ? iconMapping[sortDirection] - : iconMapping['inactive'] - - const classNames = `bi ${iconClass} me-1` - - return ( - - - - ) - } - - return ( - - {renderIcon(header.column.getIsSorted())} - {!header.isPlaceholder && - flexRender(header.column.columnDef.header, header.getContext())} - - ) - } - - return ( -
- - - {tableInstance.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header: any) => { - // Always create the column header - const columnHeaderElement = createColumnHeader(header) - - // Conditionally create the filter element - const filterElement = header.column.getCanFilter() ? ( -
- -
- ) : null - - // Return a fragment containing both the column header and the filter element (if applicable) - return ( - - {columnHeaderElement} - {filterElement} - - ) - })} - - ))} - - {/* Working but 2 loops */} - {/* {tableInstance.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return createColumnHeader(header) - })} - - {headerGroup.headers.map((header: any) => - header.column.getCanFilter() ? ( -
- -
- ) : null - )} - - - ))} */} - - - {tableInstance.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - ))} - - ))} - -
- {flexRender(cell.column.columnDef.cell, cell.getContext())} -
-
- ) -} - -export default UploadsList diff --git a/web/src/components/Upload/Uploads/Uploads.tsx b/web/src/components/Upload/Uploads/Uploads.tsx index 8ece4921..e79ecb6a 100644 --- a/web/src/components/Upload/Uploads/Uploads.tsx +++ b/web/src/components/Upload/Uploads/Uploads.tsx @@ -7,8 +7,46 @@ import TableBuilder from 'src/components/TableBuilder/TableBuilder' import { columnDefs } from './columns' const UploadsList = ({ uploads }: FindUploads) => { + // Uploads.validations is an array that can contain both valid and invalid validations, + // We store the latest valid and invalid entry + function findLatestValidationAndInvalidationDatesFromUpload(upload) { + let latestInvalidationDate = null + let latestValidationDate = null + + upload.validations.forEach((validation) => { + if (validation.invalidatedAt) { + // Update latestInvalidationDate if it's null or if this date is more recent + if ( + !latestInvalidationDate || + Date.parse(validation.invalidatedAt) > + Date.parse(latestInvalidationDate) + ) { + latestInvalidationDate = validation.invalidatedAt + } + } + + if (validation.validatedAt) { + // Update latestValidationDate if it's null or if this date is more recent + if ( + !latestValidationDate || + Date.parse(validation.validationAt) > Date.parse(latestValidationDate) + ) { + latestValidationDate = validation.validatedAt + } + } + }) + + return { latestInvalidationDate, latestValidationDate } + } + + const uploadsWithValidationDates = uploads.map((upload) => { + return { + ...upload, + ...findLatestValidationAndInvalidationDatesFromUpload(upload), + } + }) + const filterableInputs = [ - 'id', 'agency_code', 'expenditureCategory_code', 'uploadedBy_email', @@ -17,7 +55,7 @@ const UploadsList = ({ uploads }: FindUploads) => { return ( diff --git a/web/src/components/Upload/Uploads/columns.tsx b/web/src/components/Upload/Uploads/columns.tsx index ed08bcde..f502787e 100644 --- a/web/src/components/Upload/Uploads/columns.tsx +++ b/web/src/components/Upload/Uploads/columns.tsx @@ -2,6 +2,8 @@ import { createColumnHelper } from '@tanstack/react-table' import { Link, routes } from '@redwoodjs/router' +import { formatDateString } from '../../../utils/index' + const columnHelper = createColumnHelper() function valueAsLink(cell): JSX.Element { @@ -18,6 +20,22 @@ function valueAsLink(cell): JSX.Element { ) } +function validationDisplay(row) { + if (row.latestInvalidationDate) { + const formattedDate = formatDateString(row.latestInvalidationDate) + return `Invalidated at ${formattedDate}` + } + + // Else, display 'Validated at' if latestValidationDate is available + if (row.latestValidationDate) { + const formattedDate = formatDateString(row.latestValidationDate) + return `Validated at ${formattedDate}` + } + + // If neither date is available, display nothing or a default message + return 'Not set' +} + export const columnDefs = [ columnHelper.accessor('id', { cell: valueAsLink, @@ -39,8 +57,11 @@ export const columnDefs = [ cell: (info) => info.getValue(), header: 'Filename', }), - columnHelper.accessor('validated_at', { + { + accessorFn: validationDisplay, cell: (info) => info.getValue(), + id: 'validatedAt', header: 'Validated?', - }), + enableSorting: false, + }, ] diff --git a/web/src/components/Upload/UploadsCell/UploadsCell.tsx b/web/src/components/Upload/UploadsCell/UploadsCell.tsx index c75fa37c..35453574 100644 --- a/web/src/components/Upload/UploadsCell/UploadsCell.tsx +++ b/web/src/components/Upload/UploadsCell/UploadsCell.tsx @@ -18,13 +18,14 @@ export const QUERY = gql` id code } - organizationId - reportingPeriodId expenditureCategory { id - name code } + validations { + invalidatedAt + validatedAt + } createdAt updatedAt } diff --git a/web/src/scss/tables.scss b/web/src/scss/tables.scss index 3d2d4b14..d77286ac 100644 --- a/web/src/scss/tables.scss +++ b/web/src/scss/tables.scss @@ -4,10 +4,4 @@ font-weight: bold; padding: 0; border: none; -} - -.testt { - // display: flex; - // justify-content: flex-start; - vertical-align:top } \ No newline at end of file diff --git a/web/src/utils/index.ts b/web/src/utils/index.ts new file mode 100644 index 00000000..d51cff0b --- /dev/null +++ b/web/src/utils/index.ts @@ -0,0 +1,38 @@ +// Convert strings like "2023-12-13T18:32:32.080Z" to "Dec 13th 2023, 1:32:32 PM" +export function formatDateString(dateString) { + const monthNames = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ] + + function getOrdinalNum(n) { + return ( + n + + (n > 0 + ? ['th', 'st', 'nd', 'rd'][(n > 3 && n < 21) || n % 10 > 3 ? 0 : n % 10] + : '') + ) + } + + const date = new Date(dateString) + const year = date.getFullYear() + const month = monthNames[date.getMonth()] + const day = getOrdinalNum(date.getDate()) + const hours = date.getHours() + const minutes = date.getMinutes().toString().padStart(2, '0') + const seconds = date.getSeconds().toString().padStart(2, '0') + const ampm = hours >= 12 ? 'PM' : 'AM' + const formattedHours = hours % 12 || 12 + + return `${month} ${day} ${year}, ${formattedHours}:${minutes}:${seconds} ${ampm}` +} From dabef203fbc5a6a91e4d8487c1d5ccaf4653d513 Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Thu, 14 Dec 2023 09:48:41 -0500 Subject: [PATCH 10/11] feature/3 add useCallback to prevent useEffect() hook from triggering too many times, delete duplicate DebouncedInput, fix eslint errors in api/src --- .../services/agencies/agencies.scenarios.ts | 1 + api/src/services/agencies/agencies.ts | 25 +- .../expenditureCategories.scenarios.ts | 1 + .../inputTemplates.scenarios.ts | 1 + .../organizations/organizations.scenarios.ts | 1 + .../outputTemplates.scenarios.ts | 1 + .../services/projects/projects.scenarios.ts | 1 + .../reportingPeriods.scenarios.ts | 1 + api/src/services/roles/roles.scenarios.ts | 1 + api/src/services/users/users.scenarios.ts | 1 + .../TableBuilder/DebouncedInput.tsx | 2 +- web/src/components/TableBuilder/Filter.tsx | 11 +- web/src/components/Upload/Upload/Upload.tsx | 10 +- .../Upload/UploadForm/UploadForm.tsx | 4 +- .../Upload/Uploads/DebouncedInput.tsx | 32 - web/types/graphql.d.ts | 1347 ++++++++--------- 16 files changed, 666 insertions(+), 774 deletions(-) delete mode 100644 web/src/components/Upload/Uploads/DebouncedInput.tsx diff --git a/api/src/services/agencies/agencies.scenarios.ts b/api/src/services/agencies/agencies.scenarios.ts index 70f989a2..153fe58c 100644 --- a/api/src/services/agencies/agencies.scenarios.ts +++ b/api/src/services/agencies/agencies.scenarios.ts @@ -1,4 +1,5 @@ import type { Prisma, agency } from '@prisma/client' + import type { ScenarioData } from '@redwoodjs/testing/api' export const standard = defineScenario({ diff --git a/api/src/services/agencies/agencies.ts b/api/src/services/agencies/agencies.ts index 55002964..d2c69ddb 100644 --- a/api/src/services/agencies/agencies.ts +++ b/api/src/services/agencies/agencies.ts @@ -34,17 +34,16 @@ export const deleteAgency: MutationResolvers['deleteAgency'] = ({ id }) => { }) } -export const agenciesByOrganization: QueryResolvers['agenciesByOrganization'] = async ({ - organizationId, -}) => { - try { - const agencies = await db.agency.findMany({ - where: { organizationId }, - }) - return agencies || [] // Return an empty array if null is received - } catch (error) { - console.error(error) - // Handle the error appropriately; maybe log it and return an empty array - return [] +export const agenciesByOrganization: QueryResolvers['agenciesByOrganization'] = + async ({ organizationId }) => { + try { + const agencies = await db.agency.findMany({ + where: { organizationId }, + }) + return agencies || [] // Return an empty array if null is received + } catch (error) { + console.error(error) + // Handle the error appropriately; maybe log it and return an empty array + return [] + } } -} diff --git a/api/src/services/expenditureCategories/expenditureCategories.scenarios.ts b/api/src/services/expenditureCategories/expenditureCategories.scenarios.ts index 17296253..5b62daa4 100644 --- a/api/src/services/expenditureCategories/expenditureCategories.scenarios.ts +++ b/api/src/services/expenditureCategories/expenditureCategories.scenarios.ts @@ -1,4 +1,5 @@ import type { Prisma, ExpenditureCategory } from '@prisma/client' + import type { ScenarioData } from '@redwoodjs/testing/api' export const standard = defineScenario({ diff --git a/api/src/services/inputTemplates/inputTemplates.scenarios.ts b/api/src/services/inputTemplates/inputTemplates.scenarios.ts index 088bbfd9..29b562d5 100644 --- a/api/src/services/inputTemplates/inputTemplates.scenarios.ts +++ b/api/src/services/inputTemplates/inputTemplates.scenarios.ts @@ -1,4 +1,5 @@ import type { Prisma, InputTemplate } from '@prisma/client' + import type { ScenarioData } from '@redwoodjs/testing/api' export const standard = defineScenario({ diff --git a/api/src/services/organizations/organizations.scenarios.ts b/api/src/services/organizations/organizations.scenarios.ts index 14eecf1c..68678d6e 100644 --- a/api/src/services/organizations/organizations.scenarios.ts +++ b/api/src/services/organizations/organizations.scenarios.ts @@ -1,4 +1,5 @@ import type { Prisma, Organization } from '@prisma/client' + import type { ScenarioData } from '@redwoodjs/testing/api' export const standard = defineScenario({ diff --git a/api/src/services/outputTemplates/outputTemplates.scenarios.ts b/api/src/services/outputTemplates/outputTemplates.scenarios.ts index ac941191..6a8893a2 100644 --- a/api/src/services/outputTemplates/outputTemplates.scenarios.ts +++ b/api/src/services/outputTemplates/outputTemplates.scenarios.ts @@ -1,4 +1,5 @@ import type { Prisma, OutputTemplate } from '@prisma/client' + import type { ScenarioData } from '@redwoodjs/testing/api' export const standard = defineScenario({ diff --git a/api/src/services/projects/projects.scenarios.ts b/api/src/services/projects/projects.scenarios.ts index 7be54044..8becffd1 100644 --- a/api/src/services/projects/projects.scenarios.ts +++ b/api/src/services/projects/projects.scenarios.ts @@ -1,4 +1,5 @@ import type { Prisma, Project } from '@prisma/client' + import type { ScenarioData } from '@redwoodjs/testing/api' export const standard = defineScenario({ diff --git a/api/src/services/reportingPeriods/reportingPeriods.scenarios.ts b/api/src/services/reportingPeriods/reportingPeriods.scenarios.ts index 3a8df1aa..da5880c7 100644 --- a/api/src/services/reportingPeriods/reportingPeriods.scenarios.ts +++ b/api/src/services/reportingPeriods/reportingPeriods.scenarios.ts @@ -1,4 +1,5 @@ import type { Prisma, ReportingPeriod } from '@prisma/client' + import type { ScenarioData } from '@redwoodjs/testing/api' export const standard = defineScenario({ diff --git a/api/src/services/roles/roles.scenarios.ts b/api/src/services/roles/roles.scenarios.ts index 938e1d94..366836fe 100644 --- a/api/src/services/roles/roles.scenarios.ts +++ b/api/src/services/roles/roles.scenarios.ts @@ -1,4 +1,5 @@ import type { Prisma, Role } from '@prisma/client' + import type { ScenarioData } from '@redwoodjs/testing/api' export const standard = defineScenario({ diff --git a/api/src/services/users/users.scenarios.ts b/api/src/services/users/users.scenarios.ts index dc69a77a..8cf2a34e 100644 --- a/api/src/services/users/users.scenarios.ts +++ b/api/src/services/users/users.scenarios.ts @@ -1,4 +1,5 @@ import type { Prisma, User } from '@prisma/client' + import type { ScenarioData } from '@redwoodjs/testing/api' export const standard = defineScenario({ diff --git a/web/src/components/TableBuilder/DebouncedInput.tsx b/web/src/components/TableBuilder/DebouncedInput.tsx index 9f34c761..500c83f9 100644 --- a/web/src/components/TableBuilder/DebouncedInput.tsx +++ b/web/src/components/TableBuilder/DebouncedInput.tsx @@ -22,7 +22,7 @@ function DebouncedInput({ }, debounce) return () => clearTimeout(timeout) - }, [value]) + }, [value, debounce, onChange]) return ( { + column.setFilterValue(value) + }, + [column] + ) + return ( column.setFilterValue(value)} + onChange={handleInputChange} placeholder="Search..." /> ) diff --git a/web/src/components/Upload/Upload/Upload.tsx b/web/src/components/Upload/Upload/Upload.tsx index 4fb8b9de..5099af39 100644 --- a/web/src/components/Upload/Upload/Upload.tsx +++ b/web/src/components/Upload/Upload/Upload.tsx @@ -1,14 +1,14 @@ +import type { + DeleteUploadMutationVariables, + FindUploadById, +} from 'types/graphql' + import { Link, routes, navigate } from '@redwoodjs/router' import { useMutation } from '@redwoodjs/web' import { toast } from '@redwoodjs/web/toast' import { timeTag } from 'src/lib/formatters' -import type { - DeleteUploadMutationVariables, - FindUploadById, -} from 'types/graphql' - const DELETE_UPLOAD_MUTATION = gql` mutation DeleteUploadMutation($id: Int!) { deleteUpload(id: $id) { diff --git a/web/src/components/Upload/UploadForm/UploadForm.tsx b/web/src/components/Upload/UploadForm/UploadForm.tsx index c54b4d45..3b796190 100644 --- a/web/src/components/Upload/UploadForm/UploadForm.tsx +++ b/web/src/components/Upload/UploadForm/UploadForm.tsx @@ -1,3 +1,5 @@ +import type { EditUploadById, UpdateUploadInput } from 'types/graphql' + import { Form, FormError, @@ -7,8 +9,6 @@ import { NumberField, Submit, } from '@redwoodjs/forms' - -import type { EditUploadById, UpdateUploadInput } from 'types/graphql' import type { RWGqlError } from '@redwoodjs/forms' type FormUpload = NonNullable diff --git a/web/src/components/Upload/Uploads/DebouncedInput.tsx b/web/src/components/Upload/Uploads/DebouncedInput.tsx deleted file mode 100644 index 398a65b0..00000000 --- a/web/src/components/Upload/Uploads/DebouncedInput.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { useState, useEffect } from 'react' - -function DebouncedInput({ - value: initialValue, - onChange, - debounce = 500, - ...props -}) { - const [value, setValue] = useState(initialValue) - - useEffect(() => { - setValue(initialValue) - }, [initialValue]) - - useEffect(() => { - const timeout = setTimeout(() => { - onChange(value) - }, debounce) - - return () => clearTimeout(timeout) - }, [value]) - - return ( - setValue(e.target.value)} - /> - ) -} - -export default DebouncedInput diff --git a/web/types/graphql.d.ts b/web/types/graphql.d.ts index 50142f6f..d0d6c99f 100644 --- a/web/types/graphql.d.ts +++ b/web/types/graphql.d.ts @@ -1,483 +1,526 @@ -import { Prisma } from '@prisma/client' -export type Maybe = T | null -export type InputMaybe = Maybe -export type Exact = { - [K in keyof T]: T[K] -} -export type MakeOptional = Omit & { - [SubKey in K]?: Maybe -} -export type MakeMaybe = Omit & { - [SubKey in K]: Maybe -} +import { Prisma } from "@prisma/client" +export type Maybe = T | null; +export type InputMaybe = Maybe; +export type Exact = { [K in keyof T]: T[K] }; +export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; +export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { - ID: string - String: string - Boolean: boolean - Int: number - Float: number - BigInt: number - Date: string - DateTime: string - JSON: Prisma.JsonValue - JSONObject: Prisma.JsonObject - Time: string -} + ID: string; + String: string; + Boolean: boolean; + Int: number; + Float: number; + BigInt: number; + Date: string; + DateTime: string; + JSON: Prisma.JsonValue; + JSONObject: Prisma.JsonObject; + Time: string; +}; export type Agency = { - __typename?: 'Agency' - abbreviation?: Maybe - code: Scalars['String'] - id: Scalars['Int'] - name: Scalars['String'] - organizationId: Scalars['Int'] -} + __typename?: 'Agency'; + abbreviation?: Maybe; + code: Scalars['String']; + id: Scalars['Int']; + name: Scalars['String']; + organizationId: Scalars['Int']; +}; export type CreateAgencyInput = { - abbreviation?: InputMaybe - code: Scalars['String'] - name: Scalars['String'] -} + abbreviation?: InputMaybe; + code: Scalars['String']; + name: Scalars['String']; +}; export type CreateExpenditureCategoryInput = { - code: Scalars['String'] - name: Scalars['String'] -} + code: Scalars['String']; + name: Scalars['String']; +}; export type CreateInputTemplateInput = { - effectiveDate: Scalars['DateTime'] - name: Scalars['String'] - rulesGeneratedAt: Scalars['DateTime'] - version: Scalars['String'] -} + effectiveDate: Scalars['DateTime']; + name: Scalars['String']; + rulesGeneratedAt: Scalars['DateTime']; + version: Scalars['String']; +}; export type CreateOrganizationInput = { - name: Scalars['String'] -} + name: Scalars['String']; +}; export type CreateOutputTemplateInput = { - effectiveDate: Scalars['DateTime'] - name: Scalars['String'] - rulesGeneratedAt: Scalars['DateTime'] - version: Scalars['String'] -} + effectiveDate: Scalars['DateTime']; + name: Scalars['String']; + rulesGeneratedAt: Scalars['DateTime']; + version: Scalars['String']; +}; export type CreateProjectInput = { - agencyId: Scalars['Int'] - code: Scalars['String'] - description: Scalars['String'] - name: Scalars['String'] - organizationId: Scalars['Int'] - originationPeriodId: Scalars['Int'] - status: Scalars['String'] -} + agencyId: Scalars['Int']; + code: Scalars['String']; + description: Scalars['String']; + name: Scalars['String']; + organizationId: Scalars['Int']; + originationPeriodId: Scalars['Int']; + status: Scalars['String']; +}; export type CreateReportingPeriodInput = { - certifiedAt?: InputMaybe - certifiedById?: InputMaybe - endDate: Scalars['DateTime'] - inputTemplateId: Scalars['Int'] - isCurrentPeriod: Scalars['Boolean'] - name: Scalars['String'] - outputTemplateId: Scalars['Int'] - startDate: Scalars['DateTime'] -} + certifiedAt?: InputMaybe; + certifiedById?: InputMaybe; + endDate: Scalars['DateTime']; + inputTemplateId: Scalars['Int']; + isCurrentPeriod: Scalars['Boolean']; + name: Scalars['String']; + outputTemplateId: Scalars['Int']; + startDate: Scalars['DateTime']; +}; export type CreateRoleInput = { - name: Scalars['String'] -} + name: Scalars['String']; +}; export type CreateSubrecipientInput = { - certifiedAt?: InputMaybe - certifiedById?: InputMaybe - endDate: Scalars['DateTime'] - name: Scalars['String'] - organizationId: Scalars['Int'] - originationUploadId: Scalars['Int'] - startDate: Scalars['DateTime'] -} + certifiedAt?: InputMaybe; + certifiedById?: InputMaybe; + endDate: Scalars['DateTime']; + name: Scalars['String']; + organizationId: Scalars['Int']; + originationUploadId: Scalars['Int']; + startDate: Scalars['DateTime']; +}; export type CreateUploadInput = { - agencyId: Scalars['Int'] - expenditureCategoryId: Scalars['Int'] - filename: Scalars['String'] - organizationId: Scalars['Int'] - reportingPeriodId: Scalars['Int'] - uploadedById: Scalars['Int'] -} + agencyId: Scalars['Int']; + expenditureCategoryId: Scalars['Int']; + filename: Scalars['String']; + organizationId: Scalars['Int']; + reportingPeriodId: Scalars['Int']; + uploadedById: Scalars['Int']; +}; export type CreateUploadValidationInput = { - agencyId: Scalars['Int'] - inputTemplateId: Scalars['Int'] - invalidatedAt?: InputMaybe - invalidatedById?: InputMaybe - invalidationResults?: InputMaybe - organizationId: Scalars['Int'] - uploadId: Scalars['Int'] - validatedAt?: InputMaybe - validatedById?: InputMaybe - validationResults?: InputMaybe -} + agencyId: Scalars['Int']; + inputTemplateId: Scalars['Int']; + invalidatedAt?: InputMaybe; + invalidatedById?: InputMaybe; + invalidationResults?: InputMaybe; + organizationId: Scalars['Int']; + uploadId: Scalars['Int']; + validatedAt?: InputMaybe; + validatedById?: InputMaybe; + validationResults?: InputMaybe; +}; export type CreateUserInput = { - agencyId?: InputMaybe - email: Scalars['String'] - name?: InputMaybe - organizationId: Scalars['Int'] - roleId?: InputMaybe -} + agencyId?: InputMaybe; + email: Scalars['String']; + name?: InputMaybe; + organizationId: Scalars['Int']; + roleId?: InputMaybe; +}; export type ExpenditureCategory = { - __typename?: 'ExpenditureCategory' - Uploads: Array> - code: Scalars['String'] - createdAt: Scalars['DateTime'] - id: Scalars['Int'] - name: Scalars['String'] - updatedAt: Scalars['DateTime'] -} + __typename?: 'ExpenditureCategory'; + Uploads: Array>; + code: Scalars['String']; + createdAt: Scalars['DateTime']; + id: Scalars['Int']; + name: Scalars['String']; + updatedAt: Scalars['DateTime']; +}; export type InputTemplate = { - __typename?: 'InputTemplate' - createdAt: Scalars['DateTime'] - effectiveDate: Scalars['DateTime'] - id: Scalars['Int'] - name: Scalars['String'] - reportingPeriods: Array> - rulesGeneratedAt: Scalars['DateTime'] - updatedAt: Scalars['DateTime'] - version: Scalars['String'] -} + __typename?: 'InputTemplate'; + createdAt: Scalars['DateTime']; + effectiveDate: Scalars['DateTime']; + id: Scalars['Int']; + name: Scalars['String']; + reportingPeriods: Array>; + rulesGeneratedAt: Scalars['DateTime']; + updatedAt: Scalars['DateTime']; + version: Scalars['String']; +}; export type Mutation = { - __typename?: 'Mutation' - createAgency: Agency - createExpenditureCategory: ExpenditureCategory - createInputTemplate: InputTemplate - createOrganization: Organization - createOutputTemplate: OutputTemplate - createProject: Project - createReportingPeriod: ReportingPeriod - createRole: Role - createSubrecipient: Subrecipient - createUpload: Upload - createUploadValidation: UploadValidation - createUser: User - deleteAgency: Agency - deleteExpenditureCategory: ExpenditureCategory - deleteInputTemplate: InputTemplate - deleteOrganization: Organization - deleteOutputTemplate: OutputTemplate - deleteProject: Project - deleteReportingPeriod: ReportingPeriod - deleteRole: Role - deleteSubrecipient: Subrecipient - deleteUpload: Upload - deleteUploadValidation: UploadValidation - deleteUser: User - updateAgency: Agency - updateExpenditureCategory: ExpenditureCategory - updateInputTemplate: InputTemplate - updateOrganization: Organization - updateOutputTemplate: OutputTemplate - updateProject: Project - updateReportingPeriod: ReportingPeriod - updateRole: Role - updateSubrecipient: Subrecipient - updateUpload: Upload - updateUploadValidation: UploadValidation - updateUser: User -} + __typename?: 'Mutation'; + createAgency: Agency; + createExpenditureCategory: ExpenditureCategory; + createInputTemplate: InputTemplate; + createOrganization: Organization; + createOutputTemplate: OutputTemplate; + createProject: Project; + createReportingPeriod: ReportingPeriod; + createRole: Role; + createSubrecipient: Subrecipient; + createUpload: Upload; + createUploadValidation: UploadValidation; + createUser: User; + deleteAgency: Agency; + deleteExpenditureCategory: ExpenditureCategory; + deleteInputTemplate: InputTemplate; + deleteOrganization: Organization; + deleteOutputTemplate: OutputTemplate; + deleteProject: Project; + deleteReportingPeriod: ReportingPeriod; + deleteRole: Role; + deleteSubrecipient: Subrecipient; + deleteUpload: Upload; + deleteUploadValidation: UploadValidation; + deleteUser: User; + updateAgency: Agency; + updateExpenditureCategory: ExpenditureCategory; + updateInputTemplate: InputTemplate; + updateOrganization: Organization; + updateOutputTemplate: OutputTemplate; + updateProject: Project; + updateReportingPeriod: ReportingPeriod; + updateRole: Role; + updateSubrecipient: Subrecipient; + updateUpload: Upload; + updateUploadValidation: UploadValidation; + updateUser: User; +}; + export type MutationcreateAgencyArgs = { - input: CreateAgencyInput -} + input: CreateAgencyInput; +}; + export type MutationcreateExpenditureCategoryArgs = { - input: CreateExpenditureCategoryInput -} + input: CreateExpenditureCategoryInput; +}; + export type MutationcreateInputTemplateArgs = { - input: CreateInputTemplateInput -} + input: CreateInputTemplateInput; +}; + export type MutationcreateOrganizationArgs = { - input: CreateOrganizationInput -} + input: CreateOrganizationInput; +}; + export type MutationcreateOutputTemplateArgs = { - input: CreateOutputTemplateInput -} + input: CreateOutputTemplateInput; +}; + export type MutationcreateProjectArgs = { - input: CreateProjectInput -} + input: CreateProjectInput; +}; + export type MutationcreateReportingPeriodArgs = { - input: CreateReportingPeriodInput -} + input: CreateReportingPeriodInput; +}; + export type MutationcreateRoleArgs = { - input: CreateRoleInput -} + input: CreateRoleInput; +}; + export type MutationcreateSubrecipientArgs = { - input: CreateSubrecipientInput -} + input: CreateSubrecipientInput; +}; + export type MutationcreateUploadArgs = { - input: CreateUploadInput -} + input: CreateUploadInput; +}; + export type MutationcreateUploadValidationArgs = { - input: CreateUploadValidationInput -} + input: CreateUploadValidationInput; +}; + export type MutationcreateUserArgs = { - input: CreateUserInput -} + input: CreateUserInput; +}; + export type MutationdeleteAgencyArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteExpenditureCategoryArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteInputTemplateArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteOrganizationArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteOutputTemplateArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteProjectArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteReportingPeriodArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteRoleArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteSubrecipientArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteUploadArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteUploadValidationArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationdeleteUserArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + export type MutationupdateAgencyArgs = { - id: Scalars['Int'] - input: UpdateAgencyInput -} + id: Scalars['Int']; + input: UpdateAgencyInput; +}; + export type MutationupdateExpenditureCategoryArgs = { - id: Scalars['Int'] - input: UpdateExpenditureCategoryInput -} + id: Scalars['Int']; + input: UpdateExpenditureCategoryInput; +}; + export type MutationupdateInputTemplateArgs = { - id: Scalars['Int'] - input: UpdateInputTemplateInput -} + id: Scalars['Int']; + input: UpdateInputTemplateInput; +}; + export type MutationupdateOrganizationArgs = { - id: Scalars['Int'] - input: UpdateOrganizationInput -} + id: Scalars['Int']; + input: UpdateOrganizationInput; +}; + export type MutationupdateOutputTemplateArgs = { - id: Scalars['Int'] - input: UpdateOutputTemplateInput -} + id: Scalars['Int']; + input: UpdateOutputTemplateInput; +}; + export type MutationupdateProjectArgs = { - id: Scalars['Int'] - input: UpdateProjectInput -} + id: Scalars['Int']; + input: UpdateProjectInput; +}; + export type MutationupdateReportingPeriodArgs = { - id: Scalars['Int'] - input: UpdateReportingPeriodInput -} + id: Scalars['Int']; + input: UpdateReportingPeriodInput; +}; + export type MutationupdateRoleArgs = { - id: Scalars['Int'] - input: UpdateRoleInput -} + id: Scalars['Int']; + input: UpdateRoleInput; +}; + export type MutationupdateSubrecipientArgs = { - id: Scalars['Int'] - input: UpdateSubrecipientInput -} + id: Scalars['Int']; + input: UpdateSubrecipientInput; +}; + export type MutationupdateUploadArgs = { - id: Scalars['Int'] - input: UpdateUploadInput -} + id: Scalars['Int']; + input: UpdateUploadInput; +}; + export type MutationupdateUploadValidationArgs = { - id: Scalars['Int'] - input: UpdateUploadValidationInput -} + id: Scalars['Int']; + input: UpdateUploadValidationInput; +}; + export type MutationupdateUserArgs = { - id: Scalars['Int'] - input: UpdateUserInput -} + id: Scalars['Int']; + input: UpdateUserInput; +}; export type Organization = { - __typename?: 'Organization' - agencies: Array> - id: Scalars['Int'] - name: Scalars['String'] -} + __typename?: 'Organization'; + agencies: Array>; + id: Scalars['Int']; + name: Scalars['String']; +}; export type OutputTemplate = { - __typename?: 'OutputTemplate' - createdAt: Scalars['DateTime'] - effectiveDate: Scalars['DateTime'] - id: Scalars['Int'] - name: Scalars['String'] - reportingPeriods: Array> - rulesGeneratedAt: Scalars['DateTime'] - updatedAt: Scalars['DateTime'] - version: Scalars['String'] -} + __typename?: 'OutputTemplate'; + createdAt: Scalars['DateTime']; + effectiveDate: Scalars['DateTime']; + id: Scalars['Int']; + name: Scalars['String']; + reportingPeriods: Array>; + rulesGeneratedAt: Scalars['DateTime']; + updatedAt: Scalars['DateTime']; + version: Scalars['String']; +}; export type Project = { - __typename?: 'Project' - agency: Agency - agencyId: Scalars['Int'] - code: Scalars['String'] - createdAt: Scalars['DateTime'] - description: Scalars['String'] - id: Scalars['Int'] - name: Scalars['String'] - organization: Organization - organizationId: Scalars['Int'] - originationPeriod: ReportingPeriod - originationPeriodId: Scalars['Int'] - status: Scalars['String'] - updatedAt: Scalars['DateTime'] -} + __typename?: 'Project'; + agency: Agency; + agencyId: Scalars['Int']; + code: Scalars['String']; + createdAt: Scalars['DateTime']; + description: Scalars['String']; + id: Scalars['Int']; + name: Scalars['String']; + organization: Organization; + organizationId: Scalars['Int']; + originationPeriod: ReportingPeriod; + originationPeriodId: Scalars['Int']; + status: Scalars['String']; + updatedAt: Scalars['DateTime']; +}; /** About the Redwood queries. */ export type Query = { - __typename?: 'Query' - agencies: Array - agenciesByOrganization: Array - agency?: Maybe - expenditureCategories: Array - expenditureCategory?: Maybe - inputTemplate?: Maybe - inputTemplates: Array - organization?: Maybe - organizations: Array - outputTemplate?: Maybe - outputTemplates: Array - project?: Maybe - projects: Array + __typename?: 'Query'; + agencies: Array; + agenciesByOrganization: Array; + agency?: Maybe; + expenditureCategories: Array; + expenditureCategory?: Maybe; + inputTemplate?: Maybe; + inputTemplates: Array; + organization?: Maybe; + organizations: Array; + outputTemplate?: Maybe; + outputTemplates: Array; + project?: Maybe; + projects: Array; /** Fetches the Redwood root schema. */ - redwood?: Maybe - reportingPeriod?: Maybe - reportingPeriods: Array - role?: Maybe - roles: Array - subrecipient?: Maybe - subrecipients: Array - upload?: Maybe - uploadValidation?: Maybe - uploadValidations: Array - uploads: Array - user?: Maybe - users: Array -} + redwood?: Maybe; + reportingPeriod?: Maybe; + reportingPeriods: Array; + role?: Maybe; + roles: Array; + subrecipient?: Maybe; + subrecipients: Array; + upload?: Maybe; + uploadValidation?: Maybe; + uploadValidations: Array; + uploads: Array; + user?: Maybe; + users: Array; +}; + /** About the Redwood queries. */ export type QueryagenciesByOrganizationArgs = { - organizationId: Scalars['Int'] -} + organizationId: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryagencyArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryexpenditureCategoryArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryinputTemplateArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryorganizationArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryoutputTemplateArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryprojectArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryreportingPeriodArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryroleArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QuerysubrecipientArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryuploadArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryuploadValidationArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; + /** About the Redwood queries. */ export type QueryuserArgs = { - id: Scalars['Int'] -} + id: Scalars['Int']; +}; /** * The RedwoodJS Root Schema @@ -485,480 +528,344 @@ export type QueryuserArgs = { * Defines details about RedwoodJS such as the current user and version information. */ export type Redwood = { - __typename?: 'Redwood' + __typename?: 'Redwood'; /** The current user. */ - currentUser?: Maybe + currentUser?: Maybe; /** The version of Prisma. */ - prismaVersion?: Maybe + prismaVersion?: Maybe; /** The version of Redwood. */ - version?: Maybe -} + version?: Maybe; +}; export type ReportingPeriod = { - __typename?: 'ReportingPeriod' - certifiedAt?: Maybe - certifiedBy?: Maybe - certifiedById?: Maybe - createdAt: Scalars['DateTime'] - endDate: Scalars['DateTime'] - id: Scalars['Int'] - inputTemplate: InputTemplate - inputTemplateId: Scalars['Int'] - isCurrentPeriod: Scalars['Boolean'] - name: Scalars['String'] - outputTemplate: OutputTemplate - outputTemplateId: Scalars['Int'] - startDate: Scalars['DateTime'] - updatedAt: Scalars['DateTime'] -} + __typename?: 'ReportingPeriod'; + certifiedAt?: Maybe; + certifiedBy?: Maybe; + certifiedById?: Maybe; + createdAt: Scalars['DateTime']; + endDate: Scalars['DateTime']; + id: Scalars['Int']; + inputTemplate: InputTemplate; + inputTemplateId: Scalars['Int']; + isCurrentPeriod: Scalars['Boolean']; + name: Scalars['String']; + outputTemplate: OutputTemplate; + outputTemplateId: Scalars['Int']; + startDate: Scalars['DateTime']; + updatedAt: Scalars['DateTime']; +}; export type Role = { - __typename?: 'Role' - createdAt: Scalars['DateTime'] - id: Scalars['Int'] - name: Scalars['String'] - updatedAt: Scalars['DateTime'] - users: Array> -} + __typename?: 'Role'; + createdAt: Scalars['DateTime']; + id: Scalars['Int']; + name: Scalars['String']; + updatedAt: Scalars['DateTime']; + users: Array>; +}; export type Subrecipient = { - __typename?: 'Subrecipient' - certifiedAt?: Maybe - certifiedBy?: Maybe - certifiedById?: Maybe - createdAt: Scalars['DateTime'] - endDate: Scalars['DateTime'] - id: Scalars['Int'] - name: Scalars['String'] - organization: Organization - organizationId: Scalars['Int'] - originationUpload: Upload - originationUploadId: Scalars['Int'] - startDate: Scalars['DateTime'] - updatedAt: Scalars['DateTime'] -} + __typename?: 'Subrecipient'; + certifiedAt?: Maybe; + certifiedBy?: Maybe; + certifiedById?: Maybe; + createdAt: Scalars['DateTime']; + endDate: Scalars['DateTime']; + id: Scalars['Int']; + name: Scalars['String']; + organization: Organization; + organizationId: Scalars['Int']; + originationUpload: Upload; + originationUploadId: Scalars['Int']; + startDate: Scalars['DateTime']; + updatedAt: Scalars['DateTime']; +}; export type UpdateAgencyInput = { - abbreviation?: InputMaybe - code?: InputMaybe - name?: InputMaybe -} + abbreviation?: InputMaybe; + code?: InputMaybe; + name?: InputMaybe; +}; export type UpdateExpenditureCategoryInput = { - code?: InputMaybe - name?: InputMaybe -} + code?: InputMaybe; + name?: InputMaybe; +}; export type UpdateInputTemplateInput = { - effectiveDate?: InputMaybe - name?: InputMaybe - rulesGeneratedAt?: InputMaybe - version?: InputMaybe -} + effectiveDate?: InputMaybe; + name?: InputMaybe; + rulesGeneratedAt?: InputMaybe; + version?: InputMaybe; +}; export type UpdateOrganizationInput = { - name?: InputMaybe -} + name?: InputMaybe; +}; export type UpdateOutputTemplateInput = { - effectiveDate?: InputMaybe - name?: InputMaybe - rulesGeneratedAt?: InputMaybe - version?: InputMaybe -} + effectiveDate?: InputMaybe; + name?: InputMaybe; + rulesGeneratedAt?: InputMaybe; + version?: InputMaybe; +}; export type UpdateProjectInput = { - agencyId?: InputMaybe - code?: InputMaybe - description?: InputMaybe - name?: InputMaybe - organizationId?: InputMaybe - originationPeriodId?: InputMaybe - status?: InputMaybe -} + agencyId?: InputMaybe; + code?: InputMaybe; + description?: InputMaybe; + name?: InputMaybe; + organizationId?: InputMaybe; + originationPeriodId?: InputMaybe; + status?: InputMaybe; +}; export type UpdateReportingPeriodInput = { - certifiedAt?: InputMaybe - certifiedById?: InputMaybe - endDate?: InputMaybe - inputTemplateId?: InputMaybe - isCurrentPeriod?: InputMaybe - name?: InputMaybe - outputTemplateId?: InputMaybe - startDate?: InputMaybe -} + certifiedAt?: InputMaybe; + certifiedById?: InputMaybe; + endDate?: InputMaybe; + inputTemplateId?: InputMaybe; + isCurrentPeriod?: InputMaybe; + name?: InputMaybe; + outputTemplateId?: InputMaybe; + startDate?: InputMaybe; +}; export type UpdateRoleInput = { - name?: InputMaybe -} + name?: InputMaybe; +}; export type UpdateSubrecipientInput = { - certifiedAt?: InputMaybe - certifiedById?: InputMaybe - endDate?: InputMaybe - name?: InputMaybe - organizationId?: InputMaybe - originationUploadId?: InputMaybe - startDate?: InputMaybe -} + certifiedAt?: InputMaybe; + certifiedById?: InputMaybe; + endDate?: InputMaybe; + name?: InputMaybe; + organizationId?: InputMaybe; + originationUploadId?: InputMaybe; + startDate?: InputMaybe; +}; export type UpdateUploadInput = { - agencyId?: InputMaybe - expenditureCategoryId?: InputMaybe - filename?: InputMaybe - organizationId?: InputMaybe - reportingPeriodId?: InputMaybe - uploadedById?: InputMaybe -} + agencyId?: InputMaybe; + expenditureCategoryId?: InputMaybe; + filename?: InputMaybe; + organizationId?: InputMaybe; + reportingPeriodId?: InputMaybe; + uploadedById?: InputMaybe; +}; export type UpdateUploadValidationInput = { - agencyId?: InputMaybe - inputTemplateId?: InputMaybe - invalidatedAt?: InputMaybe - invalidatedById?: InputMaybe - invalidationResults?: InputMaybe - organizationId?: InputMaybe - uploadId?: InputMaybe - validatedAt?: InputMaybe - validatedById?: InputMaybe - validationResults?: InputMaybe -} + agencyId?: InputMaybe; + inputTemplateId?: InputMaybe; + invalidatedAt?: InputMaybe; + invalidatedById?: InputMaybe; + invalidationResults?: InputMaybe; + organizationId?: InputMaybe; + uploadId?: InputMaybe; + validatedAt?: InputMaybe; + validatedById?: InputMaybe; + validationResults?: InputMaybe; +}; export type UpdateUserInput = { - agencyId?: InputMaybe - email?: InputMaybe - name?: InputMaybe - organizationId?: InputMaybe - roleId?: InputMaybe -} + agencyId?: InputMaybe; + email?: InputMaybe; + name?: InputMaybe; + organizationId?: InputMaybe; + roleId?: InputMaybe; +}; export type Upload = { - __typename?: 'Upload' - agency: Agency - agencyId: Scalars['Int'] - createdAt: Scalars['DateTime'] - expenditureCategory: ExpenditureCategory - expenditureCategoryId: Scalars['Int'] - filename: Scalars['String'] - id: Scalars['Int'] - organization: Organization - organizationId: Scalars['Int'] - reportingPeriod: ReportingPeriod - reportingPeriodId: Scalars['Int'] - updatedAt: Scalars['DateTime'] - uploadedBy: User - uploadedById: Scalars['Int'] - validations: Array> -} + __typename?: 'Upload'; + agency: Agency; + agencyId: Scalars['Int']; + createdAt: Scalars['DateTime']; + expenditureCategory: ExpenditureCategory; + expenditureCategoryId: Scalars['Int']; + filename: Scalars['String']; + id: Scalars['Int']; + organization: Organization; + organizationId: Scalars['Int']; + reportingPeriod: ReportingPeriod; + reportingPeriodId: Scalars['Int']; + updatedAt: Scalars['DateTime']; + uploadedBy: User; + uploadedById: Scalars['Int']; + validations: Array>; +}; export type UploadValidation = { - __typename?: 'UploadValidation' - agency: Agency - agencyId: Scalars['Int'] - createdAt: Scalars['DateTime'] - id: Scalars['Int'] - inputTemplate: InputTemplate - inputTemplateId: Scalars['Int'] - invalidatedAt?: Maybe - invalidatedBy?: Maybe - invalidatedById?: Maybe - invalidationResults?: Maybe - organization: Organization - organizationId: Scalars['Int'] - updatedAt: Scalars['DateTime'] - upload: Upload - uploadId: Scalars['Int'] - validatedAt?: Maybe - validatedBy?: Maybe - validatedById?: Maybe - validationResults?: Maybe -} + __typename?: 'UploadValidation'; + agency: Agency; + agencyId: Scalars['Int']; + createdAt: Scalars['DateTime']; + id: Scalars['Int']; + inputTemplate: InputTemplate; + inputTemplateId: Scalars['Int']; + invalidatedAt?: Maybe; + invalidatedBy?: Maybe; + invalidatedById?: Maybe; + invalidationResults?: Maybe; + organization: Organization; + organizationId: Scalars['Int']; + updatedAt: Scalars['DateTime']; + upload: Upload; + uploadId: Scalars['Int']; + validatedAt?: Maybe; + validatedBy?: Maybe; + validatedById?: Maybe; + validationResults?: Maybe; +}; export type User = { - __typename?: 'User' - agency?: Maybe - agencyId?: Maybe - certified: Array> - createdAt: Scalars['DateTime'] - email: Scalars['String'] - id: Scalars['Int'] - name?: Maybe - organization: Organization - organizationId: Scalars['Int'] - role?: Maybe - roleId?: Maybe - updatedAt: Scalars['DateTime'] -} + __typename?: 'User'; + agency?: Maybe; + agencyId?: Maybe; + certified: Array>; + createdAt: Scalars['DateTime']; + email: Scalars['String']; + id: Scalars['Int']; + name?: Maybe; + organization: Organization; + organizationId: Scalars['Int']; + role?: Maybe; + roleId?: Maybe; + updatedAt: Scalars['DateTime']; +}; export type FindAgenciesByOrganizationIdVariables = Exact<{ - organizationId: Scalars['Int'] -}> - -export type FindAgenciesByOrganizationId = { - __typename?: 'Query' - agenciesByOrganization: Array<{ - __typename?: 'Agency' - id: number - name: string - abbreviation?: string | null - code: string - }> -} + organizationId: Scalars['Int']; +}>; + + +export type FindAgenciesByOrganizationId = { __typename?: 'Query', agenciesByOrganization: Array<{ __typename?: 'Agency', id: number, name: string, abbreviation?: string | null, code: string }> }; export type DeleteAgencyMutationVariables = Exact<{ - id: Scalars['Int'] -}> + id: Scalars['Int']; +}>; -export type DeleteAgencyMutation = { - __typename?: 'Mutation' - deleteAgency: { __typename?: 'Agency'; id: number } -} + +export type DeleteAgencyMutation = { __typename?: 'Mutation', deleteAgency: { __typename?: 'Agency', id: number } }; export type FindAgencyByIdVariables = Exact<{ - id: Scalars['Int'] -}> - -export type FindAgencyById = { - __typename?: 'Query' - agency?: { - __typename?: 'Agency' - id: number - name: string - abbreviation?: string | null - code: string - } | null -} + id: Scalars['Int']; +}>; + + +export type FindAgencyById = { __typename?: 'Query', agency?: { __typename?: 'Agency', id: number, name: string, abbreviation?: string | null, code: string } | null }; export type EditAgencyByIdVariables = Exact<{ - id: Scalars['Int'] -}> - -export type EditAgencyById = { - __typename?: 'Query' - agency?: { - __typename?: 'Agency' - id: number - name: string - abbreviation?: string | null - code: string - } | null -} + id: Scalars['Int']; +}>; + + +export type EditAgencyById = { __typename?: 'Query', agency?: { __typename?: 'Agency', id: number, name: string, abbreviation?: string | null, code: string } | null }; export type UpdateAgencyMutationVariables = Exact<{ - id: Scalars['Int'] - input: UpdateAgencyInput -}> - -export type UpdateAgencyMutation = { - __typename?: 'Mutation' - updateAgency: { - __typename?: 'Agency' - id: number - name: string - abbreviation?: string | null - code: string - } -} + id: Scalars['Int']; + input: UpdateAgencyInput; +}>; + + +export type UpdateAgencyMutation = { __typename?: 'Mutation', updateAgency: { __typename?: 'Agency', id: number, name: string, abbreviation?: string | null, code: string } }; export type CreateAgencyMutationVariables = Exact<{ - input: CreateAgencyInput -}> + input: CreateAgencyInput; +}>; -export type CreateAgencyMutation = { - __typename?: 'Mutation' - createAgency: { __typename?: 'Agency'; id: number } -} + +export type CreateAgencyMutation = { __typename?: 'Mutation', createAgency: { __typename?: 'Agency', id: number } }; export type EditOrganizationByIdVariables = Exact<{ - id: Scalars['Int'] -}> - -export type EditOrganizationById = { - __typename?: 'Query' - organization?: { - __typename?: 'Organization' - id: number - name: string - } | null -} + id: Scalars['Int']; +}>; + + +export type EditOrganizationById = { __typename?: 'Query', organization?: { __typename?: 'Organization', id: number, name: string } | null }; export type UpdateOrganizationMutationVariables = Exact<{ - id: Scalars['Int'] - input: UpdateOrganizationInput -}> + id: Scalars['Int']; + input: UpdateOrganizationInput; +}>; -export type UpdateOrganizationMutation = { - __typename?: 'Mutation' - updateOrganization: { __typename?: 'Organization'; id: number; name: string } -} + +export type UpdateOrganizationMutation = { __typename?: 'Mutation', updateOrganization: { __typename?: 'Organization', id: number, name: string } }; export type CreateOrganizationMutationVariables = Exact<{ - input: CreateOrganizationInput -}> + input: CreateOrganizationInput; +}>; + -export type CreateOrganizationMutation = { - __typename?: 'Mutation' - createOrganization: { __typename?: 'Organization'; id: number } -} +export type CreateOrganizationMutation = { __typename?: 'Mutation', createOrganization: { __typename?: 'Organization', id: number } }; export type DeleteOrganizationMutationVariables = Exact<{ - id: Scalars['Int'] -}> + id: Scalars['Int']; +}>; -export type DeleteOrganizationMutation = { - __typename?: 'Mutation' - deleteOrganization: { __typename?: 'Organization'; id: number } -} + +export type DeleteOrganizationMutation = { __typename?: 'Mutation', deleteOrganization: { __typename?: 'Organization', id: number } }; export type FindOrganizationByIdVariables = Exact<{ - id: Scalars['Int'] -}> - -export type FindOrganizationById = { - __typename?: 'Query' - organization?: { - __typename?: 'Organization' - id: number - name: string - } | null -} - -export type FindOrganizationsVariables = Exact<{ [key: string]: never }> - -export type FindOrganizations = { - __typename?: 'Query' - organizations: Array<{ - __typename?: 'Organization' - id: number - name: string - }> -} + id: Scalars['Int']; +}>; + + +export type FindOrganizationById = { __typename?: 'Query', organization?: { __typename?: 'Organization', id: number, name: string } | null }; + +export type FindOrganizationsVariables = Exact<{ [key: string]: never; }>; + + +export type FindOrganizations = { __typename?: 'Query', organizations: Array<{ __typename?: 'Organization', id: number, name: string }> }; export type FindReportingPeriodQueryVariables = Exact<{ - id: Scalars['Int'] -}> + id: Scalars['Int']; +}>; + + +export type FindReportingPeriodQuery = { __typename?: 'Query', reportingPeriod?: { __typename?: 'ReportingPeriod', name: string } | null }; -export type FindReportingPeriodQuery = { - __typename?: 'Query' - reportingPeriod?: { __typename?: 'ReportingPeriod'; name: string } | null -} +export type ReportingPeriodsQueryVariables = Exact<{ [key: string]: never; }>; -export type ReportingPeriodsQueryVariables = Exact<{ [key: string]: never }> + +export type ReportingPeriodsQuery = { __typename?: 'Query', reportingPeriods: Array<{ __typename?: 'ReportingPeriod', id: number, startDate: string, endDate: string, isCurrentPeriod: boolean, certifiedAt?: string | null, certifiedBy?: { __typename?: 'User', email: string } | null, inputTemplate: { __typename?: 'InputTemplate', name: string } }> }; export type EditUploadByIdVariables = Exact<{ - id: Scalars['Int'] -}> - -export type EditUploadById = { - __typename?: 'Query' - upload?: { - __typename?: 'Upload' - id: number - filename: string - uploadedById: number - agencyId: number - organizationId: number - reportingPeriodId: number - expenditureCategoryId: number - createdAt: string - updatedAt: string - } | null -} + id: Scalars['Int']; +}>; + + +export type EditUploadById = { __typename?: 'Query', upload?: { __typename?: 'Upload', id: number, filename: string, uploadedById: number, agencyId: number, organizationId: number, reportingPeriodId: number, expenditureCategoryId: number, createdAt: string, updatedAt: string } | null }; export type UpdateUploadMutationVariables = Exact<{ - id: Scalars['Int'] - input: UpdateUploadInput -}> - -export type UpdateUploadMutation = { - __typename?: 'Mutation' - updateUpload: { - __typename?: 'Upload' - id: number - filename: string - uploadedById: number - agencyId: number - organizationId: number - reportingPeriodId: number - expenditureCategoryId: number - createdAt: string - updatedAt: string - } -} + id: Scalars['Int']; + input: UpdateUploadInput; +}>; + + +export type UpdateUploadMutation = { __typename?: 'Mutation', updateUpload: { __typename?: 'Upload', id: number, filename: string, uploadedById: number, agencyId: number, organizationId: number, reportingPeriodId: number, expenditureCategoryId: number, createdAt: string, updatedAt: string } }; export type CreateUploadMutationVariables = Exact<{ - input: CreateUploadInput -}> + input: CreateUploadInput; +}>; -export type CreateUploadMutation = { - __typename?: 'Mutation' - createUpload: { __typename?: 'Upload'; id: number } -} + +export type CreateUploadMutation = { __typename?: 'Mutation', createUpload: { __typename?: 'Upload', id: number } }; export type DeleteUploadMutationVariables = Exact<{ - id: Scalars['Int'] -}> + id: Scalars['Int']; +}>; + -export type DeleteUploadMutation = { - __typename?: 'Mutation' - deleteUpload: { __typename?: 'Upload'; id: number } -} +export type DeleteUploadMutation = { __typename?: 'Mutation', deleteUpload: { __typename?: 'Upload', id: number } }; export type FindUploadByIdVariables = Exact<{ - id: Scalars['Int'] -}> - -export type FindUploadById = { - __typename?: 'Query' - upload?: { - __typename?: 'Upload' - id: number - filename: string - uploadedById: number - agencyId: number - organizationId: number - reportingPeriodId: number - expenditureCategoryId: number - createdAt: string - updatedAt: string - } | null -} - -export type FindUploadsVariables = Exact<{ [key: string]: never }> - -export type FindUploads = { - __typename?: 'Query' - uploads: Array<{ - __typename?: 'Upload' - id: number - filename: string - createdAt: string - updatedAt: string - uploadedBy: { __typename?: 'User'; id: number; email: string } - agency: { __typename?: 'Agency'; id: number; code: string } - expenditureCategory: { - __typename?: 'ExpenditureCategory' - id: number - code: string - } - validations: Array<{ - __typename?: 'UploadValidation' - invalidatedAt?: string | null - validatedAt?: string | null - } | null> - }> -} - -export type ReportingPeriodsQuery = { - __typename?: 'Query' - reportingPeriods: Array<{ - __typename?: 'ReportingPeriod' - id: number - startDate: string - endDate: string - isCurrentPeriod: boolean - certifiedAt?: string | null - certifiedBy?: { __typename?: 'User'; email: string } | null - inputTemplate: { __typename?: 'InputTemplate'; name: string } - }> -} + id: Scalars['Int']; +}>; + + +export type FindUploadById = { __typename?: 'Query', upload?: { __typename?: 'Upload', id: number, filename: string, uploadedById: number, agencyId: number, organizationId: number, reportingPeriodId: number, expenditureCategoryId: number, createdAt: string, updatedAt: string } | null }; + +export type FindUploadsVariables = Exact<{ [key: string]: never; }>; + + +export type FindUploads = { __typename?: 'Query', uploads: Array<{ __typename?: 'Upload', id: number, filename: string, createdAt: string, updatedAt: string, uploadedBy: { __typename?: 'User', id: number, email: string }, agency: { __typename?: 'Agency', id: number, code: string }, expenditureCategory: { __typename?: 'ExpenditureCategory', id: number, code: string }, validations: Array<{ __typename?: 'UploadValidation', invalidatedAt?: string | null, validatedAt?: string | null } | null> }> }; From ca284067dd9581fe30fe5a23117cc12e7e57c71a Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Thu, 14 Dec 2023 15:12:23 -0500 Subject: [PATCH 11/11] feature/3 update logic around upload validations --- web/src/components/Upload/Uploads/Uploads.tsx | 58 +++++++++++-------- web/src/components/Upload/Uploads/columns.tsx | 14 ++--- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/web/src/components/Upload/Uploads/Uploads.tsx b/web/src/components/Upload/Uploads/Uploads.tsx index e79ecb6a..84f46cf7 100644 --- a/web/src/components/Upload/Uploads/Uploads.tsx +++ b/web/src/components/Upload/Uploads/Uploads.tsx @@ -7,42 +7,52 @@ import TableBuilder from 'src/components/TableBuilder/TableBuilder' import { columnDefs } from './columns' const UploadsList = ({ uploads }: FindUploads) => { - // Uploads.validations is an array that can contain both valid and invalid validations, - // We store the latest valid and invalid entry - function findLatestValidationAndInvalidationDatesFromUpload(upload) { + function toDateOrNull(dateString) { + return dateString ? new Date(dateString) : null + } + + function getLaterDate(date1, date2) { + if (!date1) return date2 + if (!date2) return date1 + return date1 > date2 ? date1 : date2 + } + + /* + Returns an object that either contains the latest validation date or the latest invalidation date + (depending which validation date is later) or an empty object if no dates are found + */ + function findLatestValidationEntry(upload) { let latestInvalidationDate = null let latestValidationDate = null upload.validations.forEach((validation) => { - if (validation.invalidatedAt) { - // Update latestInvalidationDate if it's null or if this date is more recent - if ( - !latestInvalidationDate || - Date.parse(validation.invalidatedAt) > - Date.parse(latestInvalidationDate) - ) { - latestInvalidationDate = validation.invalidatedAt - } - } + const invalidatedDate = toDateOrNull(validation.invalidatedAt) + const validatedDate = toDateOrNull(validation.validatedAt) - if (validation.validatedAt) { - // Update latestValidationDate if it's null or if this date is more recent - if ( - !latestValidationDate || - Date.parse(validation.validationAt) > Date.parse(latestValidationDate) - ) { - latestValidationDate = validation.validatedAt - } - } + latestInvalidationDate = getLaterDate( + latestInvalidationDate, + invalidatedDate + ) + latestValidationDate = getLaterDate(latestValidationDate, validatedDate) }) - return { latestInvalidationDate, latestValidationDate } + if (!latestInvalidationDate && !latestValidationDate) { + return {} // Return an empty object if no dates are found + } + + const isInvalidationLatest = latestInvalidationDate > latestValidationDate + + return { + invalidatedAt: isInvalidationLatest ? latestInvalidationDate : null, + validatedAt: isInvalidationLatest ? null : latestValidationDate, + } } const uploadsWithValidationDates = uploads.map((upload) => { + const latestValidation = findLatestValidationEntry(upload) return { ...upload, - ...findLatestValidationAndInvalidationDatesFromUpload(upload), + latestValidation, } }) diff --git a/web/src/components/Upload/Uploads/columns.tsx b/web/src/components/Upload/Uploads/columns.tsx index f502787e..83063e62 100644 --- a/web/src/components/Upload/Uploads/columns.tsx +++ b/web/src/components/Upload/Uploads/columns.tsx @@ -21,15 +21,15 @@ function valueAsLink(cell): JSX.Element { } function validationDisplay(row) { - if (row.latestInvalidationDate) { - const formattedDate = formatDateString(row.latestInvalidationDate) - return `Invalidated at ${formattedDate}` + const validations = row.latestValidation + + if (validations.invalidatedAt) { + const formattedDate = formatDateString(validations.invalidatedAt) + return Invalidated at {formattedDate} } - // Else, display 'Validated at' if latestValidationDate is available - if (row.latestValidationDate) { - const formattedDate = formatDateString(row.latestValidationDate) - return `Validated at ${formattedDate}` + if (validations.validatedAt) { + return formatDateString(validations.validatedAt) } // If neither date is available, display nothing or a default message