From 2b87dc3320ee1b4c4f312054ea6e51254467adcb Mon Sep 17 00:00:00 2001
From: Anson He <60114875+ansonjwhe@users.noreply.github.com>
Date: Sat, 17 Feb 2024 19:14:02 -0500
Subject: [PATCH] ASP dashboard list view and onsite contact migration (#92)
---
.github/workflows/lint.yml | 3 +-
.gitignore | 3 +-
.idea/.gitignore | 3 +
.idea/feeding-canadian-kids.iml | 15 +
.../inspectionProfiles/profiles_settings.xml | 6 +
.idea/misc.xml | 7 +
.idea/modules.xml | 8 +
.idea/vcs.xml | 6 +
README.md | 13 +-
backend/Dockerfile | 1 -
backend/Makefile | 6 +-
backend/app/graphql/__init__.py | 16 +-
backend/app/graphql/meal_request.py | 47 +-
.../app/graphql/onsite_contact_mutations.py | 96 ++
backend/app/graphql/onsite_contact_queries.py | 20 +
backend/app/graphql/services.py | 6 +-
backend/app/graphql/types.py | 18 +-
backend/app/models/meal_request.py | 31 +-
backend/app/models/onsite_contact.py | 33 +
backend/app/models/user.py | 2 +-
backend/app/models/user_info.py | 6 +-
backend/app/resources/meal_request_dto.py | 22 +-
backend/app/resources/onsite_contact_dto.py | 31 +
backend/app/resources/validate_utils.py | 4 +-
.../implementations/meal_request_service.py | 43 +-
.../onboarding_request_service.py | 4 +-
.../implementations/onsite_contact_service.py | 80 ++
.../services/implementations/user_service.py | 23 +-
.../app/services/interfaces/auth_service.py | 4 +-
.../interfaces/meal_request_service.py | 19 +-
.../interfaces/onsite_contact_service.py | 51 +
.../app/utilities/location_to_coordinates.py | 29 +-
backend/mypy.ini | 6 +
backend/setup.cfg | 3 +-
backend/tests/graphql/conftest.py | 60 +-
backend/tests/graphql/mock_test_data.py | 89 +-
.../tests/graphql/test_all_user_mutations.py | 42 +-
.../tests/graphql/test_all_user_queries.py | 9 +-
backend/tests/graphql/test_meal_request.py | 140 ++-
.../tests/graphql/test_onboarding_request.py | 38 +-
backend/tests/graphql/test_onsite_contact.py | 168 ++++
backend/tests/unit/test_models.py | 18 +-
backend/typings/graphene/__init__.pyi | 87 ++
backend/typings/graphene/pyutils/__init__.pyi | 0
.../typings/graphene/pyutils/dataclasses.pyi | 94 ++
backend/typings/graphene/pyutils/version.pyi | 7 +
backend/typings/graphene/relay/__init__.pyi | 17 +
backend/typings/graphene/relay/connection.pyi | 54 ++
backend/typings/graphene/relay/mutation.pyi | 19 +
backend/typings/graphene/relay/node.pyi | 59 ++
backend/typings/graphene/types/__init__.pyi | 60 ++
backend/typings/graphene/types/argument.pyi | 24 +
backend/typings/graphene/types/base.pyi | 28 +
backend/typings/graphene/types/base64.pyi | 10 +
backend/typings/graphene/types/context.pyi | 2 +
backend/typings/graphene/types/datetime.pyi | 26 +
backend/typings/graphene/types/decimal.pyi | 10 +
.../typings/graphene/types/definitions.pyi | 23 +
backend/typings/graphene/types/dynamic.pyi | 13 +
backend/typings/graphene/types/enum.pyi | 36 +
backend/typings/graphene/types/field.pyi | 39 +
backend/typings/graphene/types/generic.pyi | 11 +
backend/typings/graphene/types/inputfield.pyi | 23 +
.../graphene/types/inputobjecttype.pyi | 29 +
backend/typings/graphene/types/interface.pyi | 20 +
backend/typings/graphene/types/json.pyi | 10 +
.../typings/graphene/types/mountedtype.pyi | 6 +
backend/typings/graphene/types/mutation.pyi | 38 +
backend/typings/graphene/types/objecttype.pyi | 32 +
backend/typings/graphene/types/resolver.pyi | 8 +
backend/typings/graphene/types/scalars.pyi | 62 ++
backend/typings/graphene/types/schema.pyi | 89 ++
backend/typings/graphene/types/structures.pyi | 15 +
backend/typings/graphene/types/union.pyi | 20 +
.../typings/graphene/types/unmountedtype.pyi | 13 +
backend/typings/graphene/types/utils.pyi | 9 +
backend/typings/graphene/types/uuid.pyi | 10 +
backend/typings/graphene/utils/__init__.pyi | 0
backend/typings/graphene/utils/crunch.pyi | 4 +
backend/typings/graphene/utils/dataloader.pyi | 39 +
.../typings/graphene/utils/deduplicator.pyi | 3 +
backend/typings/graphene/utils/deprecated.pyi | 6 +
.../graphene/utils/get_unbound_function.pyi | 1 +
.../graphene/utils/is_introspection_key.pyi | 1 +
.../typings/graphene/utils/module_loading.pyi | 4 +
.../typings/graphene/utils/orderedtype.pyi | 12 +
backend/typings/graphene/utils/props.pyi | 4 +
.../graphene/utils/resolve_only_args.pyi | 3 +
.../typings/graphene/utils/str_converters.pyi | 2 +
.../graphene/utils/subclass_with_meta.pyi | 8 +
backend/typings/graphene/utils/thenables.pyi | 2 +
.../typings/graphene/utils/trim_docstring.pyi | 1 +
.../typings/graphene/validation/__init__.pyi | 4 +
.../graphene/validation/depth_limit.pyi | 34 +
.../validation/disable_introspection.pyi | 6 +
backend/typings/mongoengine/__init__.pyi | 205 ++++
backend/typings/mongoengine/base/__init__.pyi | 38 +
backend/typings/mongoengine/base/common.pyi | 8 +
.../mongoengine/base/datastructures.pyi | 86 ++
backend/typings/mongoengine/base/document.pyi | 25 +
backend/typings/mongoengine/base/fields.pyi | 72 ++
.../typings/mongoengine/base/metaclasses.pyi | 14 +
backend/typings/mongoengine/base/utils.pyi | 6 +
backend/typings/mongoengine/common.pyi | 0
backend/typings/mongoengine/connection.pyi | 38 +
.../typings/mongoengine/context_managers.pyi | 90 ++
backend/typings/mongoengine/dereference.pyi | 33 +
backend/typings/mongoengine/document.pyi | 89 ++
backend/typings/mongoengine/errors.pyi | 40 +
backend/typings/mongoengine/fields.pyi | 463 +++++++++
.../typings/mongoengine/mongodb_support.pyi | 9 +
.../typings/mongoengine/pymongo_support.pyi | 14 +
.../typings/mongoengine/queryset/__init__.pyi | 43 +
backend/typings/mongoengine/queryset/base.pyi | 120 +++
.../mongoengine/queryset/field_list.pyi | 22 +
.../typings/mongoengine/queryset/manager.pyi | 12 +
.../typings/mongoengine/queryset/queryset.pyi | 28 +
.../mongoengine/queryset/transform.pyi | 8 +
.../typings/mongoengine/queryset/visitor.pyi | 48 +
backend/typings/mongoengine/signals.pyi | 33 +
e2e-tests/test_entity_gql.py | 4 +-
e2e-tests/test_simple_entity_gql.py | 2 +-
e2e-tests/test_user_gql.py | 4 +-
frontend/.eslintrc.js | 7 +-
frontend/Dockerfile | 1 -
frontend/babel.config.js | 1 +
frontend/package.json | 12 +-
frontend/src/App.tsx | 22 +-
frontend/src/Routes.tsx | 4 +-
.../asp/requests/CreateMealRequest.tsx | 23 +-
.../SchedulingFormReviewAndSubmit.tsx | 14 +-
.../components/asp/requests/TitleSection.tsx | 4 +-
frontend/src/components/auth/Join.tsx | 654 ++++++-------
frontend/src/components/auth/JoinSuccess.tsx | 4 +-
frontend/src/components/auth/Login.tsx | 18 +-
frontend/src/components/auth/SetPassword.tsx | 17 +-
frontend/src/components/common/Footer.tsx | 4 +-
frontend/src/components/common/Header.tsx | 282 +++---
.../src/components/common/LoadingSpinner.tsx | 19 +
.../components/common/OnsiteStaffSection.tsx | 305 +++---
.../components/crud/DisplayTableContainer.tsx | 6 +-
.../SimpleEntityDisplayTableContainer.tsx | 6 +-
.../src/components/mealrequest/ListView.tsx | 546 +++++++++++
frontend/src/constants/Routes.ts | 2 +-
frontend/src/pages/ASPDashboard.tsx | 118 +++
frontend/src/pages/CreatePage.tsx | 4 +-
frontend/src/pages/Dashboard.tsx | 60 --
frontend/src/pages/Default.tsx | 50 +-
frontend/src/pages/DisplayPage.tsx | 4 +-
frontend/src/pages/EditMealRequestForm.tsx | 609 ++++++++----
frontend/src/pages/MealDonorDashboard.tsx | 4 +-
frontend/src/pages/NotFound.tsx | 4 +-
frontend/src/pages/Settings.tsx | 899 ++++++++++--------
frontend/src/pages/SimpleEntityCreatePage.tsx | 4 +-
.../src/pages/SimpleEntityDisplayPage.tsx | 4 +-
frontend/src/pages/SimpleEntityUpdatePage.tsx | 4 +-
frontend/src/pages/UpdatePage.tsx | 4 +-
.../src/pages/__tests__/Dashboard.test.tsx | 18 +-
frontend/src/theme/components/text.ts | 7 +
frontend/src/types/MealRequestTypes.ts | 50 +
frontend/src/types/UserTypes.ts | 14 +-
frontend/src/utils/AuthUtils.ts | 3 +-
frontend/src/utils/GraphQLUtils.ts | 15 +
frontend/src/utils/ValidationUtils.ts | 16 +-
frontend/src/utils/useGetOnsiteContacts.ts | 59 ++
frontend/src/utils/useIsAdmin.ts | 11 +
frontend/src/utils/useIsMealDonor.ts | 11 +
frontend/tsconfig.json | 6 +-
frontend/yarn.lock | 859 ++++++++++++++++-
update_secret_files.py | 1 +
170 files changed, 7048 insertions(+), 1661 deletions(-)
create mode 100644 .idea/.gitignore
create mode 100644 .idea/feeding-canadian-kids.iml
create mode 100644 .idea/inspectionProfiles/profiles_settings.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/modules.xml
create mode 100644 .idea/vcs.xml
create mode 100644 backend/app/graphql/onsite_contact_mutations.py
create mode 100644 backend/app/graphql/onsite_contact_queries.py
create mode 100644 backend/app/models/onsite_contact.py
create mode 100644 backend/app/resources/onsite_contact_dto.py
create mode 100644 backend/app/services/implementations/onsite_contact_service.py
create mode 100644 backend/app/services/interfaces/onsite_contact_service.py
create mode 100644 backend/mypy.ini
create mode 100644 backend/tests/graphql/test_onsite_contact.py
create mode 100644 backend/typings/graphene/__init__.pyi
create mode 100644 backend/typings/graphene/pyutils/__init__.pyi
create mode 100644 backend/typings/graphene/pyutils/dataclasses.pyi
create mode 100644 backend/typings/graphene/pyutils/version.pyi
create mode 100644 backend/typings/graphene/relay/__init__.pyi
create mode 100644 backend/typings/graphene/relay/connection.pyi
create mode 100644 backend/typings/graphene/relay/mutation.pyi
create mode 100644 backend/typings/graphene/relay/node.pyi
create mode 100644 backend/typings/graphene/types/__init__.pyi
create mode 100644 backend/typings/graphene/types/argument.pyi
create mode 100644 backend/typings/graphene/types/base.pyi
create mode 100644 backend/typings/graphene/types/base64.pyi
create mode 100644 backend/typings/graphene/types/context.pyi
create mode 100644 backend/typings/graphene/types/datetime.pyi
create mode 100644 backend/typings/graphene/types/decimal.pyi
create mode 100644 backend/typings/graphene/types/definitions.pyi
create mode 100644 backend/typings/graphene/types/dynamic.pyi
create mode 100644 backend/typings/graphene/types/enum.pyi
create mode 100644 backend/typings/graphene/types/field.pyi
create mode 100644 backend/typings/graphene/types/generic.pyi
create mode 100644 backend/typings/graphene/types/inputfield.pyi
create mode 100644 backend/typings/graphene/types/inputobjecttype.pyi
create mode 100644 backend/typings/graphene/types/interface.pyi
create mode 100644 backend/typings/graphene/types/json.pyi
create mode 100644 backend/typings/graphene/types/mountedtype.pyi
create mode 100644 backend/typings/graphene/types/mutation.pyi
create mode 100644 backend/typings/graphene/types/objecttype.pyi
create mode 100644 backend/typings/graphene/types/resolver.pyi
create mode 100644 backend/typings/graphene/types/scalars.pyi
create mode 100644 backend/typings/graphene/types/schema.pyi
create mode 100644 backend/typings/graphene/types/structures.pyi
create mode 100644 backend/typings/graphene/types/union.pyi
create mode 100644 backend/typings/graphene/types/unmountedtype.pyi
create mode 100644 backend/typings/graphene/types/utils.pyi
create mode 100644 backend/typings/graphene/types/uuid.pyi
create mode 100644 backend/typings/graphene/utils/__init__.pyi
create mode 100644 backend/typings/graphene/utils/crunch.pyi
create mode 100644 backend/typings/graphene/utils/dataloader.pyi
create mode 100644 backend/typings/graphene/utils/deduplicator.pyi
create mode 100644 backend/typings/graphene/utils/deprecated.pyi
create mode 100644 backend/typings/graphene/utils/get_unbound_function.pyi
create mode 100644 backend/typings/graphene/utils/is_introspection_key.pyi
create mode 100644 backend/typings/graphene/utils/module_loading.pyi
create mode 100644 backend/typings/graphene/utils/orderedtype.pyi
create mode 100644 backend/typings/graphene/utils/props.pyi
create mode 100644 backend/typings/graphene/utils/resolve_only_args.pyi
create mode 100644 backend/typings/graphene/utils/str_converters.pyi
create mode 100644 backend/typings/graphene/utils/subclass_with_meta.pyi
create mode 100644 backend/typings/graphene/utils/thenables.pyi
create mode 100644 backend/typings/graphene/utils/trim_docstring.pyi
create mode 100644 backend/typings/graphene/validation/__init__.pyi
create mode 100644 backend/typings/graphene/validation/depth_limit.pyi
create mode 100644 backend/typings/graphene/validation/disable_introspection.pyi
create mode 100644 backend/typings/mongoengine/__init__.pyi
create mode 100644 backend/typings/mongoengine/base/__init__.pyi
create mode 100644 backend/typings/mongoengine/base/common.pyi
create mode 100644 backend/typings/mongoengine/base/datastructures.pyi
create mode 100644 backend/typings/mongoengine/base/document.pyi
create mode 100644 backend/typings/mongoengine/base/fields.pyi
create mode 100644 backend/typings/mongoengine/base/metaclasses.pyi
create mode 100644 backend/typings/mongoengine/base/utils.pyi
create mode 100644 backend/typings/mongoengine/common.pyi
create mode 100644 backend/typings/mongoengine/connection.pyi
create mode 100644 backend/typings/mongoengine/context_managers.pyi
create mode 100644 backend/typings/mongoengine/dereference.pyi
create mode 100644 backend/typings/mongoengine/document.pyi
create mode 100644 backend/typings/mongoengine/errors.pyi
create mode 100644 backend/typings/mongoengine/fields.pyi
create mode 100644 backend/typings/mongoengine/mongodb_support.pyi
create mode 100644 backend/typings/mongoengine/pymongo_support.pyi
create mode 100644 backend/typings/mongoengine/queryset/__init__.pyi
create mode 100644 backend/typings/mongoengine/queryset/base.pyi
create mode 100644 backend/typings/mongoengine/queryset/field_list.pyi
create mode 100644 backend/typings/mongoengine/queryset/manager.pyi
create mode 100644 backend/typings/mongoengine/queryset/queryset.pyi
create mode 100644 backend/typings/mongoengine/queryset/transform.pyi
create mode 100644 backend/typings/mongoengine/queryset/visitor.pyi
create mode 100644 backend/typings/mongoengine/signals.pyi
create mode 100644 frontend/babel.config.js
create mode 100644 frontend/src/components/common/LoadingSpinner.tsx
create mode 100644 frontend/src/components/mealrequest/ListView.tsx
create mode 100644 frontend/src/pages/ASPDashboard.tsx
delete mode 100644 frontend/src/pages/Dashboard.tsx
create mode 100644 frontend/src/types/MealRequestTypes.ts
create mode 100644 frontend/src/utils/GraphQLUtils.ts
create mode 100644 frontend/src/utils/useGetOnsiteContacts.ts
create mode 100644 frontend/src/utils/useIsAdmin.ts
create mode 100644 frontend/src/utils/useIsMealDonor.ts
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 674ee866..dd771895 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -1,4 +1,3 @@
-
name: Lint codebase
on:
@@ -52,4 +51,4 @@ jobs:
- name: Lint backend
if: steps.changes.outputs.backend == 'true'
working-directory: ./backend
- run: pip install black flake8 && python -m black --check . && python -m flake8 .
+ run: pip install black flake8 && python -m black --check . --exclude ".*typings.*|test_csv.py" && flake8 .
diff --git a/.gitignore b/.gitignore
index 093f0d82..0a014b41 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,4 +11,5 @@
**/*.cache
**/*.egg-info
**/*.eslintcache
-**/*.swp
\ No newline at end of file
+**/*.swp
+**/.mypy_cache/**
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000..26d33521
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/feeding-canadian-kids.iml b/.idea/feeding-canadian-kids.iml
new file mode 100644
index 00000000..5fdd65ba
--- /dev/null
+++ b/.idea/feeding-canadian-kids.iml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 00000000..105ce2da
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..a377feb7
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000..0e711090
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 97b17fbe..8d1ee1aa 100644
--- a/README.md
+++ b/README.md
@@ -60,7 +60,18 @@ docker-compose up --build
The backend runs at http://localhost:5000 and the frontend runs at http://localhost:3000.
-If you need to login as a user, there is a user in the development db: `test@test.com` with password `12345678`.
+### Test Users
+
+Password For all test accounts: `12345678`
+
+Test ASP:
+Email: `shahan.neda+asptest1@gmail.com`
+
+Test Donor:
+Email: `shahan.neda+mealdonortest1@gmail.com`
+
+Test Admin:
+Email: `shahan.neda+testadmin1@gmail.com`
## Useful Commands
diff --git a/backend/Dockerfile b/backend/Dockerfile
index 34a970ff..e65a574a 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -1,5 +1,4 @@
FROM python:3.8
-
WORKDIR /app
COPY requirements.txt ./
diff --git a/backend/Makefile b/backend/Makefile
index 1515aded..dfaaad05 100644
--- a/backend/Makefile
+++ b/backend/Makefile
@@ -4,8 +4,8 @@ test:
docker ps -qf name=fck_backend | grep "." > /dev/null || (echo "****** Run \`docker-compose up\` first! ******" && false)
# Add -s to the end of this next line to see all prints when testing
# i.e "... python -m pytest -s"
- docker exec -it fck_backend /bin/bash -c "pip install -r requirements.txt && python -m pytest"
-
+ docker exec -it fck_backend /bin/bash -c "pip install -r requirements.txt && python -m pytest -s"
lint:
docker ps -qf name=fck_backend | grep "." > /dev/null || (echo "****** Run \`docker-compose up\` first! ******" && false)
- docker exec -it fck_backend /bin/bash -c "black . && flake8 ."
+ docker exec -it fck_backend /bin/bash -c "black . && flake8 . --exclude **/typings/**"
+
diff --git a/backend/app/graphql/__init__.py b/backend/app/graphql/__init__.py
index b937225e..332b619f 100644
--- a/backend/app/graphql/__init__.py
+++ b/backend/app/graphql/__init__.py
@@ -2,6 +2,10 @@
import os
from flask import current_app
+
+
+from .onsite_contact_mutations import OnsiteContactMutations
+from .onsite_contact_queries import OnsiteContactQueries
from .example import ExampleQueries, ExampleMutations
from .user_queries import UserQueries
from .user_mutations import UserMutations
@@ -9,6 +13,7 @@
from ..services.implementations.user_service import UserService
from ..services.implementations.email_service import EmailService
from ..services.implementations.auth_service import AuthService
+from ..services.implementations.onsite_contact_service import OnsiteContactService
from .auth import AuthMutations
from .meal_request import MealRequestMutations, MealRequestQueries
from ..services.implementations.meal_request_service import MealRequestService
@@ -24,6 +29,7 @@ class RootQuery(
UserQueries,
OnboardingRequestQueries,
MealRequestQueries,
+ OnsiteContactQueries,
):
pass
@@ -35,6 +41,7 @@ class RootMutation(
OnboardingRequestMutations,
MealRequestMutations,
UserMutations,
+ OnsiteContactMutations,
):
pass
@@ -48,7 +55,6 @@ class RootMutation(
def init_app(app):
with app.app_context():
# Add your services here: services["service_name"] = ...
- services["user_service"] = UserService(logger=current_app.logger)
services["email_service"] = EmailService(
logger=current_app.logger,
credentials={
@@ -60,6 +66,13 @@ def init_app(app):
sender_email=os.getenv("MAILER_USER"),
display_name="Feeding Canadian Kids",
)
+ services["onsite_contact_service"] = OnsiteContactService(
+ logger=current_app.logger
+ )
+ services["user_service"] = UserService(
+ logger=current_app.logger,
+ onsite_contact_service=services["onsite_contact_service"],
+ )
services["auth_service"] = AuthService(
logger=current_app.logger,
user_service=services["user_service"],
@@ -69,4 +82,3 @@ def init_app(app):
logger=current_app.logger, email_service=services["email_service"]
)
services["meal_request_service"] = MealRequestService(logger=current_app.logger)
- services["user_service"] = UserService(logger=current_app.logger)
diff --git a/backend/app/graphql/meal_request.py b/backend/app/graphql/meal_request.py
index 3bf2326a..363d4378 100644
--- a/backend/app/graphql/meal_request.py
+++ b/backend/app/graphql/meal_request.py
@@ -1,15 +1,14 @@
import graphene
from .types import (
- ContactInput,
- Contact,
Mutation,
MutationList,
+ OnsiteContact,
QueryList,
SortDirection,
User,
)
-from ..models.meal_request import MealStatus, MEAL_STATUSES
+from ..models.meal_request import MEAL_STATUSES_ENUMS, MealStatus
from ..graphql.services import services
# Input Types
@@ -34,8 +33,9 @@ class MealInfoResponse(graphene.ObjectType):
class CreateMealRequestResponse(graphene.ObjectType):
id = graphene.ID()
drop_off_datetime = graphene.DateTime(required=True)
- status = graphene.String(required=True)
+ status = graphene.Field(graphene.Enum.from_enum(MealStatus), required=True)
meal_info = graphene.Field(MealInfoResponse, required=True)
+ onsite_staff = graphene.List(OnsiteContact)
class DonationInfo(graphene.ObjectType):
@@ -48,11 +48,11 @@ class DonationInfo(graphene.ObjectType):
class MealRequestResponse(graphene.ObjectType):
id = graphene.ID()
requestor = graphene.Field(User)
- status = graphene.String()
+ status = graphene.Field(graphene.Enum.from_enum(MealStatus), required=True)
drop_off_datetime = graphene.DateTime()
drop_off_location = graphene.String()
meal_info = graphene.Field(MealInfoResponse)
- onsite_staff = graphene.List(Contact)
+ onsite_staff = graphene.List(OnsiteContact)
date_created = graphene.DateTime()
date_updated = graphene.DateTime()
delivery_instructions = graphene.String()
@@ -70,7 +70,7 @@ class Arguments:
drop_off_time = graphene.Time(required=True)
drop_off_location = graphene.String(required=True)
delivery_instructions = graphene.String(default_value=None)
- onsite_staff = graphene.List(ContactInput, required=True)
+ onsite_staff = graphene.List(graphene.String, default_value=[])
# return values
meal_requests = graphene.List(CreateMealRequestResponse)
@@ -102,12 +102,12 @@ def mutate(
class UpdateMealRequest(Mutation):
class Arguments:
meal_request_id = graphene.ID(required=True)
- requestor = graphene.ID(required=False)
+ requestor_id = graphene.ID(required=False)
drop_off_datetime = graphene.DateTime(required=False)
meal_info = MealTypeInput()
drop_off_location = graphene.String()
delivery_instructions = graphene.String()
- onsite_staff = graphene.List(ContactInput)
+ onsite_staff = graphene.List(graphene.String)
# return values
meal_request = graphene.Field(MealRequestResponse)
@@ -116,7 +116,7 @@ def mutate(
self,
info,
meal_request_id,
- requestor=None,
+ requestor_id: str,
drop_off_datetime=None,
meal_info=None,
drop_off_location=None,
@@ -124,7 +124,7 @@ def mutate(
onsite_staff=None,
):
result = services["meal_request_service"].update_meal_request(
- requestor=requestor,
+ requestor_id=requestor_id,
meal_info=meal_info,
drop_off_datetime=drop_off_datetime,
drop_off_location=drop_off_location,
@@ -138,7 +138,7 @@ def mutate(
class CommitToMealRequest(Mutation):
class Arguments:
- requester = graphene.ID(required=True)
+ requestor = graphene.ID(required=True)
meal_request_ids = graphene.List(graphene.ID, required=True)
meal_description = graphene.String(required=True)
additional_info = graphene.String(default_value=None)
@@ -148,13 +148,13 @@ class Arguments:
def mutate(
self,
info,
- requester,
+ requestor,
meal_request_ids,
meal_description,
additional_info=None,
):
result = services["meal_request_service"].commit_to_meal_request(
- donor_id=requester,
+ donor_id=requestor,
meal_request_ids=meal_request_ids,
meal_description=meal_description,
additional_info=additional_info,
@@ -175,15 +175,32 @@ class MealRequestQueries(QueryList):
requestor_id=graphene.ID(required=True),
min_drop_off_date=graphene.Date(default_value=None),
max_drop_off_date=graphene.Date(default_value=None),
+ # status=graphene.List(graphene.Enum.from_enum(MealStatus)),
status=graphene.List(
graphene.Enum.from_enum(MealStatus),
- default_value=MEAL_STATUSES,
+ # MealStatus,
+ default_value=MEAL_STATUSES_ENUMS,
),
offset=graphene.Int(default_value=0),
limit=graphene.Int(default_value=None),
sort_by_date_direction=SortDirection(default_value=SortDirection.ASCENDING),
)
+ getMealRequestById = graphene.Field(
+ MealRequestResponse,
+ requestor_id=graphene.ID(required=True),
+ id=graphene.ID(required=True),
+ )
+
+ def resolve_getMealRequestById(
+ self,
+ info,
+ requestor_id: str,
+ id: str,
+ ):
+ meal_request = services["meal_request_service"].get_meal_request_by_id(id)
+ return meal_request
+
def resolve_getMealRequestsByRequestorId(
self,
info,
diff --git a/backend/app/graphql/onsite_contact_mutations.py b/backend/app/graphql/onsite_contact_mutations.py
new file mode 100644
index 00000000..d305cb58
--- /dev/null
+++ b/backend/app/graphql/onsite_contact_mutations.py
@@ -0,0 +1,96 @@
+import graphene
+from .services import services
+from .types import (
+ Mutation,
+ MutationList,
+ OnsiteContact,
+)
+
+
+class CreateOnsiteContact(Mutation):
+ class Arguments:
+ requestor_id = graphene.String(required=True)
+ organization_id = graphene.String(required=True)
+ name = graphene.String(required=True)
+ phone = graphene.String(required=True)
+ email = graphene.String(required=True)
+
+ onsite_contact = graphene.Field(OnsiteContact)
+
+ def mutate(self, info, requestor_id, organization_id, name, phone, email):
+ onsite_contact_service = services["onsite_contact_service"]
+ user_service = services["user_service"]
+ requestor_auth_id = user_service.get_auth_id_by_user_id(requestor_id)
+ requestor_role = user_service.get_user_role_by_auth_id(requestor_auth_id)
+
+ if requestor_role == "Admin" or requestor_id == organization_id:
+ onsite_contact_dto = onsite_contact_service.create_onsite_contact(
+ organization_id,
+ name,
+ email,
+ phone,
+ )
+ return CreateOnsiteContact(onsite_contact_dto)
+
+
+class UpdateOnsiteContact(Mutation):
+ class Arguments:
+ requestor_id = graphene.String(required=True)
+ id = graphene.String(required=True)
+ name = graphene.String()
+ phone = graphene.String()
+ email = graphene.String()
+
+ onsite_contact = graphene.Field(OnsiteContact)
+
+ def mutate(self, info, requestor_id, id, name=None, phone=None, email=None):
+ # TODO: Add requestor_id check
+ user_service = services["user_service"]
+ onsite_contact_service = services["onsite_contact_service"]
+
+ requestor_auth_id = user_service.get_auth_id_by_user_id(requestor_id)
+ requestor_role = user_service.get_user_role_by_auth_id(requestor_auth_id)
+ onsite_contact = onsite_contact_service.get_onsite_contact_by_id(id)
+ organization_id = onsite_contact.organization_id
+
+ if requestor_role != "Admin" and requestor_id != organization_id:
+ raise Exception("Unauthorized")
+
+ updated_onsite_contact = onsite_contact_service.update_onsite_contact_by_id(
+ id, name, email, phone
+ )
+ return UpdateOnsiteContact(updated_onsite_contact)
+
+
+class DeleteOnsiteContact(Mutation):
+ class Arguments:
+ requestor_id = graphene.String(required=True)
+ id = graphene.String(required=True)
+
+ success = graphene.Boolean()
+
+ def mutate(self, info, requestor_id, id):
+ onsite_contact_service = services["onsite_contact_service"]
+ user_service = services["user_service"]
+
+ requestor_auth_id = user_service.get_auth_id_by_user_id(requestor_id)
+ requestor_role = user_service.get_user_role_by_auth_id(requestor_auth_id)
+ onsite_contact = onsite_contact_service.get_onsite_contact_by_id(id)
+ organization_id = onsite_contact.organization_id
+
+ if requestor_role != "Admin" and requestor_id != organization_id:
+ raise Exception("Unauthorized")
+
+ try:
+ onsite_contact_service.delete_onsite_contact_by_id(id)
+ success = True
+ except Exception as e:
+ print(e)
+ success = False
+ return DeleteOnsiteContact(success)
+
+
+class OnsiteContactMutations(MutationList):
+ createOnsiteContact = CreateOnsiteContact.Field()
+ updateOnsiteContact = UpdateOnsiteContact.Field()
+ deleteOnsiteContact = DeleteOnsiteContact.Field()
diff --git a/backend/app/graphql/onsite_contact_queries.py b/backend/app/graphql/onsite_contact_queries.py
new file mode 100644
index 00000000..b0afec49
--- /dev/null
+++ b/backend/app/graphql/onsite_contact_queries.py
@@ -0,0 +1,20 @@
+import graphene
+from .services import services
+from .types import OnsiteContact, QueryList
+
+
+class OnsiteContactQueries(QueryList):
+ get_onsite_contact_for_user_by_id = graphene.Field(
+ graphene.List(OnsiteContact), user_id=graphene.String(required=True)
+ )
+ get_onsite_contact_by_id = graphene.Field(
+ OnsiteContact, id=graphene.String(required=True)
+ )
+
+ def resolve_get_onsite_contact_for_user_by_id(self, info, user_id):
+ return services["onsite_contact_service"].get_onsite_contacts_for_user_by_id(
+ user_id
+ )
+
+ def resolve_get_onsite_contact_by_id(self, info, id):
+ return services["onsite_contact_service"].get_onsite_contact_by_id(id)
diff --git a/backend/app/graphql/services.py b/backend/app/graphql/services.py
index d4745591..afe665db 100644
--- a/backend/app/graphql/services.py
+++ b/backend/app/graphql/services.py
@@ -1,4 +1,6 @@
from typing import TypedDict
+
+from ..services.interfaces.onsite_contact_service import IOnsiteContactService
from ..services.interfaces.user_service import IUserService
from ..services.interfaces.auth_service import IAuthService
from ..services.interfaces.email_service import IEmailService
@@ -17,6 +19,7 @@ class ServicesObject(TypedDict):
auth_service: IAuthService
onboarding_request_service: IOnboardingRequestService
meal_request_service: IMealRequestService
+ onsite_contact_service: IOnsiteContactService
services: ServicesObject = {
@@ -25,4 +28,5 @@ class ServicesObject(TypedDict):
"auth_service": None,
"onboarding_request_service": None,
"meal_request_service": None,
-}
+ "onsite_contact_service": None,
+} # type: ignore
diff --git a/backend/app/graphql/types.py b/backend/app/graphql/types.py
index f63bc94f..be15adc4 100644
--- a/backend/app/graphql/types.py
+++ b/backend/app/graphql/types.py
@@ -16,7 +16,9 @@ class QueryList(graphene.ObjectType, metaclass=LogErrors(graphene.ObjectType)):
# get around this, we declare the method initially, then delete it from the
# class definition once the validation logic has completed. This way, subclasses
# still get the validation logic.
-class Mutation(graphene.Mutation, metaclass=LogErrors(graphene.Mutation)):
+class Mutation(
+ graphene.Mutation, metaclass=LogErrors(graphene.Mutation)
+): # type: ignore
def mutate(self):
pass
@@ -57,9 +59,11 @@ class UserInfo(graphene.ObjectType):
role = graphene.String()
role_info = graphene.Field(RoleInfo)
primary_contact = graphene.Field(Contact)
- onsite_contacts = graphene.List(Contact)
+ initial_onsite_contacts = graphene.List(Contact)
active = graphene.Boolean()
+ # def resolve_onsite_contacts()
+
class ContactInput(graphene.InputObjectType):
name = graphene.String(required=True)
@@ -89,7 +93,7 @@ class UserInfoInput(graphene.InputObjectType):
role = graphene.String(required=True)
role_info = graphene.Field(RoleInfoInput)
primary_contact = graphene.Field(ContactInput, required=True)
- onsite_contacts = graphene.List(ContactInput, required=True)
+ initial_onsite_contacts = graphene.List(ContactInput, required=True)
active = graphene.Boolean()
@@ -98,6 +102,14 @@ class User(graphene.ObjectType):
info = graphene.Field(UserInfo)
+class OnsiteContact(graphene.ObjectType):
+ id = graphene.ID()
+ organization_id = graphene.String()
+ name = graphene.String()
+ email = graphene.String()
+ phone = graphene.String()
+
+
class ASPDistance(graphene.ObjectType):
id = graphene.String()
info = graphene.Field(UserInfo)
diff --git a/backend/app/models/meal_request.py b/backend/app/models/meal_request.py
index 40b76635..2deaa118 100644
--- a/backend/app/models/meal_request.py
+++ b/backend/app/models/meal_request.py
@@ -2,8 +2,9 @@
from datetime import datetime
from enum import Enum
+from app.models.onsite_contact import OnsiteContact
+
from .user import User
-from .user_info import Contact
class MealStatus(Enum):
@@ -13,7 +14,8 @@ class MealStatus(Enum):
CANCELLED = "Cancelled"
-MEAL_STATUSES = [status.value for status in MealStatus]
+MEAL_STATUSES_ENUMS = [status for status in MealStatus]
+MEAL_STATUSES_STRINGS = [status.value for status in MealStatus]
# Information on the requested meals, provided by the ASP
@@ -32,18 +34,34 @@ class DonationInfo(mg.EmbeddedDocument):
class MealRequest(mg.Document):
requestor = mg.ReferenceField(User, required=True)
+ # status = mg.EnumField(MealStatus, default=MealStatus.OPEN)
status = mg.StringField(
- choices=MEAL_STATUSES, required=True, default=MealStatus.OPEN.value
+ choices=MEAL_STATUSES_STRINGS, required=True, default=MealStatus.OPEN.value
)
+
drop_off_datetime = mg.DateTimeField(required=True)
drop_off_location = mg.StringField(required=True)
meal_info = mg.EmbeddedDocumentField(MealInfo, required=True)
- onsite_staff = mg.EmbeddedDocumentListField(Contact, required=True)
+
+ # https://docs.mongoengine.org/apireference.html#mongoengine.fields.ReferenceField
+ onsite_staff = mg.ListField(
+ mg.ReferenceField(OnsiteContact, required=True, reverse_delete_rule=4)
+ ) # 4 = PULL
date_created = mg.DateTimeField(required=True, default=datetime.utcnow)
date_updated = mg.DateTimeField(required=True, default=datetime.utcnow)
delivery_instructions = mg.StringField(default=None)
donation_info = mg.EmbeddedDocumentField(DonationInfo, default=None)
+ def validate_onsite_contacts(self):
+ if self.onsite_staff:
+ # Try to fetch the referenced document to ensure it exists, will throw an error if it doesn't
+ for contact in self.onsite_staff:
+ contact = OnsiteContact.objects(id=contact.id).first()
+ if not contact or contact.organization_id != self.requestor.id:
+ raise Exception(
+ f"onsite contact {contact.id} not found or not associated with the requestor's organization"
+ )
+
def to_serializable_dict(self):
"""
Returns a dict representation of the document that is JSON serializable
@@ -53,6 +71,11 @@ def to_serializable_dict(self):
meal_request_dict = self.to_mongo().to_dict()
id = meal_request_dict.pop("_id", None)
meal_request_dict["id"] = str(id)
+ contacts = [contact.to_mongo().to_dict() for contact in self.onsite_staff]
+ for contact in contacts:
+ id = contact.pop("_id")
+ contact["id"] = id
+ meal_request_dict["onsite_staff"] = contacts
return meal_request_dict
meta = {"collection": "meal_requests"}
diff --git a/backend/app/models/onsite_contact.py b/backend/app/models/onsite_contact.py
new file mode 100644
index 00000000..a1671760
--- /dev/null
+++ b/backend/app/models/onsite_contact.py
@@ -0,0 +1,33 @@
+import mongoengine as mg
+
+from app.resources.onsite_contact_dto import OnsiteContactDTO
+
+
+class OnsiteContact(mg.Document):
+ organization_id = mg.ObjectIdField(required=True)
+ name = mg.StringField(required=True)
+ email = mg.StringField(required=True)
+ phone = mg.StringField(required=True)
+
+ def to_serializable_dict(self):
+ """
+ Returns a dict representation of the document that is JSON serializable
+ ObjectId must be converted to a string.
+ """
+
+ dict = self.to_mongo().to_dict()
+ id = dict.pop("_id", None)
+ dict["id"] = str(id)
+
+ # MongoDB ObjectId type is hard to work with graphQL so convert to a string
+ dict["organization_id"] = str(dict["organization_id"])
+
+ return dict
+
+ def to_dto(self) -> OnsiteContactDTO:
+ return OnsiteContactDTO(**self.to_serializable_dict()) # type: ignore #
+
+ def __str__(self):
+ return f"OnsiteContact({self.id}, {self.organization_id}, {self.name}, {self.email}, {self.phone})"
+
+ meta = {"collection": "onsite_contacts"}
diff --git a/backend/app/models/user.py b/backend/app/models/user.py
index 6f3b3da3..d5a3ec38 100644
--- a/backend/app/models/user.py
+++ b/backend/app/models/user.py
@@ -1,6 +1,6 @@
import mongoengine as mg
-from .user_info import UserInfo
+from app.models.user_info import UserInfo
class User(mg.Document):
diff --git a/backend/app/models/user_info.py b/backend/app/models/user_info.py
index 0aea8735..3520ba1b 100644
--- a/backend/app/models/user_info.py
+++ b/backend/app/models/user_info.py
@@ -44,7 +44,11 @@ class UserInfo(mg.EmbeddedDocument):
role = mg.StringField(choices=USERINFO_ROLES, required=True)
role_info = mg.EmbeddedDocumentField(RoleInfo)
primary_contact = mg.EmbeddedDocumentField(Contact, required=True)
- onsite_contacts = mg.EmbeddedDocumentListField(Contact, required=True)
+
+ # This information is given as part of the onboarding request
+ # When a user actually signs up, these contacts get turned into separate OnsiteContact documents
+ initial_onsite_contacts = mg.EmbeddedDocumentListField(Contact, required=False)
+
active = mg.BooleanField(default=True)
meta = {"allow_inheritance": True}
diff --git a/backend/app/resources/meal_request_dto.py b/backend/app/resources/meal_request_dto.py
index 3acb28de..0aed09f4 100644
--- a/backend/app/resources/meal_request_dto.py
+++ b/backend/app/resources/meal_request_dto.py
@@ -1,6 +1,6 @@
import datetime
-from ..models.meal_request import MEAL_STATUSES
+from ..models.meal_request import MEAL_STATUSES_STRINGS
from .validate_utils import (
validate_contact,
validate_donation_info,
@@ -49,15 +49,17 @@ def validate(self):
validate_user(self.requestor, "requestor", error_list)
- if type(self.status) is not str:
- error_list.append("The status supplied is not a string.")
-
- if self.status not in MEAL_STATUSES:
- error_list.append(
- "The status {self_status} is not one of {valid_statuses}".format(
- self_status=self.status, valid_statuses=", ".join(MEAL_STATUSES)
- )
- )
+ # if type(self.status) is not str:
+ # error_list.append("The status supplied is not a string.")
+
+ if self.status not in MEAL_STATUSES_STRINGS:
+ # TODO: revisit this
+ pass
+ # error_list.append(
+ # "The status {self_status} is not one of {valid_statuses}".format(
+ # self_status=self.status, valid_statuses=", ".join(MEAL_STATUSES)
+ # )
+ # )
if type(self.drop_off_datetime) is not datetime.datetime:
error_list.append(
diff --git a/backend/app/resources/onsite_contact_dto.py b/backend/app/resources/onsite_contact_dto.py
new file mode 100644
index 00000000..f43816db
--- /dev/null
+++ b/backend/app/resources/onsite_contact_dto.py
@@ -0,0 +1,31 @@
+class OnsiteContactDTO:
+ def __init__(
+ self, id: str, organization_id: str, name: str, email: str, phone: str
+ ):
+ self.id = id
+ self.organization_id = organization_id
+ self.name = name
+ self.email = email
+ self.phone = phone
+
+ error_list = self.validate()
+ if len(error_list) > 0:
+ error_message = "\n".join(error_list)
+ raise Exception(error_message)
+
+ def validate(self):
+ error_list = []
+
+ if type(self.id) is not str:
+ error_list.append("The id supplied is not a string.")
+
+ for field in [self.name, self.email, self.phone, self.organization_id]:
+ if type(field) is not str:
+ error_list.append(
+ f'The field "{field}" in onsite_contact {self.id} is not a string.'
+ )
+ elif field == "":
+ error_list.append(
+ f'The field "{field}" in onsite_contact {self.id} must not be an empty string.'
+ )
+ return error_list
diff --git a/backend/app/resources/validate_utils.py b/backend/app/resources/validate_utils.py
index aabf510b..91aa9d59 100644
--- a/backend/app/resources/validate_utils.py
+++ b/backend/app/resources/validate_utils.py
@@ -79,7 +79,7 @@ def validate_userinfo(userinfo, error_list):
"role",
"role_info",
"primary_contact",
- "onsite_contacts",
+ "initial_onsite_contacts",
"active",
]
if not isinstance(userinfo, dict):
@@ -94,7 +94,7 @@ def validate_userinfo(userinfo, error_list):
for key, val in userinfo.items():
if key == "primary_contact":
error_list = validate_contact(val, "info.primary_contact", error_list)
- elif key == "onsite_contacts":
+ elif key == "initial_onsite_contacts":
if not isinstance(val, list):
error_list.append("The info.onsite_contacts supplied is not a list.")
else:
diff --git a/backend/app/services/implementations/meal_request_service.py b/backend/app/services/implementations/meal_request_service.py
index 888b0b93..d623aaf3 100644
--- a/backend/app/services/implementations/meal_request_service.py
+++ b/backend/app/services/implementations/meal_request_service.py
@@ -1,4 +1,4 @@
-from ...models.user_info import Contact
+from typing import List
from ...models.meal_request import MealInfo, MealRequest
from ..interfaces.meal_request_service import IMealRequestService
from datetime import datetime
@@ -22,7 +22,7 @@ def create_meal_request(
drop_off_time,
drop_off_location,
delivery_instructions,
- onsite_staff,
+ onsite_staff: List[str],
):
try:
# Create MealRequests
@@ -32,6 +32,7 @@ def create_meal_request(
meal_requests = []
for request_date in request_dates:
+ # print("creaing!")
new_meal_request = MealRequest(
requestor=requestor,
meal_info=meal_info,
@@ -40,6 +41,7 @@ def create_meal_request(
delivery_instructions=delivery_instructions,
onsite_staff=onsite_staff,
)
+ new_meal_request.validate_onsite_contacts()
new_meal_request.save()
meal_requests.append(new_meal_request.to_serializable_dict())
except Exception as error:
@@ -49,7 +51,7 @@ def create_meal_request(
def update_meal_request(
self,
- requestor,
+ requestor_id,
meal_info,
drop_off_datetime,
drop_off_location,
@@ -58,13 +60,13 @@ def update_meal_request(
meal_request_id,
):
original_meal_request: MealRequest = MealRequest.objects(
- id=meal_request_id
+ id=meal_request_id, requestor=requestor_id
).first()
- if not original_meal_request:
- raise Exception(f"meal request with id {meal_request_id} not found")
- if requestor is not None:
- original_meal_request.requestor = requestor
+ if not original_meal_request:
+ raise Exception(
+ f"meal request with id {meal_request_id} by {requestor_id} not found"
+ )
if drop_off_datetime is not None:
original_meal_request.drop_off_datetime = drop_off_datetime
@@ -82,18 +84,18 @@ def update_meal_request(
original_meal_request.delivery_instructions = delivery_instructions
if onsite_staff is not None:
- original_meal_request.onsite_staff = [
- Contact(name=staff.name, phone=staff.phone, email=staff.email)
- for staff in onsite_staff
- ]
+ original_meal_request.onsite_staff = onsite_staff
requestor = original_meal_request.requestor
+
# Does validation,
meal_request_dto = self.convert_meal_request_to_dto(
original_meal_request, requestor
)
+ original_meal_request.validate_onsite_contacts()
original_meal_request.save()
+
return meal_request_dto
def commit_to_meal_request(
@@ -102,7 +104,7 @@ def commit_to_meal_request(
meal_request_ids: [str],
meal_description: str,
additional_info: str,
- ) -> [MealRequestDTO]:
+ ) -> List[MealRequestDTO]:
try:
donor = User.objects(id=donor_id).first()
if not donor:
@@ -169,11 +171,12 @@ def get_meal_requests_by_requestor_id(
requestor_id,
min_drop_off_date,
max_drop_off_date,
- status,
+ status: List[MealStatus],
offset,
limit,
sort_by_date_direction,
):
+ status_value_list = list(map(lambda stat: stat.value, status))
try:
sort_prefix = "+"
if sort_by_date_direction == SortDirection.DESCENDING:
@@ -182,8 +185,8 @@ def get_meal_requests_by_requestor_id(
requestor = User.objects(id=requestor_id).first()
requests = MealRequest.objects(
requestor=requestor,
- status__in=status,
- ).order_by(f"{sort_prefix}date_created")
+ status__in=status_value_list,
+ ).order_by(f"{sort_prefix}drop_off_datetime")
# Filter results by optional parameters.
# Since we want to filter these optionally (i.e. filter only if specified),
@@ -212,3 +215,11 @@ def get_meal_requests_by_requestor_id(
except Exception as error:
self.logger.error(str(error))
raise error
+
+ def get_meal_request_by_id(self, id: str) -> MealRequestDTO:
+ meal_request = MealRequest.objects(id=id).first()
+ meal_request_dto = self.convert_meal_request_to_dto(
+ meal_request, meal_request.requestor
+ )
+
+ return meal_request_dto
diff --git a/backend/app/services/implementations/onboarding_request_service.py b/backend/app/services/implementations/onboarding_request_service.py
index 56c32559..5fcc3764 100644
--- a/backend/app/services/implementations/onboarding_request_service.py
+++ b/backend/app/services/implementations/onboarding_request_service.py
@@ -36,10 +36,9 @@ def create_onboarding_request(self, userInfo: UserInfo):
role=userInfo.role,
role_info=userInfo.role_info,
primary_contact=userInfo.primary_contact,
- onsite_contacts=userInfo.onsite_contacts,
+ initial_onsite_contacts=userInfo.initial_onsite_contacts,
active=userInfo.active,
)
-
# Create OnboardingRequest object
new_onboarding_request = OnboardingRequest(
info=user_info,
@@ -112,7 +111,6 @@ def approve_onboarding_request(self, request_id):
referenced_onboarding_request.status = (
ONBOARDING_REQUEST_STATUS_APPROVED # approve the onboarding request
)
-
referenced_onboarding_request.save() # save the changes
recipient_email = referenced_onboarding_request.info.email
diff --git a/backend/app/services/implementations/onsite_contact_service.py b/backend/app/services/implementations/onsite_contact_service.py
new file mode 100644
index 00000000..dc981b4d
--- /dev/null
+++ b/backend/app/services/implementations/onsite_contact_service.py
@@ -0,0 +1,80 @@
+from typing import List, Optional
+
+from app.models.onsite_contact import OnsiteContact
+from app.resources.onsite_contact_dto import OnsiteContactDTO
+
+from ..interfaces.onsite_contact_service import IOnsiteContactService
+
+from ...models.user import User
+
+
+class OnsiteContactService(IOnsiteContactService):
+ def __init__(self, logger):
+ self.logger = logger
+
+ def get_onsite_contact_by_id(
+ self,
+ id: str,
+ ):
+ onsite_staff = OnsiteContact.objects(id=id).first()
+ if onsite_staff:
+ return onsite_staff.to_dto()
+ else:
+ return None
+
+ def get_onsite_contacts_for_user_by_id(
+ self,
+ user_id: str,
+ ) -> List[OnsiteContactDTO]:
+ onsite_staff = OnsiteContact.objects(organization_id=user_id).all()
+ return [staff.to_dto() for staff in onsite_staff]
+
+ def delete_onsite_contact_by_id(
+ self,
+ id: str,
+ ):
+ OnsiteContact.objects(id=id).delete()
+
+ def update_onsite_contact_by_id(
+ self,
+ id: str,
+ name: Optional[str],
+ email: Optional[str],
+ phone: Optional[str],
+ ) -> OnsiteContactDTO:
+ existing: OnsiteContact = OnsiteContact.objects(id=id).first()
+ if not existing:
+ raise Exception(f'onsite contact with id "{id}" not found')
+ if name is not None:
+ existing.name = name
+ if email is not None:
+ existing.email = email
+ if phone is not None:
+ existing.phone = phone
+ existing.save()
+ existing.to_serializable_dict()
+
+ return existing.to_dto()
+
+ def create_onsite_contact(
+ self, organization_id: str, name: str, email: str, phone: str
+ ) -> OnsiteContactDTO:
+ try:
+ # Check that the organization does exist
+ organization = User.objects(id=organization_id).first()
+ if not organization:
+ raise Exception(f'organization with id "{organization_id}" not found')
+
+ new_contact = OnsiteContact(
+ organization_id=organization_id,
+ name=name,
+ email=email,
+ phone=phone,
+ )
+ new_contact.save()
+
+ return new_contact.to_dto()
+
+ except Exception as error:
+ self.logger.error(str(error))
+ raise error
diff --git a/backend/app/services/implementations/user_service.py b/backend/app/services/implementations/user_service.py
index 39080d20..716955bd 100644
--- a/backend/app/services/implementations/user_service.py
+++ b/backend/app/services/implementations/user_service.py
@@ -1,4 +1,7 @@
import firebase_admin.auth
+from app.models.user_info import UserInfo
+
+from app.services.interfaces.onsite_contact_service import IOnsiteContactService
from ...models.onboarding_request import OnboardingRequest
from ..interfaces.user_service import IUserService
from ...models.user import User
@@ -12,7 +15,7 @@ class UserService(IUserService):
UserService implementation with user management methods
"""
- def __init__(self, logger):
+ def __init__(self, logger, onsite_contact_service: IOnsiteContactService):
"""
Create an instance of UserService
@@ -20,6 +23,7 @@ def __init__(self, logger):
:type logger: logger
"""
self.logger = logger
+ self.onsite_contact_service = onsite_contact_service
def get_user_by_id(self, user_id):
try:
@@ -173,13 +177,24 @@ def create_user(self, create_user_dto):
)
try:
+ user_info: UserInfo = (
+ OnboardingRequest.objects(id=create_user_dto.request_id)
+ .first()
+ .info
+ )
new_user: User = User(
auth_id=firebase_user.uid,
- info=OnboardingRequest.objects(id=create_user_dto.request_id)
- .first()
- .info,
+ info=user_info,
)
new_user.save()
+ for onsite_contact in user_info.initial_onsite_contacts:
+ self.onsite_contact_service.create_onsite_contact(
+ organization_id=new_user.id,
+ name=onsite_contact.name,
+ email=onsite_contact.email,
+ phone=onsite_contact.phone,
+ )
+
except Exception as mongo_error:
# rollback user creation in Firebase
try:
diff --git a/backend/app/services/interfaces/auth_service.py b/backend/app/services/interfaces/auth_service.py
index 1f0f3938..db2bab2d 100644
--- a/backend/app/services/interfaces/auth_service.py
+++ b/backend/app/services/interfaces/auth_service.py
@@ -1,5 +1,7 @@
from abc import ABC, abstractmethod
+from app.resources.auth_dto import AuthDTO
+
class IAuthService(ABC):
"""
@@ -7,7 +9,7 @@ class IAuthService(ABC):
"""
@abstractmethod
- def generate_token(self, email, password):
+ def generate_token(self, email, password) -> AuthDTO:
"""
Generate a short-lived JWT access token and a long-lived refresh token
when supplied user's email and password
diff --git a/backend/app/services/interfaces/meal_request_service.py b/backend/app/services/interfaces/meal_request_service.py
index 5e13e304..ccc74d1b 100644
--- a/backend/app/services/interfaces/meal_request_service.py
+++ b/backend/app/services/interfaces/meal_request_service.py
@@ -1,5 +1,5 @@
from abc import ABC, abstractmethod
-from typing import Union
+from typing import Union, List
from ...resources.meal_request_dto import MealRequestDTO
@@ -18,7 +18,7 @@ def create_meal_request(
drop_off_time,
drop_off_location,
delivery_instructions,
- onsite_staff,
+ onsite_staff: List[str],
):
"""Create a new MealRequest object and corresponding MealRequests
@@ -33,12 +33,12 @@ def create_meal_request(
@abstractmethod
def update_meal_request(
self,
- requestor,
+ requestor_id: str,
meal_info,
drop_off_datetime,
drop_off_location,
delivery_instructions,
- onsite_staff,
+ onsite_staff: List[str],
meal_request_id,
):
pass
@@ -47,10 +47,17 @@ def update_meal_request(
def commit_to_meal_request(
self,
donor_id: str,
- meal_request_ids: [str],
+ meal_request_ids: List[str],
meal_description: str,
additional_info: Union[str, None],
- ) -> [MealRequestDTO]:
+ ) -> List[MealRequestDTO]:
+ pass
+
+ @abstractmethod
+ def get_meal_request_by_id(
+ self,
+ id: str,
+ ) -> MealRequestDTO:
pass
@abstractmethod
diff --git a/backend/app/services/interfaces/onsite_contact_service.py b/backend/app/services/interfaces/onsite_contact_service.py
new file mode 100644
index 00000000..6656fe33
--- /dev/null
+++ b/backend/app/services/interfaces/onsite_contact_service.py
@@ -0,0 +1,51 @@
+from abc import ABC, abstractmethod
+from typing import Optional, List
+
+from ...resources.onsite_contact_dto import OnsiteContactDTO
+
+
+class IOnsiteContactService(ABC):
+ """
+ OnsiteContactService for handling requests relating to onsite contacts
+ """
+
+ @abstractmethod
+ def create_onsite_contact(
+ self,
+ organization_id: str,
+ name: str,
+ email: str,
+ phone: str,
+ ) -> OnsiteContactDTO:
+ pass
+
+ @abstractmethod
+ def update_onsite_contact_by_id(
+ self,
+ id: str,
+ name: Optional[str],
+ email: Optional[str],
+ phone: Optional[str],
+ ) -> OnsiteContactDTO:
+ pass
+
+ @abstractmethod
+ def delete_onsite_contact_by_id(
+ self,
+ id: str,
+ ):
+ pass
+
+ @abstractmethod
+ def get_onsite_contacts_for_user_by_id(
+ self,
+ user_id: str,
+ ) -> List[OnsiteContactDTO]:
+ pass
+
+ @abstractmethod
+ def get_onsite_contact_by_id(
+ self,
+ id: str,
+ ) -> OnsiteContactDTO:
+ pass
diff --git a/backend/app/utilities/location_to_coordinates.py b/backend/app/utilities/location_to_coordinates.py
index aab1c2ef..de83b9ab 100644
--- a/backend/app/utilities/location_to_coordinates.py
+++ b/backend/app/utilities/location_to_coordinates.py
@@ -1,18 +1,31 @@
+import os
+
import requests
GEOCODE_API_URL = "https://geocode.maps.co/search"
+GEOCODE_API_KEY = os.getenv("GEOCODING_API_KEY")
def getGeocodeFromAddress(organization_address):
+ if "PYTEST_CURRENT_TEST" in os.environ:
+ print("MOCKING LATITUDE IN TESTING")
+ return [-11.1, 11.1]
+
response = requests.get(
- '{base_url}?q="{address}"'.format(
- base_url=GEOCODE_API_URL, address=organization_address
+ '{base_url}?q="{address}"&api_key={api_key}'.format(
+ base_url=GEOCODE_API_URL,
+ address=organization_address,
+ api_key=GEOCODE_API_KEY,
)
)
+ try:
+ if response.status_code != 200:
+ raise Exception("Failed to get coordinates from Geocode API")
- response_json = response.json()
-
- if len(response_json) == 0:
- raise Exception("Failed to get coordinates from Geocode API")
-
- return [float(response_json[0]["lon"]), float(response_json[0]["lat"])]
+ response_json = response.json()
+ if len(response_json) == 0:
+ raise Exception("Failed to get coordinates from Geocode API")
+ return [float(response_json[0]["lon"]), float(response_json[0]["lat"])]
+ except Exception as e:
+ print("Failed when getting geoencoding from address!")
+ raise e
diff --git a/backend/mypy.ini b/backend/mypy.ini
new file mode 100644
index 00000000..21d459ba
--- /dev/null
+++ b/backend/mypy.ini
@@ -0,0 +1,6 @@
+[mypy]
+ignore_missing_imports = True
+exclude = (?x)(
+ .conftest.|
+ .mock_test_data.
+ )
\ No newline at end of file
diff --git a/backend/setup.cfg b/backend/setup.cfg
index 8dd399ab..8bbe463d 100644
--- a/backend/setup.cfg
+++ b/backend/setup.cfg
@@ -1,3 +1,4 @@
[flake8]
max-line-length = 88
-extend-ignore = E203
+extend-ignore = E203,E501,W503
+exclude = /home/runner/work/feeding-canadian-kids/feeding-canadian-kids/backend/typings/graphene/relay/mutation.pyi
diff --git a/backend/tests/graphql/conftest.py b/backend/tests/graphql/conftest.py
index 6d7ce7e0..2791bc56 100644
--- a/backend/tests/graphql/conftest.py
+++ b/backend/tests/graphql/conftest.py
@@ -2,6 +2,7 @@
from app.models.user import User
from app.models.onboarding_request import OnboardingRequest
from app.models.meal_request import MealRequest
+from app.models.onsite_contact import OnsiteContact
from tests.graphql.mock_test_data import (
MOCK_INFO1_SNAKE,
MOCK_INFO2_SNAKE,
@@ -22,7 +23,7 @@ def graphql_schema():
yield graphql_schema
-@pytest.fixture(scope="session", autouse=True)
+@pytest.fixture(scope="function", autouse=True)
def onboarding_request_setup():
onboarding_request_1 = OnboardingRequest(
info=MOCK_INFO1_SNAKE, status="Pending"
@@ -37,20 +38,32 @@ def onboarding_request_setup():
onboarding_request_2.delete()
-@pytest.fixture(scope="session", autouse=True)
+@pytest.fixture(scope="function", autouse=True)
def user_setup():
- user_1 = User(**MOCK_USER1_SNAKE).save()
- user_2 = User(**MOCK_USER2_SNAKE).save()
- user_3 = User(**MOCK_USER3_SNAKE).save()
+ users = []
+ for MOCK_USER in [MOCK_USER1_SNAKE, MOCK_USER2_SNAKE, MOCK_USER3_SNAKE]:
+ user = User(**MOCK_USER)
+ user.save()
- yield user_1, user_2, user_3
+ # onsite_contact_1 = OnsiteContact(**MOCK_ONSITE_CONTACT_1)
+ # onsite_contact_1.organization_id = user.id
+ # onsite_contact_1.save()
- user_1.delete()
- user_2.delete()
- user_3.delete()
+ # onsite_contact_2 = OnsiteContact(**MOCK_ONSITE_CONTACT_2)
+ # onsite_contact_2.organization_id = user.id
+ # onsite_contact_2.save()
+ # user.info.onsite_contacts.extend([onsite_contact_1.id, onsite_contact_2.id])
+ # user.save()
+ users.append(user)
-@pytest.fixture(scope="session", autouse=True)
+ yield users
+
+ for user in users:
+ user.delete()
+
+
+@pytest.fixture(scope="function", autouse=True)
def meal_request_setup(user_setup):
requestor, donor, _ = user_setup
meal_request = MealRequest(requestor=requestor, **MOCK_MEALREQUEST1_SNAKE).save()
@@ -60,3 +73,30 @@ def meal_request_setup(user_setup):
requestor.delete()
donor.delete()
meal_request.delete()
+
+
+@pytest.fixture(scope="function", autouse=True)
+def onsite_contact_setup(user_setup):
+ asp, donor, _ = user_setup
+ asp_onsite_contact = OnsiteContact(
+ name="Sample Contact",
+ email="sample@test.com",
+ phone="123-456-7890",
+ organization_id=asp.id,
+ ).save()
+ asp_onsite_contact2 = OnsiteContact(
+ name="Sample Contact 2",
+ email="sample2@test.com",
+ phone="123-456-7890",
+ organization_id=asp.id,
+ ).save()
+ donor_onsite_contact = OnsiteContact(
+ name="Sample Contact 2",
+ email="sample2@test.com",
+ phone="123-333-7890",
+ organization_id=donor.id,
+ ).save()
+
+ yield asp, donor, [asp_onsite_contact, asp_onsite_contact2], donor_onsite_contact
+ asp_onsite_contact.delete()
+ donor_onsite_contact.delete()
diff --git a/backend/tests/graphql/mock_test_data.py b/backend/tests/graphql/mock_test_data.py
index 33b1421b..c88b4fc9 100644
--- a/backend/tests/graphql/mock_test_data.py
+++ b/backend/tests/graphql/mock_test_data.py
@@ -1,9 +1,12 @@
+# NOTE: The coodinates have been mocked out in testing
MOCK_INFO1_SNAKE = {
"email": "test1@organization.com",
"organization_address": "255 King St N",
"organization_name": "Test1 Org",
"organization_desc": "Testing123",
- "organization_coordinates": [-80.52565465, 43.477876300000005],
+ "organization_coordinates": [-11.1, 11.1],
+ # Real Coordinates:
+ # "organization_coordinates": [-80.52565465, 43.477876300000005],
"role": "ASP",
"role_info": {
"asp_info": {
@@ -16,19 +19,29 @@
"phone": "123456",
"email": "jessie123@gmail.com",
},
- "onsite_contacts": [
- {"name": "abc", "phone": "123-456-7890", "email": "abc@uwblueprint.org"},
- {"name": "Jane Doe", "phone": "111-222-3333", "email": "example@domain.com"},
- ],
+ "initial_onsite_contacts": [],
"active": True,
}
+MOCK_ONSITE_CONTACT_1 = {
+ "name": "abc",
+ "phone": "123-456-7890",
+ "email": "abc@uwblueprint.org",
+}
+MOCK_ONSITE_CONTACT_2 = {
+ "name": "Jane Doe",
+ "phone": "111-222-3333",
+ "email": "example@domain.com",
+}
+
MOCK_INFO1_CAMEL = {
"email": "test1@organization.com",
"organizationAddress": "255 King St N",
"organizationName": "Test1 Org",
"organizationDesc": "Testing123",
- "organizationCoordinates": [-80.52565465, 43.477876300000005],
+ "organizationCoordinates": [-11.1, 11.1],
+ # Real Coordinates:
+ # "organizationCoordinates": [-80.52565465, 43.477876300000005],
"role": "ASP",
"roleInfo": {
"aspInfo": {
@@ -41,10 +54,7 @@
"phone": "123456",
"email": "jessie123@gmail.com",
},
- "onsiteContacts": [
- {"name": "abc", "phone": "123-456-7890", "email": "abc@uwblueprint.org"},
- {"name": "Jane Doe", "phone": "111-222-3333", "email": "example@domain.com"},
- ],
+ "initialOnsiteContacts": [],
"active": True,
}
@@ -53,7 +63,9 @@
"organization_address": "370 Highland Rd W",
"organization_name": "Test2 Org",
"organization_desc": "Testing123",
- "organization_coordinates": [-80.5118701, 43.4384664],
+ "organization_coordinates": [-11.1, 11.1],
+ # Real Coordinates:
+ # "organization_coordinates": [-80.5118701, 43.4384664],
"role": "Donor",
"role_info": {
"asp_info": None,
@@ -67,10 +79,11 @@
"phone": "98765",
"email": "goose@gmail.com",
},
- "onsite_contacts": [
- {"name": "def", "phone": "098-765-4321", "email": "def@uwblueprint.org"},
- {"name": "John Doe", "phone": "444-555-6666", "email": "elpmaxe@niamod.moc"},
- ],
+ "initial_onsite_contacts": [],
+ # "initial_onsite_contacts": [
+ # {"name": "def", "phone": "098-765-4321", "email": "def@uwblueprint.org"},
+ # {"name": "John Doe", "phone": "444-555-6666", "email": "elpmaxe@niamod.moc"},
+ # ],
"active": True,
}
@@ -79,7 +92,9 @@
"organizationAddress": "370 Highland Rd W",
"organizationName": "Test2 Org",
"organizationDesc": "Testing123",
- "organizationCoordinates": [-80.5118701, 43.4384664],
+ "organizationCoordinates": [-11.1, 11.1],
+ # Real Coordinates:
+ # "organizationCoordinates": [-80.5118701, 43.4384664],
"role": "Donor",
"roleInfo": {
"aspInfo": None,
@@ -93,10 +108,11 @@
"phone": "98765",
"email": "goose@gmail.com",
},
- "onsiteContacts": [
- {"name": "def", "phone": "098-765-4321", "email": "def@uwblueprint.org"},
- {"name": "John Doe", "phone": "444-555-6666", "email": "elpmaxe@niamod.moc"},
- ],
+ "initialOnsiteContacts": [],
+ # "initialOnsiteContacts": [
+ # {"name": "def", "phone": "098-765-4321", "email": "def@uwblueprint.org"},
+ # {"name": "John Doe", "phone": "444-555-6666", "email": "elpmaxe@niamod.moc"},
+ # ],
"active": True,
}
@@ -105,7 +121,9 @@
"organization_address": "170 University Ave W",
"organization_name": "Test3 Org",
"organization_desc": "Testing 123",
- "organization_coordinates": [-80.5373252901463, 43.472995850000004],
+ "organization_coordinates": [-11.1, 11.1],
+ # Real Coordinates:
+ # "organization_coordinates": [-80.5373252901463, 43.472995850000004],
"role": "Admin",
"role_info": None,
"primary_contact": {
@@ -113,10 +131,11 @@
"phone": "13579",
"email": "anon@gmail.com",
},
- "onsite_contacts": [
- {"name": "ghi", "phone": "135-792-4680", "email": "ghi@uwblueprint.org"},
- {"name": "Jack Doe", "phone": "777-888-999", "email": "com@domain.email"},
- ],
+ "initial_onsite_contacts": [],
+ # "initial_onsite_contacts": [
+ # {"name": "ghi", "phone": "135-792-4680", "email": "ghi@uwblueprint.org"},
+ # {"name": "Jack Doe", "phone": "777-888-999", "email": "com@domain.email"},
+ # ],
"active": False,
}
@@ -125,7 +144,9 @@
"organizationAddress": "170 University Ave W",
"organizationName": "Test3 Org",
"organizationDesc": "Testing 123",
- "organizationCoordinates": [-80.5373252901463, 43.472995850000004],
+ # Real Coordinates:
+ # "organizationCoordinates": [-80.5373252901463, 43.472995850000004],
+ "organizationCoordinates": [-11.1, 11.1],
"role": "Admin",
"roleInfo": None,
"primaryContact": {
@@ -133,10 +154,11 @@
"phone": "13579",
"email": "anon@gmail.com",
},
- "onsiteContacts": [
- {"name": "ghi", "phone": "135-792-4680", "email": "ghi@uwblueprint.org"},
- {"name": "Jack Doe", "phone": "777-888-999", "email": "com@domain.email"},
- ],
+ "initialOnsiteContacts": [],
+ # "initialOnsiteContacts": [
+ # {"name": "ghi", "phone": "135-792-4680", "email": "ghi@uwblueprint.org"},
+ # {"name": "Jack Doe", "phone": "777-888-999", "email": "com@domain.email"},
+ # ],
"active": False,
}
@@ -163,13 +185,6 @@
"portions": 10,
"dietary_restrictions": "Vegan",
},
- "onsite_staff": [
- {
- "name": "Test name",
- "email": "test@gmail.com",
- "phone": "1234567890",
- }
- ],
"date_created": "2023-03-31T00:00:00",
"date_updated": "2023-03-31T00:00:00",
"delivery_instructions": "Test instructions",
diff --git a/backend/tests/graphql/test_all_user_mutations.py b/backend/tests/graphql/test_all_user_mutations.py
index 4473b7b1..00a9ae73 100644
--- a/backend/tests/graphql/test_all_user_mutations.py
+++ b/backend/tests/graphql/test_all_user_mutations.py
@@ -30,18 +30,7 @@ def test_update_user_by_id(user_setup, mocker):
phone: "13579",
email: "anon@gmail.com",
}},
- onsiteContacts: [
- {{
- name: "ghi",
- phone: "135-792-4680",
- email: "ghi@uwblueprint.org"
- }},
- {{
- name: "Jack Doe",
- phone: "777-888-999",
- email: "com@domain.email"
- }},
- ],
+ initialOnsiteContacts: [],
active: false
}}
) {{
@@ -68,7 +57,7 @@ def test_update_user_by_id(user_setup, mocker):
phone
email
}}
- onsiteContacts {{
+ initialOnsiteContacts {{
name
phone
email
@@ -108,18 +97,7 @@ def test_update_user_by_id(user_setup, mocker):
phone: "123456",
email: "jessie123@gmail.com"
}},
- onsiteContacts: [
- {{
- name: "abc",
- phone: "123-456-7890",
- email: "abc@uwblueprint.org"
- }},
- {{
- name: "Jane Doe",
- phone: "111-222-3333",
- email: "example@domain.com"
- }}
- ],
+ initialOnsiteContacts: [],
active: true
}}
) {{
@@ -146,7 +124,7 @@ def test_update_user_by_id(user_setup, mocker):
phone
email
}}
- onsiteContacts {{
+ initialOnsiteContacts {{
name
phone
email
@@ -193,7 +171,7 @@ def test_number_of_kids_cant_be_set_negative(user_setup, mocker):
phone: "123456",
email: "jessie123@gmail.com"
}},
- onsiteContacts: [
+ initialOnsiteContacts: [
{{
name: "abc",
phone: "123-456-7890",
@@ -231,7 +209,7 @@ def test_number_of_kids_cant_be_set_negative(user_setup, mocker):
phone
email
}}
- onsiteContacts {{
+ initialOnsiteContacts {{
name
phone
email
@@ -282,7 +260,7 @@ def test_activate_user_by_id(user_setup, mocker):
phone
email
}}
- onsiteContacts {{
+ initialOnsiteContacts {{
name
phone
email
@@ -328,7 +306,7 @@ def test_deactivate_user_by_id(user_setup, mocker):
phone
email
}}
- onsiteContacts {{
+ initialOnsiteContacts {{
name
phone
email
@@ -370,7 +348,7 @@ def test_deactivate_user_by_id(user_setup, mocker):
phone
email
}}
- onsiteContacts {{
+ initialOnsiteContacts {{
name
phone
email
@@ -413,7 +391,7 @@ def test_deactivate_user_by_id(user_setup, mocker):
phone
email
}}
- onsiteContacts {{
+ initialOnsiteContacts {{
name
phone
email
diff --git a/backend/tests/graphql/test_all_user_queries.py b/backend/tests/graphql/test_all_user_queries.py
index 33edca9d..bbffceb5 100644
--- a/backend/tests/graphql/test_all_user_queries.py
+++ b/backend/tests/graphql/test_all_user_queries.py
@@ -33,7 +33,7 @@ def test_all_users(user_setup):
phone
email
}
- onsiteContacts {
+ initialOnsiteContacts {
name
phone
email
@@ -45,7 +45,6 @@ def test_all_users(user_setup):
)
assert len(executed.data["getAllUsers"]) == 3
- print(executed.data["getAllUsers"])
user_result1 = executed.data["getAllUsers"][0]
assert user_result1["id"] == str(user_1.id)
assert user_result1["info"] == MOCK_INFO1_CAMEL
@@ -84,7 +83,7 @@ def test_all_users_filter_by_role(user_setup):
phone
email
}
- onsiteContacts {
+ initialOnsiteContacts {
name
phone
email
@@ -127,7 +126,7 @@ def test_get_user_by_id(user_setup):
phone
email
}}
- onsiteContacts {{
+ initialOnsiteContacts {{
name
phone
email
@@ -171,7 +170,7 @@ def test_get_user_by_id(user_setup):
# phone
# email
# }}
-# onsiteContacts {{
+# initialOnsiteContacts {{
# name
# phone
# email
diff --git a/backend/tests/graphql/test_meal_request.py b/backend/tests/graphql/test_meal_request.py
index 2acf9e75..1d9bd53c 100644
--- a/backend/tests/graphql/test_meal_request.py
+++ b/backend/tests/graphql/test_meal_request.py
@@ -8,8 +8,21 @@
"""
-def test_create_meal_request(meal_request_setup):
- requestor, _, _ = meal_request_setup
+def compare_returned_onsite_contact(result, onsite_contact):
+ assert result["id"] == str(onsite_contact.id)
+ assert result["name"] == onsite_contact.name
+ assert result["email"] == onsite_contact.email
+ assert result["phone"] == onsite_contact.phone
+ assert result["organizationId"] == str(onsite_contact.organization_id)
+
+
+def test_create_meal_request(meal_request_setup, onsite_contact_setup):
+ (
+ asp,
+ donor,
+ [asp_onsite_contact, asp_onsite_contact2],
+ donor_onsite_contact,
+ ) = onsite_contact_setup
mutation = f"""
mutation testCreateMealRequest {{
@@ -21,19 +34,8 @@ def test_create_meal_request(meal_request_setup):
portions: 40,
dietaryRestrictions: "7 gluten free, 7 no beef",
}},
- onsiteStaff: [
- {{
- name: "John Doe",
- email: "john.doe@example.com",
- phone: "+1234567890"
- }},
- {{
- name: "Jane Smith",
- email: "jane.smith@example.com",
- phone: "+9876543210"
- }}
- ],
- requestorId: "{str(requestor.id)}",
+ onsiteStaff: ["{asp_onsite_contact.id}", "{asp_onsite_contact2.id}"],
+ requestorId: "{str(asp.id)}",
requestDates: [
"2023-06-01",
"2023-06-02",
@@ -48,15 +50,21 @@ def test_create_meal_request(meal_request_setup):
portions
dietaryRestrictions
}}
+ onsiteStaff{{
+ id
+ name
+ email
+ phone
+ organizationId
+ }}
}}
}}
}}
"""
result = graphql_schema.execute(mutation)
-
assert result.errors is None
- assert result.data["createMealRequest"]["mealRequests"][0]["status"] == "Open"
+ assert result.data["createMealRequest"]["mealRequests"][0]["status"] == "OPEN"
assert (
result.data["createMealRequest"]["mealRequests"][0]["mealInfo"]["portions"]
== 40
@@ -76,11 +84,72 @@ def test_create_meal_request(meal_request_setup):
== "2023-06-02T16:30:00+00:00"
)
+ created_onsite_contacts = result.data["createMealRequest"]["mealRequests"][0][
+ "onsiteStaff"
+ ]
+ expected_onsite_contacts = (
+ [asp_onsite_contact, asp_onsite_contact2]
+ if created_onsite_contacts[0]["id"] == str(asp_onsite_contact.id)
+ else [asp_onsite_contact2, asp_onsite_contact]
+ )
+ for created, expected in zip(created_onsite_contacts, expected_onsite_contacts):
+ assert created["id"] == str(expected.id)
+ assert created["name"] == str(expected.name)
+ assert created["email"] == str(expected.email)
+ assert created["phone"] == str(expected.phone)
+ assert created["organizationId"] == str(expected.organization_id)
+
# Delete the created meal requests
for meal_request in result.data["createMealRequest"]["mealRequests"]:
MealRequest.objects(id=meal_request["id"]).delete()
+def test_create_meal_request_fails_invalid_onsite_contact(
+ meal_request_setup, onsite_contact_setup
+):
+ asp, donor, asp_onsite_contact, donor_onsite_contact = onsite_contact_setup
+
+ counter_before = MealRequest.objects().count()
+ mutation = f"""
+ mutation testCreateMealRequest {{
+ createMealRequest(
+ deliveryInstructions: "Leave at front door",
+ dropOffLocation: "123 Main Street",
+ dropOffTime: "16:30:00Z",
+ mealInfo: {{
+ portions: 40,
+ dietaryRestrictions: "7 gluten free, 7 no beef",
+ }},
+ onsiteStaff: ["{asp_onsite_contact}, fdsfdja"],
+ requestorId: "{str(asp.id)}",
+ requestDates: [
+ "2023-06-01",
+ "2023-06-02",
+ ],
+ )
+ {{
+ mealRequests {{
+ status
+ id
+ dropOffDatetime
+ mealInfo {{
+ portions
+ dietaryRestrictions
+ }}
+ onsiteStaff{{
+ id
+ }}
+ }}
+ }}
+ }}
+ """
+
+ result = graphql_schema.execute(mutation)
+ assert result.errors is not None
+ counter_after = MealRequest.objects().count()
+ assert counter_before == counter_after
+
+
# Happy path: A donor commits to fulfilling one meal request
def test_commit_to_meal_request(meal_request_setup):
_, donor, meal_request = meal_request_setup
@@ -88,7 +157,7 @@ def test_commit_to_meal_request(meal_request_setup):
mutation = f"""
mutation testCommitToMealRequest {{
commitToMealRequest(
- requester: "{str(donor.id)}",
+ requestor: "{str(donor.id)}",
mealRequestIds: ["{str(meal_request.id)}"],
mealDescription: "Pizza",
additionalInfo: "No nuts"
@@ -132,10 +201,7 @@ def test_commit_to_meal_request(meal_request_setup):
assert result.errors is None
# Verify that the meal request's status was updated
- assert (
- result.data["commitToMealRequest"]["mealRequests"][0]["status"]
- == MealStatus.UPCOMING.value
- )
+ assert result.data["commitToMealRequest"]["mealRequests"][0]["status"] == "UPCOMING"
# Verify that the meal request's donationInfo was populated correctly
assert result.data["commitToMealRequest"]["mealRequests"][0]["donationInfo"][
@@ -165,11 +231,12 @@ def test_commit_to_meal_request_fails_for_non_donor(meal_request_setup):
for role in INVALID_USERINFO_ROLES:
donor.info.role = role
+ donor.save()
mutation = f"""
mutation testCommitToMealRequest {{
commitToMealRequest(
- requester: "{str(donor.id)}",
+ requestor: "{str(donor.id)}",
mealRequestIds: ["{str(meal_request.id)}"],
mealDescription: "Pizza",
additionalInfo: "No nuts"
@@ -200,11 +267,12 @@ def test_commit_to_meal_request_fails_if_not_open(meal_request_setup):
for meal_status in INVALID_MEAL_STATUSES:
meal_request.status = meal_status
+ meal_request.save()
mutation = f"""
mutation testCommitToMealRequest {{
commitToMealRequest(
- requester: "{str(donor.id)}",
+ requestor: "{str(donor.id)}",
mealRequestIds: ["{str(meal_request.id)}"],
mealDescription: "Pizza",
additionalInfo: "No nuts"
@@ -221,9 +289,13 @@ def test_commit_to_meal_request_fails_if_not_open(meal_request_setup):
assert result.errors is not None
-def test_update_meal_request(meal_request_setup):
+def test_update_meal_request(onsite_contact_setup, meal_request_setup):
+ requestor, _, asp_onsite_contacts, donor_onsite_contact = onsite_contact_setup
_, _, meal_request = meal_request_setup
+ onsite_contact1 = asp_onsite_contacts[0]
+ onsite_contact2 = asp_onsite_contacts[1]
+
updatedDateTime = "2023-10-31T16:45:00+00:00"
updatedDeliveryInstructions = "Updated delivery instructions"
updatedDropOffLocation = "Updated drop off location"
@@ -231,13 +303,11 @@ def test_update_meal_request(meal_request_setup):
"portions": 11,
"dietaryRestrictions": "No nuts",
}
- updatedOnsiteStaff = [
- {"name": "test", "email": "test@test.com", "phone": "604-441-1171"}
- ]
mutation = f"""
mutation testUpdateMealRequest{{
updateMealRequest(
+ requestorId:"{str(requestor.id)}",
mealRequestId:"{meal_request.id}",
deliveryInstructions:"{updatedDeliveryInstructions}",
dropOffDatetime: "{updatedDateTime}",
@@ -246,11 +316,7 @@ def test_update_meal_request(meal_request_setup):
portions: {updatedMealInfo["portions"]},
dietaryRestrictions: "{updatedMealInfo["dietaryRestrictions"]}",
}},
- onsiteStaff:[{{
- name: "{updatedOnsiteStaff[0]["name"]}",
- email: "{updatedOnsiteStaff[0]["email"]}",
- phone: "{updatedOnsiteStaff[0]["phone"]}"
- }}]
+ onsiteStaff: ["{onsite_contact1.id}","{onsite_contact2.id}"]
)
{{
mealRequest{{
@@ -263,9 +329,11 @@ def test_update_meal_request(meal_request_setup):
dietaryRestrictions
}}
onsiteStaff{{
+ id
name
email
phone
+ organizationId
}}
donationInfo{{
donor{{
@@ -284,11 +352,13 @@ def test_update_meal_request(meal_request_setup):
assert result.errors is None
updatedMealRequest = result.data["updateMealRequest"]["mealRequest"]
-
assert updatedMealRequest["dropOffLocation"] == updatedDropOffLocation
assert updatedMealRequest["deliveryInstructions"] == updatedDeliveryInstructions
assert updatedMealRequest["mealInfo"] == updatedMealInfo
- assert updatedMealRequest["onsiteStaff"] == updatedOnsiteStaff
+ returned_onsite_contacts = updatedMealRequest["onsiteStaff"]
+ compare_returned_onsite_contact(returned_onsite_contacts[0], onsite_contact1)
+ compare_returned_onsite_contact(returned_onsite_contacts[1], onsite_contact2)
+
assert updatedMealRequest["dropOffDatetime"] == updatedDateTime
diff --git a/backend/tests/graphql/test_onboarding_request.py b/backend/tests/graphql/test_onboarding_request.py
index acf525f4..d2815475 100644
--- a/backend/tests/graphql/test_onboarding_request.py
+++ b/backend/tests/graphql/test_onboarding_request.py
@@ -22,18 +22,7 @@ def test_create_onboarding_request():
phone: "13579",
email: "anon@gmail.com",
},
- onsiteContacts: [
- {
- name: "ghi",
- phone: "135-792-4680",
- email: "ghi@uwblueprint.org"
- },
- {
- name: "Jack Doe",
- phone: "777-888-999",
- email: "com@domain.email"
- },
- ],
+ initialOnsiteContacts: [],
active: false
}
) {
@@ -60,7 +49,7 @@ def test_create_onboarding_request():
phone
email
}
- onsiteContacts {
+ initialOnsiteContacts {
name
phone
email
@@ -104,18 +93,7 @@ def test_create_onboarding_request_with_existing_email_errors():
phone: "123456",
email: "jessie123@gmail.com"
}},
- onsiteContacts: [
- {{
- name: "abc",
- phone: "123-456-7890",
- email: "abc@uwblueprint.org"
- }},
- {{
- name: "Jane Doe",
- phone: "111-222-3333",
- email: "example@domain.com"
- }}
- ],
+ initialOnsiteContacts: [],
active: true
}}
) {{
@@ -142,7 +120,7 @@ def test_create_onboarding_request_with_existing_email_errors():
phone
email
}}
- onsiteContacts {{
+ initialOnsiteContacts {{
name
phone
email
@@ -187,7 +165,7 @@ def test_get_all_requests(onboarding_request_setup):
phone
email
}
- onsiteContacts {
+ initialOnsiteContacts {
name
phone
email
@@ -239,7 +217,7 @@ def test_filter_requests_by_role(onboarding_request_setup):
phone
email
}
- onsiteContacts {
+ initialOnsiteContacts {
name
phone
email
@@ -286,7 +264,7 @@ def test_filter_requests_by_status(onboarding_request_setup):
phone
email
}
- onsiteContacts {
+ initialOnsiteContacts {
name
phone
email
@@ -333,7 +311,7 @@ def test_get_requests_by_id(onboarding_request_setup):
phone
email
}}
- onsiteContacts {{
+ initialOnsiteContacts {{
name
phone
email
diff --git a/backend/tests/graphql/test_onsite_contact.py b/backend/tests/graphql/test_onsite_contact.py
new file mode 100644
index 00000000..a9b69e35
--- /dev/null
+++ b/backend/tests/graphql/test_onsite_contact.py
@@ -0,0 +1,168 @@
+from app.graphql import schema as graphql_schema
+from app.models.onsite_contact import OnsiteContact
+
+"""
+Tests for ONsite contact and query/mutation logic
+Running graphql_schema.execute(...) also tests the service logic
+"""
+
+
+def compare_returned_onsite_contact(result, onsite_contact):
+ assert result["id"] == str(onsite_contact.id)
+ assert result["name"] == onsite_contact.name
+ assert result["email"] == onsite_contact.email
+ assert result["phone"] == onsite_contact.phone
+ assert result["organizationId"] == str(onsite_contact.organization_id)
+
+
+def test_create_onsite_contact(onsite_contact_setup):
+ asp, donor, onsite_contacts, _ = onsite_contact_setup
+
+ mutation = f"""
+ mutation c{{
+ createOnsiteContact(
+ email: "bob@test.com",
+ name: "Bob Cat",
+ organizationId: "{donor.id}",
+ phone: "604-433-1111",
+ requestorId: "{donor.id}"
+ ){{
+ onsiteContact{{
+ id
+ name
+ email
+ phone
+ organizationId
+ }}
+ }}
+ }}
+ """
+ result = graphql_schema.execute(mutation)
+ assert result.errors is None
+ return_result_contact = result.data["createOnsiteContact"]["onsiteContact"]
+ db_result = OnsiteContact.objects(
+ organization_id=donor.id, id=return_result_contact["id"]
+ ).first()
+
+ for contact in [return_result_contact, db_result]:
+ assert contact["name"] == "Bob Cat"
+ assert contact["email"] == "bob@test.com"
+ assert contact["phone"] == "604-433-1111"
+
+ assert return_result_contact["organizationId"] == str(donor.id)
+ assert db_result.organization_id == donor.id
+
+
+def test_update_onsite_contact(onsite_contact_setup):
+ asp, donor, asp_onsite_contacts, donor_onsite_contact = onsite_contact_setup
+
+ # Test for the update mutation
+ mutation = f"""
+ mutation u{{
+ updateOnsiteContact(
+ id: "{donor_onsite_contact.id}",
+ name: "Updated Bob Cat",
+ email: "updated_bob@test.com",
+ phone: "604-433-2222",
+ requestorId: "{donor.id}"
+ ){{
+ onsiteContact{{
+ id
+ name
+ email
+ phone
+ }}
+ }}
+ }}
+ """
+ result = graphql_schema.execute(mutation)
+ assert result.errors is None
+ updated_result_contact = result.data["updateOnsiteContact"]["onsiteContact"]
+ updated_db_result = OnsiteContact.objects(id=donor_onsite_contact["id"]).first()
+
+ for contact in [updated_result_contact, updated_db_result]:
+ assert contact["name"] == "Updated Bob Cat"
+ assert contact["email"] == "updated_bob@test.com"
+ assert contact["phone"] == "604-433-2222"
+
+
+def test_delete_onsite_contact(onsite_contact_setup):
+ asp, donor, onsite_contacts, _ = onsite_contact_setup
+ onsite_contact = onsite_contacts[0]
+
+ # Test for the delete mutation
+ mutation = f"""
+ mutation d{{
+ deleteOnsiteContact(
+ id: "{onsite_contact.id}",
+ requestorId: "{asp.id}"
+ ){{
+ success
+ }}
+ }}
+ """
+ result = graphql_schema.execute(mutation)
+ assert result.errors is None
+ deleted_db_result = OnsiteContact.objects(id=onsite_contact["id"]).first()
+
+ assert deleted_db_result is None
+
+
+def test_get_onsite_contacts_for_user_by_id(onsite_contact_setup):
+ asp, donor, onsite_contacts, _ = onsite_contact_setup
+ onsite_contact = onsite_contacts[0]
+
+ # asp = User.objects(id=asp.id).get()
+ # asp.info.onsite_contacts = []
+ # asp.save()
+
+ # Test for the get_onsite_contact_for_user_by_id query
+ query = f"""
+ query q{{
+ getOnsiteContactForUserById(
+ userId: "{asp.id}"
+ ){{
+ id
+ name
+ email
+ phone
+ }}
+ }}
+ """
+ result = graphql_schema.execute(query)
+ assert result.errors is None
+ result = result.data["getOnsiteContactForUserById"][0]
+
+ assert result["id"] == str(onsite_contact.id)
+ assert result["name"] == onsite_contact.name
+ assert result["email"] == onsite_contact.email
+ assert result["phone"] == onsite_contact.phone
+
+
+def test_get_onsite_contact_by_id(onsite_contact_setup):
+ asp, donor, onsite_contacts, _ = onsite_contact_setup
+ onsite_contact = onsite_contacts[0]
+
+ # Test for the get_onsite_contact_by_id query
+ query = f"""
+ query q{{
+ getOnsiteContactById(
+ id: "{onsite_contact.id}"
+ ){{
+ id
+ name
+ email
+ phone
+ organizationId
+ }}
+ }}
+ """
+ result = graphql_schema.execute(query)
+ assert result.errors is None
+ result = result.data["getOnsiteContactById"]
+
+ assert result["id"] == str(onsite_contact.id)
+ assert result["name"] == onsite_contact.name
+ assert result["email"] == onsite_contact.email
+ assert result["phone"] == onsite_contact.phone
+ assert result["organizationId"] == str(onsite_contact.organization_id)
diff --git a/backend/tests/unit/test_models.py b/backend/tests/unit/test_models.py
index 51fd9315..cf7c0b83 100644
--- a/backend/tests/unit/test_models.py
+++ b/backend/tests/unit/test_models.py
@@ -27,7 +27,7 @@
"phone": "123-456-7890",
"email": "ansonjwhe@gmail.com",
},
- "onsite_contacts": [
+ "initial_onsite_contacts": [
{"name": "Abu", "phone": "123-456-7890", "email": "abu@uwblueprint.org"},
{"name": "Jane Doe", "phone": "111-222-3333", "email": "example@domain.com"},
],
@@ -81,20 +81,4 @@ def test_create_onboarding_request():
onboarding_request.info.primary_contact.email
== test_user_info["primary_contact"]["email"]
)
- assert len(onboarding_request.info.onsite_contacts) == len(
- test_user_info["onsite_contacts"]
- )
- for i in range(len(test_user_info["onsite_contacts"])):
- assert (
- onboarding_request.info.onsite_contacts[i].name
- == test_user_info["onsite_contacts"][i]["name"]
- )
- assert (
- onboarding_request.info.onsite_contacts[i].phone
- == test_user_info["onsite_contacts"][i]["phone"]
- )
- assert (
- onboarding_request.info.onsite_contacts[i].email
- == test_user_info["onsite_contacts"][i]["email"]
- )
assert onboarding_request.info.active == test_user_info["active"]
diff --git a/backend/typings/graphene/__init__.pyi b/backend/typings/graphene/__init__.pyi
new file mode 100644
index 00000000..f939f2f5
--- /dev/null
+++ b/backend/typings/graphene/__init__.pyi
@@ -0,0 +1,87 @@
+from .relay import (
+ ClientIDMutation as ClientIDMutation,
+ Connection as Connection,
+ ConnectionField as ConnectionField,
+ GlobalID as GlobalID,
+ Node as Node,
+ PageInfo as PageInfo,
+ is_node as is_node,
+)
+from .types import (
+ Argument as Argument,
+ Base64 as Base64,
+ BigInt as BigInt,
+ Boolean as Boolean,
+ Context as Context,
+ Date as Date,
+ DateTime as DateTime,
+ Decimal as Decimal,
+ Dynamic as Dynamic,
+ Enum as Enum,
+ Field as Field,
+ Float as Float,
+ ID as ID,
+ InputField as InputField,
+ InputObjectType as InputObjectType,
+ Int as Int,
+ Interface as Interface,
+ JSONString as JSONString,
+ List as List,
+ Mutation as Mutation,
+ NonNull as NonNull,
+ ObjectType as ObjectType,
+ ResolveInfo as ResolveInfo,
+ Scalar as Scalar,
+ Schema as Schema,
+ String as String,
+ Time as Time,
+ UUID as UUID,
+ Union as Union,
+)
+from .utils.module_loading import lazy_import as lazy_import
+from .utils.resolve_only_args import resolve_only_args as resolve_only_args
+from _typeshed import Incomplete
+
+__all__ = [
+ "__version__",
+ "Argument",
+ "Base64",
+ "BigInt",
+ "Boolean",
+ "ClientIDMutation",
+ "Connection",
+ "ConnectionField",
+ "Context",
+ "Date",
+ "DateTime",
+ "Decimal",
+ "Dynamic",
+ "Enum",
+ "Field",
+ "Float",
+ "GlobalID",
+ "ID",
+ "InputField",
+ "InputObjectType",
+ "Int",
+ "Interface",
+ "JSONString",
+ "List",
+ "Mutation",
+ "Node",
+ "NonNull",
+ "ObjectType",
+ "PageInfo",
+ "ResolveInfo",
+ "Scalar",
+ "Schema",
+ "String",
+ "Time",
+ "UUID",
+ "Union",
+ "is_node",
+ "lazy_import",
+ "resolve_only_args",
+]
+
+__version__: Incomplete
diff --git a/backend/typings/graphene/pyutils/__init__.pyi b/backend/typings/graphene/pyutils/__init__.pyi
new file mode 100644
index 00000000..e69de29b
diff --git a/backend/typings/graphene/pyutils/dataclasses.pyi b/backend/typings/graphene/pyutils/dataclasses.pyi
new file mode 100644
index 00000000..8e789d8f
--- /dev/null
+++ b/backend/typings/graphene/pyutils/dataclasses.pyi
@@ -0,0 +1,94 @@
+from _typeshed import Incomplete
+
+__all__ = [
+ "dataclass",
+ "field",
+ "Field",
+ "FrozenInstanceError",
+ "InitVar",
+ "MISSING",
+ "fields",
+ "asdict",
+ "astuple",
+ "make_dataclass",
+ "replace",
+ "is_dataclass",
+]
+
+class FrozenInstanceError(AttributeError): ...
+class _HAS_DEFAULT_FACTORY_CLASS: ...
+class _MISSING_TYPE: ...
+
+MISSING: Incomplete
+
+class _FIELD_BASE:
+ name: Incomplete
+ def __init__(self, name) -> None: ...
+
+class _InitVarMeta(type):
+ def __getitem__(self, params): ...
+
+class InitVar(metaclass=_InitVarMeta): ...
+
+class Field:
+ name: Incomplete
+ type: Incomplete
+ default: Incomplete
+ default_factory: Incomplete
+ init: Incomplete
+ repr: Incomplete
+ hash: Incomplete
+ compare: Incomplete
+ metadata: Incomplete
+ def __init__(
+ self, default, default_factory, init, repr, hash, compare, metadata
+ ) -> None: ...
+ def __set_name__(self, owner, name) -> None: ...
+
+class _DataclassParams:
+ init: Incomplete
+ repr: Incomplete
+ eq: Incomplete
+ order: Incomplete
+ unsafe_hash: Incomplete
+ frozen: Incomplete
+ def __init__(self, init, repr, eq, order, unsafe_hash, frozen) -> None: ...
+
+def field(
+ *,
+ default=...,
+ default_factory=...,
+ init: bool = True,
+ repr: bool = True,
+ hash: Incomplete | None = None,
+ compare: bool = True,
+ metadata: Incomplete | None = None
+): ...
+def dataclass(
+ _cls: Incomplete | None = None,
+ *,
+ init: bool = True,
+ repr: bool = True,
+ eq: bool = True,
+ order: bool = False,
+ unsafe_hash: bool = False,
+ frozen: bool = False
+): ...
+def fields(class_or_instance): ...
+def is_dataclass(obj): ...
+def asdict(obj, *, dict_factory=...): ...
+def astuple(obj, *, tuple_factory=...): ...
+def make_dataclass(
+ cls_name,
+ fields,
+ *,
+ bases=(),
+ namespace: Incomplete | None = None,
+ init: bool = True,
+ repr: bool = True,
+ eq: bool = True,
+ order: bool = False,
+ unsafe_hash: bool = False,
+ frozen: bool = False
+): ...
+def replace(obj, **changes): ...
diff --git a/backend/typings/graphene/pyutils/version.pyi b/backend/typings/graphene/pyutils/version.pyi
new file mode 100644
index 00000000..ba28483b
--- /dev/null
+++ b/backend/typings/graphene/pyutils/version.pyi
@@ -0,0 +1,7 @@
+from _typeshed import Incomplete
+
+def get_version(version: Incomplete | None = None): ...
+def get_main_version(version: Incomplete | None = None): ...
+def get_complete_version(version: Incomplete | None = None): ...
+def get_docs_version(version: Incomplete | None = None): ...
+def get_git_changeset(): ...
diff --git a/backend/typings/graphene/relay/__init__.pyi b/backend/typings/graphene/relay/__init__.pyi
new file mode 100644
index 00000000..ed99ded3
--- /dev/null
+++ b/backend/typings/graphene/relay/__init__.pyi
@@ -0,0 +1,17 @@
+from .connection import (
+ Connection as Connection,
+ ConnectionField as ConnectionField,
+ PageInfo as PageInfo,
+)
+from .mutation import ClientIDMutation as ClientIDMutation
+from .node import GlobalID as GlobalID, Node as Node, is_node as is_node
+
+__all__ = [
+ "Node",
+ "is_node",
+ "GlobalID",
+ "ClientIDMutation",
+ "Connection",
+ "ConnectionField",
+ "PageInfo",
+]
diff --git a/backend/typings/graphene/relay/connection.pyi b/backend/typings/graphene/relay/connection.pyi
new file mode 100644
index 00000000..1f615d1d
--- /dev/null
+++ b/backend/typings/graphene/relay/connection.pyi
@@ -0,0 +1,54 @@
+from ..types import (
+ Boolean as Boolean,
+ Enum as Enum,
+ Int as Int,
+ Interface as Interface,
+ List as List,
+ NonNull as NonNull,
+ Scalar as Scalar,
+ String as String,
+ Union as Union,
+)
+from ..types.field import Field as Field
+from ..types.objecttype import (
+ ObjectType as ObjectType,
+ ObjectTypeOptions as ObjectTypeOptions,
+)
+from ..utils.thenables import maybe_thenable as maybe_thenable
+from .node import is_node as is_node
+from _typeshed import Incomplete
+
+class PageInfo(ObjectType):
+ class Meta:
+ description: str
+ has_next_page: Incomplete
+ has_previous_page: Incomplete
+ start_cursor: Incomplete
+ end_cursor: Incomplete
+
+def page_info_adapter(startCursor, endCursor, hasPreviousPage, hasNextPage): ...
+
+class ConnectionOptions(ObjectTypeOptions):
+ node: Incomplete
+
+class Connection(ObjectType):
+ class Meta:
+ abstract: bool
+ @classmethod
+ def __init_subclass_with_meta__(
+ cls, node: Incomplete | None = None, name: Incomplete | None = None, **options
+ ): ...
+
+def connection_adapter(cls, edges, pageInfo): ...
+
+class IterableConnectionField(Field):
+ def __init__(self, type_, *args, **kwargs) -> None: ...
+ @property
+ def type(self): ...
+ @classmethod
+ def resolve_connection(cls, connection_type, args, resolved): ...
+ @classmethod
+ def connection_resolver(cls, resolver, connection_type, root, info, **args): ...
+ def wrap_resolve(self, parent_resolver): ...
+
+ConnectionField = IterableConnectionField
diff --git a/backend/typings/graphene/relay/mutation.pyi b/backend/typings/graphene/relay/mutation.pyi
new file mode 100644
index 00000000..7fd7cd52
--- /dev/null
+++ b/backend/typings/graphene/relay/mutation.pyi
@@ -0,0 +1,19 @@
+from ..types import Field as Field, InputObjectType as InputObjectType, String as String
+from ..types.mutation import Mutation as Mutation
+from ..utils.thenables import maybe_thenable as maybe_thenable
+from _typeshed import Incomplete
+
+class ClientIDMutation(Mutation):
+ class Meta:
+ abstract: bool
+ @classmethod
+ def __init_subclass_with_meta__(
+ cls,
+ output: Incomplete | None = None,
+ input_fields: Incomplete | None = None,
+ arguments: Incomplete | None = None,
+ name: Incomplete | None = None,
+ **options
+ ) -> None: ...
+ @classmethod
+ def mutate(cls, root, info, input): ...
diff --git a/backend/typings/graphene/relay/node.pyi b/backend/typings/graphene/relay/node.pyi
new file mode 100644
index 00000000..cb747c6b
--- /dev/null
+++ b/backend/typings/graphene/relay/node.pyi
@@ -0,0 +1,59 @@
+from ..types import (
+ Field as Field,
+ ID as ID,
+ Interface as Interface,
+ ObjectType as ObjectType,
+)
+from ..types.interface import InterfaceOptions as InterfaceOptions
+from ..types.utils import get_type as get_type
+from _typeshed import Incomplete
+
+def is_node(objecttype): ...
+
+class GlobalID(Field):
+ node: Incomplete
+ parent_type_name: Incomplete
+ def __init__(
+ self,
+ node: Incomplete | None = None,
+ parent_type: Incomplete | None = None,
+ required: bool = True,
+ *args,
+ **kwargs
+ ) -> None: ...
+ @staticmethod
+ def id_resolver(
+ parent_resolver,
+ node,
+ root,
+ info,
+ parent_type_name: Incomplete | None = None,
+ **args
+ ): ...
+ def wrap_resolve(self, parent_resolver): ...
+
+class NodeField(Field):
+ node_type: Incomplete
+ field_type: Incomplete
+ def __init__(self, node, type_: bool = False, **kwargs) -> None: ...
+ def wrap_resolve(self, parent_resolver): ...
+
+class AbstractNode(Interface):
+ class Meta:
+ abstract: bool
+ @classmethod
+ def __init_subclass_with_meta__(cls, **options) -> None: ...
+
+class Node(AbstractNode):
+ @classmethod
+ def Field(cls, *args, **kwargs): ...
+ @classmethod
+ def node_resolver(cls, only_type, root, info, id): ...
+ @classmethod
+ def get_node_from_global_id(
+ cls, info, global_id, only_type: Incomplete | None = None
+ ): ...
+ @classmethod
+ def from_global_id(cls, global_id): ...
+ @classmethod
+ def to_global_id(cls, type_, id): ...
diff --git a/backend/typings/graphene/types/__init__.pyi b/backend/typings/graphene/types/__init__.pyi
new file mode 100644
index 00000000..e6e94ffe
--- /dev/null
+++ b/backend/typings/graphene/types/__init__.pyi
@@ -0,0 +1,60 @@
+from .argument import Argument as Argument
+from .base64 import Base64 as Base64
+from .context import Context as Context
+from .datetime import Date as Date, DateTime as DateTime, Time as Time
+from .decimal import Decimal as Decimal
+from .dynamic import Dynamic as Dynamic
+from .enum import Enum as Enum
+from .field import Field as Field
+from .inputfield import InputField as InputField
+from .inputobjecttype import InputObjectType as InputObjectType
+from .interface import Interface as Interface
+from .json import JSONString as JSONString
+from .mutation import Mutation as Mutation
+from .objecttype import ObjectType as ObjectType
+from .scalars import (
+ BigInt as BigInt,
+ Boolean as Boolean,
+ Float as Float,
+ ID as ID,
+ Int as Int,
+ Scalar as Scalar,
+ String as String,
+)
+from .schema import Schema as Schema
+from .structures import List as List, NonNull as NonNull
+from .union import Union as Union
+from .uuid import UUID as UUID
+from graphql import GraphQLResolveInfo as ResolveInfo
+
+__all__ = [
+ "Argument",
+ "Base64",
+ "BigInt",
+ "Boolean",
+ "Context",
+ "Date",
+ "DateTime",
+ "Decimal",
+ "Dynamic",
+ "Enum",
+ "Field",
+ "Float",
+ "ID",
+ "InputField",
+ "InputObjectType",
+ "Int",
+ "Interface",
+ "JSONString",
+ "List",
+ "Mutation",
+ "NonNull",
+ "ObjectType",
+ "ResolveInfo",
+ "Scalar",
+ "Schema",
+ "String",
+ "Time",
+ "UUID",
+ "Union",
+]
diff --git a/backend/typings/graphene/types/argument.pyi b/backend/typings/graphene/types/argument.pyi
new file mode 100644
index 00000000..44c189f5
--- /dev/null
+++ b/backend/typings/graphene/types/argument.pyi
@@ -0,0 +1,24 @@
+from .dynamic import Dynamic as Dynamic
+from .mountedtype import MountedType as MountedType
+from .structures import NonNull as NonNull
+from .utils import get_type as get_type
+from _typeshed import Incomplete
+
+class Argument(MountedType):
+ name: Incomplete
+ default_value: Incomplete
+ description: Incomplete
+ def __init__(
+ self,
+ type_,
+ default_value=...,
+ description: Incomplete | None = None,
+ name: Incomplete | None = None,
+ required: bool = False,
+ _creation_counter: Incomplete | None = None,
+ ) -> None: ...
+ @property
+ def type(self): ...
+ def __eq__(self, other): ...
+
+def to_arguments(args, extra_args: Incomplete | None = None): ...
diff --git a/backend/typings/graphene/types/base.pyi b/backend/typings/graphene/types/base.pyi
new file mode 100644
index 00000000..de6fd2ff
--- /dev/null
+++ b/backend/typings/graphene/types/base.pyi
@@ -0,0 +1,28 @@
+from ..utils.subclass_with_meta import (
+ SubclassWithMeta as SubclassWithMeta,
+ SubclassWithMeta_Meta as SubclassWithMeta_Meta,
+)
+from ..utils.trim_docstring import trim_docstring as trim_docstring
+from _typeshed import Incomplete
+
+class BaseOptions:
+ name: str
+ description: str
+ class_type: Incomplete
+ def __init__(self, class_type) -> None: ...
+ def freeze(self) -> None: ...
+ def __setattr__(self, name, value) -> None: ...
+
+BaseTypeMeta = SubclassWithMeta_Meta
+
+class BaseType(SubclassWithMeta):
+ @classmethod
+ def create_type(cls, class_name, **options): ...
+ @classmethod
+ def __init_subclass_with_meta__(
+ cls,
+ name: Incomplete | None = None,
+ description: Incomplete | None = None,
+ _meta: Incomplete | None = None,
+ **_kwargs
+ ) -> None: ...
diff --git a/backend/typings/graphene/types/base64.pyi b/backend/typings/graphene/types/base64.pyi
new file mode 100644
index 00000000..f6e6d13e
--- /dev/null
+++ b/backend/typings/graphene/types/base64.pyi
@@ -0,0 +1,10 @@
+from .scalars import Scalar as Scalar
+from _typeshed import Incomplete
+
+class Base64(Scalar):
+ @staticmethod
+ def serialize(value): ...
+ @classmethod
+ def parse_literal(cls, node, _variables: Incomplete | None = None): ...
+ @staticmethod
+ def parse_value(value): ...
diff --git a/backend/typings/graphene/types/context.pyi b/backend/typings/graphene/types/context.pyi
new file mode 100644
index 00000000..97effe22
--- /dev/null
+++ b/backend/typings/graphene/types/context.pyi
@@ -0,0 +1,2 @@
+class Context:
+ def __init__(self, **params) -> None: ...
diff --git a/backend/typings/graphene/types/datetime.pyi b/backend/typings/graphene/types/datetime.pyi
new file mode 100644
index 00000000..d6dcffe9
--- /dev/null
+++ b/backend/typings/graphene/types/datetime.pyi
@@ -0,0 +1,26 @@
+from .scalars import Scalar as Scalar
+from _typeshed import Incomplete
+
+class Date(Scalar):
+ @staticmethod
+ def serialize(date): ...
+ @classmethod
+ def parse_literal(cls, node, _variables: Incomplete | None = None): ...
+ @staticmethod
+ def parse_value(value): ...
+
+class DateTime(Scalar):
+ @staticmethod
+ def serialize(dt): ...
+ @classmethod
+ def parse_literal(cls, node, _variables: Incomplete | None = None): ...
+ @staticmethod
+ def parse_value(value): ...
+
+class Time(Scalar):
+ @staticmethod
+ def serialize(time): ...
+ @classmethod
+ def parse_literal(cls, node, _variables: Incomplete | None = None): ...
+ @classmethod
+ def parse_value(cls, value): ...
diff --git a/backend/typings/graphene/types/decimal.pyi b/backend/typings/graphene/types/decimal.pyi
new file mode 100644
index 00000000..26236e30
--- /dev/null
+++ b/backend/typings/graphene/types/decimal.pyi
@@ -0,0 +1,10 @@
+from .scalars import Scalar as Scalar
+from _typeshed import Incomplete
+
+class Decimal(Scalar):
+ @staticmethod
+ def serialize(dec): ...
+ @classmethod
+ def parse_literal(cls, node, _variables: Incomplete | None = None): ...
+ @staticmethod
+ def parse_value(value): ...
diff --git a/backend/typings/graphene/types/definitions.pyi b/backend/typings/graphene/types/definitions.pyi
new file mode 100644
index 00000000..0946a001
--- /dev/null
+++ b/backend/typings/graphene/types/definitions.pyi
@@ -0,0 +1,23 @@
+from _typeshed import Incomplete
+from graphql import (
+ GraphQLEnumType,
+ GraphQLInputObjectType,
+ GraphQLInterfaceType,
+ GraphQLObjectType,
+ GraphQLScalarType,
+ GraphQLUnionType,
+)
+
+class GrapheneGraphQLType:
+ graphene_type: Incomplete
+ def __init__(self, *args, **kwargs) -> None: ...
+
+class GrapheneInterfaceType(GrapheneGraphQLType, GraphQLInterfaceType): ...
+class GrapheneUnionType(GrapheneGraphQLType, GraphQLUnionType): ...
+class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType): ...
+class GrapheneScalarType(GrapheneGraphQLType, GraphQLScalarType): ...
+
+class GrapheneEnumType(GrapheneGraphQLType, GraphQLEnumType):
+ def serialize(self, value): ...
+
+class GrapheneInputObjectType(GrapheneGraphQLType, GraphQLInputObjectType): ...
diff --git a/backend/typings/graphene/types/dynamic.pyi b/backend/typings/graphene/types/dynamic.pyi
new file mode 100644
index 00000000..46c3248b
--- /dev/null
+++ b/backend/typings/graphene/types/dynamic.pyi
@@ -0,0 +1,13 @@
+from .mountedtype import MountedType as MountedType
+from _typeshed import Incomplete
+
+class Dynamic(MountedType):
+ type: Incomplete
+ with_schema: Incomplete
+ def __init__(
+ self,
+ type_,
+ with_schema: bool = False,
+ _creation_counter: Incomplete | None = None,
+ ) -> None: ...
+ def get_type(self, schema: Incomplete | None = None): ...
diff --git a/backend/typings/graphene/types/enum.pyi b/backend/typings/graphene/types/enum.pyi
new file mode 100644
index 00000000..2b67fd3e
--- /dev/null
+++ b/backend/typings/graphene/types/enum.pyi
@@ -0,0 +1,36 @@
+from .base import BaseOptions as BaseOptions, BaseType as BaseType
+from .unmountedtype import UnmountedType as UnmountedType
+from _typeshed import Incomplete
+from graphene.utils.subclass_with_meta import (
+ SubclassWithMeta_Meta as SubclassWithMeta_Meta,
+)
+
+def eq_enum(self, other): ...
+
+EnumType: Incomplete
+
+class EnumOptions(BaseOptions):
+ enum: Enum
+ deprecation_reason: Incomplete
+
+class EnumMeta(SubclassWithMeta_Meta):
+ def __new__(cls, name_, bases, classdict, **options): ...
+ def get(cls, value): ...
+ def __getitem__(cls, value): ...
+ def __prepare__(name, bases, **kwargs): ...
+ def __call__(cls, *args, **kwargs): ...
+ def from_enum(
+ cls,
+ enum,
+ name: Incomplete | None = None,
+ description: Incomplete | None = None,
+ deprecation_reason: Incomplete | None = None,
+ ): ...
+
+class Enum(UnmountedType, BaseType, metaclass=EnumMeta):
+ @classmethod
+ def __init_subclass_with_meta__(
+ cls, enum: Incomplete | None = None, _meta: Incomplete | None = None, **options
+ ) -> None: ...
+ @classmethod
+ def get_type(cls): ...
diff --git a/backend/typings/graphene/types/field.pyi b/backend/typings/graphene/types/field.pyi
new file mode 100644
index 00000000..96c54211
--- /dev/null
+++ b/backend/typings/graphene/types/field.pyi
@@ -0,0 +1,39 @@
+from ..utils.deprecated import warn_deprecation as warn_deprecation
+from .argument import Argument as Argument, to_arguments as to_arguments
+from .mountedtype import MountedType as MountedType
+from .resolver import default_resolver as default_resolver
+from .structures import NonNull as NonNull
+from .unmountedtype import UnmountedType as UnmountedType
+from .utils import get_type as get_type
+from _typeshed import Incomplete
+
+base_type = type
+
+def source_resolver(source, root, info, **args): ...
+
+class Field(MountedType):
+ name: Incomplete
+ args: Incomplete
+ resolver: Incomplete
+ deprecation_reason: Incomplete
+ description: Incomplete
+ default_value: Incomplete
+ def __init__(
+ self,
+ type_,
+ args: Incomplete | None = None,
+ resolver: Incomplete | None = None,
+ source: Incomplete | None = None,
+ deprecation_reason: Incomplete | None = None,
+ name: Incomplete | None = None,
+ description: Incomplete | None = None,
+ required: bool = False,
+ _creation_counter: Incomplete | None = None,
+ default_value: Incomplete | None = None,
+ **extra_args
+ ) -> None: ...
+ @property
+ def type(self): ...
+ get_resolver: Incomplete
+ def wrap_resolve(self, parent_resolver): ...
+ def wrap_subscribe(self, parent_subscribe): ...
diff --git a/backend/typings/graphene/types/generic.pyi b/backend/typings/graphene/types/generic.pyi
new file mode 100644
index 00000000..38b6b7ab
--- /dev/null
+++ b/backend/typings/graphene/types/generic.pyi
@@ -0,0 +1,11 @@
+from .scalars import Scalar as Scalar
+from _typeshed import Incomplete
+from graphene.types.scalars import MAX_INT as MAX_INT, MIN_INT as MIN_INT
+
+class GenericScalar(Scalar):
+ @staticmethod
+ def identity(value): ...
+ serialize = identity
+ parse_value = identity
+ @staticmethod
+ def parse_literal(ast, _variables: Incomplete | None = None): ...
diff --git a/backend/typings/graphene/types/inputfield.pyi b/backend/typings/graphene/types/inputfield.pyi
new file mode 100644
index 00000000..795ce7e7
--- /dev/null
+++ b/backend/typings/graphene/types/inputfield.pyi
@@ -0,0 +1,23 @@
+from .mountedtype import MountedType as MountedType
+from .structures import NonNull as NonNull
+from .utils import get_type as get_type
+from _typeshed import Incomplete
+
+class InputField(MountedType):
+ name: Incomplete
+ deprecation_reason: Incomplete
+ default_value: Incomplete
+ description: Incomplete
+ def __init__(
+ self,
+ type_,
+ name: Incomplete | None = None,
+ default_value=...,
+ deprecation_reason: Incomplete | None = None,
+ description: Incomplete | None = None,
+ required: bool = False,
+ _creation_counter: Incomplete | None = None,
+ **extra_args
+ ) -> None: ...
+ @property
+ def type(self): ...
diff --git a/backend/typings/graphene/types/inputobjecttype.pyi b/backend/typings/graphene/types/inputobjecttype.pyi
new file mode 100644
index 00000000..02be9410
--- /dev/null
+++ b/backend/typings/graphene/types/inputobjecttype.pyi
@@ -0,0 +1,29 @@
+from .base import BaseOptions as BaseOptions, BaseType as BaseType
+from .inputfield import InputField as InputField
+from .unmountedtype import UnmountedType as UnmountedType
+from .utils import yank_fields_from_attrs as yank_fields_from_attrs
+from _typeshed import Incomplete
+from typing import Dict
+
+MYPY: bool
+
+class InputObjectTypeOptions(BaseOptions):
+ fields: Dict[str, InputField]
+ container: InputObjectTypeContainer
+
+class InputObjectTypeContainer(dict, BaseType):
+ class Meta:
+ abstract: bool
+ def __init__(self, *args, **kwargs) -> None: ...
+ def __init_subclass__(cls, *args, **kwargs) -> None: ...
+
+class InputObjectType(UnmountedType, BaseType):
+ @classmethod
+ def __init_subclass_with_meta__(
+ cls,
+ container: Incomplete | None = None,
+ _meta: Incomplete | None = None,
+ **options
+ ) -> None: ...
+ @classmethod
+ def get_type(cls): ...
diff --git a/backend/typings/graphene/types/interface.pyi b/backend/typings/graphene/types/interface.pyi
new file mode 100644
index 00000000..a912e281
--- /dev/null
+++ b/backend/typings/graphene/types/interface.pyi
@@ -0,0 +1,20 @@
+from .base import BaseOptions as BaseOptions, BaseType as BaseType
+from .field import Field as Field
+from .utils import yank_fields_from_attrs as yank_fields_from_attrs
+from _typeshed import Incomplete
+from typing import Dict, Iterable, Type
+
+MYPY: bool
+
+class InterfaceOptions(BaseOptions):
+ fields: Dict[str, Field]
+ interfaces: Iterable[Type[Interface]]
+
+class Interface(BaseType):
+ @classmethod
+ def __init_subclass_with_meta__(
+ cls, _meta: Incomplete | None = None, interfaces=(), **options
+ ) -> None: ...
+ @classmethod
+ def resolve_type(cls, instance, info): ...
+ def __init__(self, *args, **kwargs) -> None: ...
diff --git a/backend/typings/graphene/types/json.pyi b/backend/typings/graphene/types/json.pyi
new file mode 100644
index 00000000..c055e0d5
--- /dev/null
+++ b/backend/typings/graphene/types/json.pyi
@@ -0,0 +1,10 @@
+from .scalars import Scalar as Scalar
+from _typeshed import Incomplete
+
+class JSONString(Scalar):
+ @staticmethod
+ def serialize(dt): ...
+ @staticmethod
+ def parse_literal(node, _variables: Incomplete | None = None): ...
+ @staticmethod
+ def parse_value(value): ...
diff --git a/backend/typings/graphene/types/mountedtype.pyi b/backend/typings/graphene/types/mountedtype.pyi
new file mode 100644
index 00000000..7fafb514
--- /dev/null
+++ b/backend/typings/graphene/types/mountedtype.pyi
@@ -0,0 +1,6 @@
+from ..utils.orderedtype import OrderedType as OrderedType
+from .unmountedtype import UnmountedType as UnmountedType
+
+class MountedType(OrderedType):
+ @classmethod
+ def mounted(cls, unmounted): ...
diff --git a/backend/typings/graphene/types/mutation.pyi b/backend/typings/graphene/types/mutation.pyi
new file mode 100644
index 00000000..1e692c1b
--- /dev/null
+++ b/backend/typings/graphene/types/mutation.pyi
@@ -0,0 +1,38 @@
+from ..utils.deprecated import warn_deprecation as warn_deprecation
+from ..utils.get_unbound_function import get_unbound_function as get_unbound_function
+from ..utils.props import props as props
+from .argument import Argument as Argument
+from .field import Field as Field
+from .interface import Interface as Interface
+from .objecttype import ObjectType as ObjectType, ObjectTypeOptions as ObjectTypeOptions
+from .utils import yank_fields_from_attrs as yank_fields_from_attrs
+from _typeshed import Incomplete
+from typing import Callable, Dict, Iterable, Type
+
+MYPY: bool
+
+class MutationOptions(ObjectTypeOptions):
+ arguments: Dict[str, Argument]
+ output: Type[ObjectType]
+ resolver: Callable
+ interfaces: Iterable[Type[Interface]]
+
+class Mutation(ObjectType):
+ @classmethod
+ def __init_subclass_with_meta__(
+ cls,
+ interfaces=(),
+ resolver: Incomplete | None = None,
+ output: Incomplete | None = None,
+ arguments: Incomplete | None = None,
+ _meta: Incomplete | None = None,
+ **options
+ ) -> None: ...
+ @classmethod
+ def Field(
+ cls,
+ name: Incomplete | None = None,
+ description: Incomplete | None = None,
+ deprecation_reason: Incomplete | None = None,
+ required: bool = False,
+ ): ...
diff --git a/backend/typings/graphene/types/objecttype.pyi b/backend/typings/graphene/types/objecttype.pyi
new file mode 100644
index 00000000..e9131ced
--- /dev/null
+++ b/backend/typings/graphene/types/objecttype.pyi
@@ -0,0 +1,32 @@
+from ..pyutils.dataclasses import field as field, make_dataclass as make_dataclass
+from .base import (
+ BaseOptions as BaseOptions,
+ BaseType as BaseType,
+ BaseTypeMeta as BaseTypeMeta,
+)
+from .field import Field as Field
+from .interface import Interface as Interface
+from .utils import yank_fields_from_attrs as yank_fields_from_attrs
+from _typeshed import Incomplete
+from typing import Dict, Iterable, Type
+
+MYPY: bool
+
+class ObjectTypeOptions(BaseOptions):
+ fields: Dict[str, Field]
+ interfaces: Iterable[Type[Interface]]
+
+class ObjectTypeMeta(BaseTypeMeta):
+ def __new__(cls, name_, bases, namespace, **options): ...
+
+class ObjectType(BaseType, metaclass=ObjectTypeMeta):
+ @classmethod
+ def __init_subclass_with_meta__(
+ cls,
+ interfaces=(),
+ possible_types=(),
+ default_resolver: Incomplete | None = None,
+ _meta: Incomplete | None = None,
+ **options
+ ) -> None: ...
+ is_type_of: Incomplete
diff --git a/backend/typings/graphene/types/resolver.pyi b/backend/typings/graphene/types/resolver.pyi
new file mode 100644
index 00000000..e0a8c72d
--- /dev/null
+++ b/backend/typings/graphene/types/resolver.pyi
@@ -0,0 +1,8 @@
+def attr_resolver(attname, default_value, root, info, **args): ...
+def dict_resolver(attname, default_value, root, info, **args): ...
+def dict_or_attr_resolver(attname, default_value, root, info, **args): ...
+
+default_resolver = dict_or_attr_resolver
+
+def set_default_resolver(resolver) -> None: ...
+def get_default_resolver(): ...
diff --git a/backend/typings/graphene/types/scalars.pyi b/backend/typings/graphene/types/scalars.pyi
new file mode 100644
index 00000000..ae3ae45b
--- /dev/null
+++ b/backend/typings/graphene/types/scalars.pyi
@@ -0,0 +1,62 @@
+from .base import BaseOptions as BaseOptions, BaseType as BaseType
+from .unmountedtype import UnmountedType as UnmountedType
+from _typeshed import Incomplete
+from typing import Any
+
+class ScalarOptions(BaseOptions): ...
+
+class Scalar(UnmountedType, BaseType):
+ @classmethod
+ def __init_subclass_with_meta__(cls, **options) -> None: ...
+ serialize: Incomplete
+ parse_value: Incomplete
+ parse_literal: Incomplete
+ @classmethod
+ def get_type(cls): ...
+
+MAX_INT: int
+MIN_INT: int
+
+class Int(Scalar):
+ @staticmethod
+ def coerce_int(value): ...
+ serialize = coerce_int
+ parse_value = coerce_int
+ @staticmethod
+ def parse_literal(ast, _variables: Incomplete | None = None): ...
+
+class BigInt(Scalar):
+ @staticmethod
+ def coerce_int(value): ...
+ serialize = coerce_int
+ parse_value = coerce_int
+ @staticmethod
+ def parse_literal(ast, _variables: Incomplete | None = None): ...
+
+class Float(Scalar):
+ @staticmethod
+ def coerce_float(value: Any) -> float: ...
+ serialize = coerce_float
+ parse_value = coerce_float
+ @staticmethod
+ def parse_literal(ast, _variables: Incomplete | None = None): ...
+
+class String(Scalar):
+ @staticmethod
+ def coerce_string(value): ...
+ serialize = coerce_string
+ parse_value = coerce_string
+ @staticmethod
+ def parse_literal(ast, _variables: Incomplete | None = None): ...
+
+class Boolean(Scalar):
+ serialize = bool
+ parse_value = bool
+ @staticmethod
+ def parse_literal(ast, _variables: Incomplete | None = None): ...
+
+class ID(Scalar):
+ serialize = str
+ parse_value = str
+ @staticmethod
+ def parse_literal(ast, _variables: Incomplete | None = None): ...
diff --git a/backend/typings/graphene/types/schema.pyi b/backend/typings/graphene/types/schema.pyi
new file mode 100644
index 00000000..8c38df4d
--- /dev/null
+++ b/backend/typings/graphene/types/schema.pyi
@@ -0,0 +1,89 @@
+from ..utils.get_unbound_function import get_unbound_function as get_unbound_function
+from ..utils.str_converters import to_camel_case as to_camel_case
+from .definitions import (
+ GrapheneEnumType as GrapheneEnumType,
+ GrapheneGraphQLType as GrapheneGraphQLType,
+ GrapheneInputObjectType as GrapheneInputObjectType,
+ GrapheneInterfaceType as GrapheneInterfaceType,
+ GrapheneObjectType as GrapheneObjectType,
+ GrapheneScalarType as GrapheneScalarType,
+ GrapheneUnionType as GrapheneUnionType,
+)
+from .dynamic import Dynamic as Dynamic
+from .enum import Enum as Enum
+from .field import Field as Field
+from .inputobjecttype import InputObjectType as InputObjectType
+from .interface import Interface as Interface
+from .objecttype import ObjectType as ObjectType
+from .resolver import get_default_resolver as get_default_resolver
+from .scalars import (
+ Boolean as Boolean,
+ Float as Float,
+ ID as ID,
+ Int as Int,
+ Scalar as Scalar,
+ String as String,
+)
+from .structures import List as List, NonNull as NonNull
+from .union import Union as Union
+from .utils import get_field_as as get_field_as
+from _typeshed import Incomplete
+
+introspection_query: Incomplete
+IntrospectionSchema: Incomplete
+
+def assert_valid_root_type(type_) -> None: ...
+def is_graphene_type(type_): ...
+def is_type_of_from_possible_types(possible_types, root, _info): ...
+def identity_resolve(root, info, **arguments): ...
+
+class TypeMap(dict):
+ auto_camelcase: Incomplete
+ query: Incomplete
+ mutation: Incomplete
+ subscription: Incomplete
+ types: Incomplete
+ def __init__(
+ self,
+ query: Incomplete | None = None,
+ mutation: Incomplete | None = None,
+ subscription: Incomplete | None = None,
+ types: Incomplete | None = None,
+ auto_camelcase: bool = True,
+ ) -> None: ...
+ def add_type(self, graphene_type): ...
+ @staticmethod
+ def create_scalar(graphene_type): ...
+ @staticmethod
+ def create_enum(graphene_type): ...
+ def create_objecttype(self, graphene_type): ...
+ def create_interface(self, graphene_type): ...
+ def create_inputobjecttype(self, graphene_type): ...
+ def construct_union(self, graphene_type): ...
+ def get_name(self, name): ...
+ def create_fields_for_type(self, graphene_type, is_input_type: bool = False): ...
+ def get_function_for_type(self, graphene_type, func_name, name, default_value): ...
+ def resolve_type(self, resolve_type_func, type_name, root, info, _type): ...
+
+class Schema:
+ query: Incomplete
+ mutation: Incomplete
+ subscription: Incomplete
+ graphql_schema: Incomplete
+ def __init__(
+ self,
+ query: Incomplete | None = None,
+ mutation: Incomplete | None = None,
+ subscription: Incomplete | None = None,
+ types: Incomplete | None = None,
+ directives: Incomplete | None = None,
+ auto_camelcase: bool = True,
+ ) -> None: ...
+ def __getattr__(self, type_name): ...
+ def lazy(self, _type): ...
+ def execute(self, *args, **kwargs): ...
+ async def execute_async(self, *args, **kwargs): ...
+ async def subscribe(self, query, *args, **kwargs): ...
+ def introspect(self): ...
+
+def normalize_execute_kwargs(kwargs): ...
diff --git a/backend/typings/graphene/types/structures.pyi b/backend/typings/graphene/types/structures.pyi
new file mode 100644
index 00000000..809b5564
--- /dev/null
+++ b/backend/typings/graphene/types/structures.pyi
@@ -0,0 +1,15 @@
+from .unmountedtype import UnmountedType as UnmountedType
+from .utils import get_type as get_type
+
+class Structure(UnmountedType):
+ def __init__(self, of_type, *args, **kwargs) -> None: ...
+ @property
+ def of_type(self): ...
+ def get_type(self): ...
+
+class List(Structure):
+ def __eq__(self, other): ...
+
+class NonNull(Structure):
+ def __init__(self, *args, **kwargs) -> None: ...
+ def __eq__(self, other): ...
diff --git a/backend/typings/graphene/types/union.pyi b/backend/typings/graphene/types/union.pyi
new file mode 100644
index 00000000..1d17fdcd
--- /dev/null
+++ b/backend/typings/graphene/types/union.pyi
@@ -0,0 +1,20 @@
+from .base import BaseOptions as BaseOptions, BaseType as BaseType
+from .objecttype import ObjectType as ObjectType
+from .unmountedtype import UnmountedType as UnmountedType
+from _typeshed import Incomplete
+from typing import Iterable, Type
+
+MYPY: bool
+
+class UnionOptions(BaseOptions):
+ types: Iterable[Type[ObjectType]]
+
+class Union(UnmountedType, BaseType):
+ @classmethod
+ def __init_subclass_with_meta__(
+ cls, types: Incomplete | None = None, **options
+ ) -> None: ...
+ @classmethod
+ def get_type(cls): ...
+ @classmethod
+ def resolve_type(cls, instance, info): ...
diff --git a/backend/typings/graphene/types/unmountedtype.pyi b/backend/typings/graphene/types/unmountedtype.pyi
new file mode 100644
index 00000000..52b48781
--- /dev/null
+++ b/backend/typings/graphene/types/unmountedtype.pyi
@@ -0,0 +1,13 @@
+from ..utils.orderedtype import OrderedType as OrderedType
+from _typeshed import Incomplete
+
+class UnmountedType(OrderedType):
+ args: Incomplete
+ kwargs: Incomplete
+ def __init__(self, *args, **kwargs) -> None: ...
+ def get_type(self) -> None: ...
+ def mount_as(self, _as): ...
+ def Field(self): ...
+ def InputField(self): ...
+ def Argument(self): ...
+ def __eq__(self, other): ...
diff --git a/backend/typings/graphene/types/utils.pyi b/backend/typings/graphene/types/utils.pyi
new file mode 100644
index 00000000..1b4a290e
--- /dev/null
+++ b/backend/typings/graphene/types/utils.pyi
@@ -0,0 +1,9 @@
+from ..utils.module_loading import import_string as import_string
+from .mountedtype import MountedType as MountedType
+from .unmountedtype import UnmountedType as UnmountedType
+from _typeshed import Incomplete
+
+def get_field_as(value, _as: Incomplete | None = None): ...
+def yank_fields_from_attrs(attrs, _as: Incomplete | None = None, sort: bool = True): ...
+def get_type(_type): ...
+def get_underlying_type(_type): ...
diff --git a/backend/typings/graphene/types/uuid.pyi b/backend/typings/graphene/types/uuid.pyi
new file mode 100644
index 00000000..30159903
--- /dev/null
+++ b/backend/typings/graphene/types/uuid.pyi
@@ -0,0 +1,10 @@
+from .scalars import Scalar as Scalar
+from _typeshed import Incomplete
+
+class UUID(Scalar):
+ @staticmethod
+ def serialize(uuid): ...
+ @staticmethod
+ def parse_literal(node, _variables: Incomplete | None = None): ...
+ @staticmethod
+ def parse_value(value): ...
diff --git a/backend/typings/graphene/utils/__init__.pyi b/backend/typings/graphene/utils/__init__.pyi
new file mode 100644
index 00000000..e69de29b
diff --git a/backend/typings/graphene/utils/crunch.pyi b/backend/typings/graphene/utils/crunch.pyi
new file mode 100644
index 00000000..2f965dce
--- /dev/null
+++ b/backend/typings/graphene/utils/crunch.pyi
@@ -0,0 +1,4 @@
+def to_key(value): ...
+def insert(value, index, values): ...
+def flatten(data, index, values): ...
+def crunch(data): ...
diff --git a/backend/typings/graphene/utils/dataloader.pyi b/backend/typings/graphene/utils/dataloader.pyi
new file mode 100644
index 00000000..8488f938
--- /dev/null
+++ b/backend/typings/graphene/utils/dataloader.pyi
@@ -0,0 +1,39 @@
+from _typeshed import Incomplete
+from typing import NamedTuple
+
+class Loader(NamedTuple):
+ key: Incomplete
+ future: Incomplete
+
+def iscoroutinefunctionorpartial(fn): ...
+
+class DataLoader:
+ batch: bool
+ max_batch_size: int
+ cache: bool
+ batch_load_fn: Incomplete
+ get_cache_key: Incomplete
+ def __init__(
+ self,
+ batch_load_fn: Incomplete | None = None,
+ batch: Incomplete | None = None,
+ max_batch_size: Incomplete | None = None,
+ cache: Incomplete | None = None,
+ get_cache_key: Incomplete | None = None,
+ cache_map: Incomplete | None = None,
+ loop: Incomplete | None = None,
+ ) -> None: ...
+ @property
+ def loop(self): ...
+ def load(self, key: Incomplete | None = None): ...
+ def do_resolve_reject(self, key, future) -> None: ...
+ def load_many(self, keys): ...
+ def clear(self, key): ...
+ def clear_all(self): ...
+ def prime(self, key, value): ...
+
+def enqueue_post_future_job(loop, loader) -> None: ...
+def get_chunks(iterable_obj, chunk_size: int = 1): ...
+def dispatch_queue(loader) -> None: ...
+async def dispatch_queue_batch(loader, queue): ...
+def failed_dispatch(loader, queue, error) -> None: ...
diff --git a/backend/typings/graphene/utils/deduplicator.pyi b/backend/typings/graphene/utils/deduplicator.pyi
new file mode 100644
index 00000000..dced923a
--- /dev/null
+++ b/backend/typings/graphene/utils/deduplicator.pyi
@@ -0,0 +1,3 @@
+from _typeshed import Incomplete
+
+def deflate(node, index: Incomplete | None = None, path: Incomplete | None = None): ...
diff --git a/backend/typings/graphene/utils/deprecated.pyi b/backend/typings/graphene/utils/deprecated.pyi
new file mode 100644
index 00000000..f02961be
--- /dev/null
+++ b/backend/typings/graphene/utils/deprecated.pyi
@@ -0,0 +1,6 @@
+from _typeshed import Incomplete
+
+string_types: Incomplete
+
+def warn_deprecation(text) -> None: ...
+def deprecated(reason): ...
diff --git a/backend/typings/graphene/utils/get_unbound_function.pyi b/backend/typings/graphene/utils/get_unbound_function.pyi
new file mode 100644
index 00000000..c86c6d96
--- /dev/null
+++ b/backend/typings/graphene/utils/get_unbound_function.pyi
@@ -0,0 +1 @@
+def get_unbound_function(func): ...
diff --git a/backend/typings/graphene/utils/is_introspection_key.pyi b/backend/typings/graphene/utils/is_introspection_key.pyi
new file mode 100644
index 00000000..dfbc96d2
--- /dev/null
+++ b/backend/typings/graphene/utils/is_introspection_key.pyi
@@ -0,0 +1 @@
+def is_introspection_key(key): ...
diff --git a/backend/typings/graphene/utils/module_loading.pyi b/backend/typings/graphene/utils/module_loading.pyi
new file mode 100644
index 00000000..109c5dee
--- /dev/null
+++ b/backend/typings/graphene/utils/module_loading.pyi
@@ -0,0 +1,4 @@
+from _typeshed import Incomplete
+
+def import_string(dotted_path, dotted_attributes: Incomplete | None = None): ...
+def lazy_import(dotted_path, dotted_attributes: Incomplete | None = None): ...
diff --git a/backend/typings/graphene/utils/orderedtype.pyi b/backend/typings/graphene/utils/orderedtype.pyi
new file mode 100644
index 00000000..c426e378
--- /dev/null
+++ b/backend/typings/graphene/utils/orderedtype.pyi
@@ -0,0 +1,12 @@
+from _typeshed import Incomplete
+
+class OrderedType:
+ creation_counter: int
+ def __init__(self, _creation_counter: Incomplete | None = None) -> None: ...
+ @staticmethod
+ def gen_counter(): ...
+ def reset_counter(self) -> None: ...
+ def __eq__(self, other): ...
+ def __lt__(self, other): ...
+ def __gt__(self, other): ...
+ def __hash__(self): ...
diff --git a/backend/typings/graphene/utils/props.pyi b/backend/typings/graphene/utils/props.pyi
new file mode 100644
index 00000000..11ebcfbd
--- /dev/null
+++ b/backend/typings/graphene/utils/props.pyi
@@ -0,0 +1,4 @@
+class _OldClass: ...
+class _NewClass: ...
+
+def props(x): ...
diff --git a/backend/typings/graphene/utils/resolve_only_args.pyi b/backend/typings/graphene/utils/resolve_only_args.pyi
new file mode 100644
index 00000000..bd699bf2
--- /dev/null
+++ b/backend/typings/graphene/utils/resolve_only_args.pyi
@@ -0,0 +1,3 @@
+from .deprecated import deprecated as deprecated
+
+def resolve_only_args(func): ...
diff --git a/backend/typings/graphene/utils/str_converters.pyi b/backend/typings/graphene/utils/str_converters.pyi
new file mode 100644
index 00000000..6f19101f
--- /dev/null
+++ b/backend/typings/graphene/utils/str_converters.pyi
@@ -0,0 +1,2 @@
+def to_camel_case(snake_str): ...
+def to_snake_case(name): ...
diff --git a/backend/typings/graphene/utils/subclass_with_meta.pyi b/backend/typings/graphene/utils/subclass_with_meta.pyi
new file mode 100644
index 00000000..ec72b8f1
--- /dev/null
+++ b/backend/typings/graphene/utils/subclass_with_meta.pyi
@@ -0,0 +1,8 @@
+from .props import props as props
+
+class SubclassWithMeta_Meta(type): ...
+
+class SubclassWithMeta(metaclass=SubclassWithMeta_Meta):
+ def __init_subclass__(cls, **meta_options) -> None: ...
+ @classmethod
+ def __init_subclass_with_meta__(cls, **meta_options) -> None: ...
diff --git a/backend/typings/graphene/utils/thenables.pyi b/backend/typings/graphene/utils/thenables.pyi
new file mode 100644
index 00000000..797f13b5
--- /dev/null
+++ b/backend/typings/graphene/utils/thenables.pyi
@@ -0,0 +1,2 @@
+def await_and_execute(obj, on_resolve): ...
+def maybe_thenable(obj, on_resolve): ...
diff --git a/backend/typings/graphene/utils/trim_docstring.pyi b/backend/typings/graphene/utils/trim_docstring.pyi
new file mode 100644
index 00000000..ceff5b4f
--- /dev/null
+++ b/backend/typings/graphene/utils/trim_docstring.pyi
@@ -0,0 +1 @@
+def trim_docstring(docstring): ...
diff --git a/backend/typings/graphene/validation/__init__.pyi b/backend/typings/graphene/validation/__init__.pyi
new file mode 100644
index 00000000..ceda0425
--- /dev/null
+++ b/backend/typings/graphene/validation/__init__.pyi
@@ -0,0 +1,4 @@
+from .depth_limit import depth_limit_validator as depth_limit_validator
+from .disable_introspection import DisableIntrospection as DisableIntrospection
+
+__all__ = ["DisableIntrospection", "depth_limit_validator"]
diff --git a/backend/typings/graphene/validation/depth_limit.pyi b/backend/typings/graphene/validation/depth_limit.pyi
new file mode 100644
index 00000000..25691b12
--- /dev/null
+++ b/backend/typings/graphene/validation/depth_limit.pyi
@@ -0,0 +1,34 @@
+from ..utils.is_introspection_key import is_introspection_key as is_introspection_key
+from graphql.language import (
+ DefinitionNode as DefinitionNode,
+ FieldNode,
+ FragmentDefinitionNode,
+ Node as Node,
+ OperationDefinitionNode,
+)
+from graphql.validation import ValidationContext as ValidationContext
+from typing import Callable, Dict, List, Optional, Pattern, Union
+
+IgnoreType = Union[Callable[[str], bool], Pattern, str]
+
+def depth_limit_validator(
+ max_depth: int,
+ ignore: Optional[List[IgnoreType]] = None,
+ callback: Callable[[Dict[str, int]], None] = None,
+): ...
+def get_fragments(
+ definitions: List[DefinitionNode],
+) -> Dict[str, FragmentDefinitionNode]: ...
+def get_queries_and_mutations(
+ definitions: List[DefinitionNode],
+) -> Dict[str, OperationDefinitionNode]: ...
+def determine_depth(
+ node: Node,
+ fragments: Dict[str, FragmentDefinitionNode],
+ depth_so_far: int,
+ max_depth: int,
+ context: ValidationContext,
+ operation_name: str,
+ ignore: Optional[List[IgnoreType]] = None,
+) -> int: ...
+def is_ignored(node: FieldNode, ignore: Optional[List[IgnoreType]] = None) -> bool: ...
diff --git a/backend/typings/graphene/validation/disable_introspection.pyi b/backend/typings/graphene/validation/disable_introspection.pyi
new file mode 100644
index 00000000..7dd36e02
--- /dev/null
+++ b/backend/typings/graphene/validation/disable_introspection.pyi
@@ -0,0 +1,6 @@
+from ..utils.is_introspection_key import is_introspection_key as is_introspection_key
+from graphql.language import FieldNode as FieldNode
+from graphql.validation import ValidationRule
+
+class DisableIntrospection(ValidationRule):
+ def enter_field(self, node: FieldNode, *_args): ...
diff --git a/backend/typings/mongoengine/__init__.pyi b/backend/typings/mongoengine/__init__.pyi
new file mode 100644
index 00000000..05761cd8
--- /dev/null
+++ b/backend/typings/mongoengine/__init__.pyi
@@ -0,0 +1,205 @@
+from mongoengine.connection import *
+from mongoengine.document import *
+from mongoengine.errors import *
+from mongoengine.fields import *
+from mongoengine.queryset import *
+from mongoengine.signals import *
+
+__all__ = [
+ "Document",
+ "EmbeddedDocument",
+ "DynamicDocument",
+ "DynamicEmbeddedDocument",
+ "OperationError",
+ "InvalidCollectionError",
+ "NotUniqueError",
+ "MapReduceDocument",
+ "StringField",
+ "URLField",
+ "EmailField",
+ "IntField",
+ "LongField",
+ "FloatField",
+ "DecimalField",
+ "BooleanField",
+ "DateTimeField",
+ "DateField",
+ "ComplexDateTimeField",
+ "EmbeddedDocumentField",
+ "ObjectIdField",
+ "GenericEmbeddedDocumentField",
+ "DynamicField",
+ "ListField",
+ "SortedListField",
+ "EmbeddedDocumentListField",
+ "DictField",
+ "MapField",
+ "ReferenceField",
+ "CachedReferenceField",
+ "LazyReferenceField",
+ "GenericLazyReferenceField",
+ "GenericReferenceField",
+ "BinaryField",
+ "GridFSError",
+ "GridFSProxy",
+ "FileField",
+ "ImageGridFsProxy",
+ "ImproperlyConfigured",
+ "ImageField",
+ "GeoPointField",
+ "PointField",
+ "LineStringField",
+ "PolygonField",
+ "SequenceField",
+ "UUIDField",
+ "EnumField",
+ "MultiPointField",
+ "MultiLineStringField",
+ "MultiPolygonField",
+ "GeoJsonBaseField",
+ "Decimal128Field",
+ "DEFAULT_CONNECTION_NAME",
+ "DEFAULT_DATABASE_NAME",
+ "ConnectionFailure",
+ "connect",
+ "disconnect",
+ "disconnect_all",
+ "get_connection",
+ "get_db",
+ "register_connection",
+ "QuerySet",
+ "QuerySetNoCache",
+ "Q",
+ "queryset_manager",
+ "QuerySetManager",
+ "QueryFieldList",
+ "DO_NOTHING",
+ "NULLIFY",
+ "CASCADE",
+ "DENY",
+ "PULL",
+ "DoesNotExist",
+ "InvalidQueryError",
+ "MultipleObjectsReturned",
+ "NotUniqueError",
+ "OperationError",
+ "pre_init",
+ "post_init",
+ "pre_save",
+ "pre_save_post_validation",
+ "post_save",
+ "pre_delete",
+ "post_delete",
+ "NotRegistered",
+ "InvalidDocumentError",
+ "LookUpError",
+ "DoesNotExist",
+ "MultipleObjectsReturned",
+ "InvalidQueryError",
+ "OperationError",
+ "NotUniqueError",
+ "BulkWriteError",
+ "FieldDoesNotExist",
+ "ValidationError",
+ "SaveConditionError",
+ "DeprecatedError",
+]
+
+# Names in __all__ with no definition:
+# BinaryField
+# BooleanField
+# BulkWriteError
+# CASCADE
+# CachedReferenceField
+# ComplexDateTimeField
+# ConnectionFailure
+# DEFAULT_CONNECTION_NAME
+# DEFAULT_DATABASE_NAME
+# DENY
+# DO_NOTHING
+# DateField
+# DateTimeField
+# Decimal128Field
+# DecimalField
+# DeprecatedError
+# DictField
+# Document
+# DoesNotExist
+# DoesNotExist
+# DynamicDocument
+# DynamicEmbeddedDocument
+# DynamicField
+# EmailField
+# EmbeddedDocument
+# EmbeddedDocumentField
+# EmbeddedDocumentListField
+# EnumField
+# FieldDoesNotExist
+# FileField
+# FloatField
+# GenericEmbeddedDocumentField
+# GenericLazyReferenceField
+# GenericReferenceField
+# GeoJsonBaseField
+# GeoPointField
+# GridFSError
+# GridFSProxy
+# ImageField
+# ImageGridFsProxy
+# ImproperlyConfigured
+# IntField
+# InvalidCollectionError
+# InvalidDocumentError
+# InvalidQueryError
+# InvalidQueryError
+# LazyReferenceField
+# LineStringField
+# ListField
+# LongField
+# LookUpError
+# MapField
+# MapReduceDocument
+# MultiLineStringField
+# MultiPointField
+# MultiPolygonField
+# MultipleObjectsReturned
+# MultipleObjectsReturned
+# NULLIFY
+# NotRegistered
+# NotUniqueError
+# NotUniqueError
+# NotUniqueError
+# ObjectIdField
+# OperationError
+# OperationError
+# OperationError
+# PULL
+# PointField
+# PolygonField
+# Q
+# QueryFieldList
+# QuerySet
+# QuerySetManager
+# QuerySetNoCache
+# ReferenceField
+# SaveConditionError
+# SequenceField
+# SortedListField
+# StringField
+# URLField
+# UUIDField
+# ValidationError
+# connect
+# disconnect
+# disconnect_all
+# get_connection
+# get_db
+# post_delete
+# post_init
+# post_save
+# pre_delete
+# pre_init
+# pre_save
+# pre_save_post_validation
+# queryset_manager
+# register_connection
diff --git a/backend/typings/mongoengine/base/__init__.pyi b/backend/typings/mongoengine/base/__init__.pyi
new file mode 100644
index 00000000..aab2b104
--- /dev/null
+++ b/backend/typings/mongoengine/base/__init__.pyi
@@ -0,0 +1,38 @@
+from mongoengine.base.common import *
+from mongoengine.base.datastructures import *
+from mongoengine.base.document import *
+from mongoengine.base.fields import *
+from mongoengine.base.metaclasses import *
+
+__all__ = [
+ "UPDATE_OPERATORS",
+ "_document_registry",
+ "get_document",
+ "BaseDict",
+ "BaseList",
+ "EmbeddedDocumentList",
+ "LazyReference",
+ "BaseDocument",
+ "BaseField",
+ "ComplexBaseField",
+ "ObjectIdField",
+ "GeoJsonBaseField",
+ "DocumentMetaclass",
+ "TopLevelDocumentMetaclass",
+]
+
+# Names in __all__ with no definition:
+# BaseDict
+# BaseDocument
+# BaseField
+# BaseList
+# ComplexBaseField
+# DocumentMetaclass
+# EmbeddedDocumentList
+# GeoJsonBaseField
+# LazyReference
+# ObjectIdField
+# TopLevelDocumentMetaclass
+# UPDATE_OPERATORS
+# _document_registry
+# get_document
diff --git a/backend/typings/mongoengine/base/common.pyi b/backend/typings/mongoengine/base/common.pyi
new file mode 100644
index 00000000..15873b0f
--- /dev/null
+++ b/backend/typings/mongoengine/base/common.pyi
@@ -0,0 +1,8 @@
+from _typeshed import Incomplete
+
+__all__ = ["UPDATE_OPERATORS", "get_document", "_document_registry"]
+
+UPDATE_OPERATORS: Incomplete
+_document_registry: Incomplete
+
+def get_document(name): ...
diff --git a/backend/typings/mongoengine/base/datastructures.pyi b/backend/typings/mongoengine/base/datastructures.pyi
new file mode 100644
index 00000000..77eac409
--- /dev/null
+++ b/backend/typings/mongoengine/base/datastructures.pyi
@@ -0,0 +1,86 @@
+from _typeshed import Incomplete
+from bson import DBRef
+from collections.abc import Generator
+
+__all__ = [
+ "BaseDict",
+ "StrictDict",
+ "BaseList",
+ "EmbeddedDocumentList",
+ "LazyReference",
+]
+
+class BaseDict(dict):
+ def __init__(self, dict_items, instance, name) -> None: ...
+ def get(self, key, default: Incomplete | None = None): ...
+ def __getitem__(self, key): ...
+ __setitem__: Incomplete
+ __delattr__: Incomplete
+ __delitem__: Incomplete
+ pop: Incomplete
+ clear: Incomplete
+ update: Incomplete
+ popitem: Incomplete
+ setdefault: Incomplete
+
+class BaseList(list):
+ def __init__(self, list_items, instance, name) -> None: ...
+ def __getitem__(self, key): ...
+ def __iter__(self): ...
+ def __setitem__(self, key, value) -> None: ...
+ append: Incomplete
+ extend: Incomplete
+ insert: Incomplete
+ pop: Incomplete
+ remove: Incomplete
+ reverse: Incomplete
+ sort: Incomplete
+ __delitem__: Incomplete
+ __iadd__: Incomplete
+ __imul__: Incomplete
+
+class EmbeddedDocumentList(BaseList):
+ def __init__(self, list_items, instance, name) -> None: ...
+ def filter(self, **kwargs): ...
+ def exclude(self, **kwargs): ...
+ def count(self): ...
+ def get(self, **kwargs): ...
+ def first(self): ...
+ def create(self, **values): ...
+ def save(self, *args, **kwargs) -> None: ...
+ def delete(self): ...
+ def update(self, **update): ...
+
+class StrictDict:
+ def __init__(self, **kwargs) -> None: ...
+ def __getitem__(self, key): ...
+ def __setitem__(self, key, value) -> None: ...
+ def __contains__(self, key) -> bool: ...
+ def get(self, key, default: Incomplete | None = None): ...
+ def pop(self, key, default: Incomplete | None = None): ...
+ def iteritems(self) -> Generator[Incomplete, None, None]: ...
+ def items(self): ...
+ def iterkeys(self): ...
+ def keys(self): ...
+ def __iter__(self): ...
+ def __len__(self) -> int: ...
+ def __eq__(self, other): ...
+ def __ne__(self, other): ...
+ @classmethod
+ def create(cls, allowed_keys): ...
+
+class LazyReference(DBRef):
+ def fetch(self, force: bool = False): ...
+ @property
+ def pk(self): ...
+ document_type: Incomplete
+ passthrough: Incomplete
+ def __init__(
+ self,
+ document_type,
+ pk,
+ cached_doc: Incomplete | None = None,
+ passthrough: bool = False,
+ ) -> None: ...
+ def __getitem__(self, name): ...
+ def __getattr__(self, name): ...
diff --git a/backend/typings/mongoengine/base/document.pyi b/backend/typings/mongoengine/base/document.pyi
new file mode 100644
index 00000000..bd9b35f8
--- /dev/null
+++ b/backend/typings/mongoengine/base/document.pyi
@@ -0,0 +1,25 @@
+from _typeshed import Incomplete
+
+__all__ = ["BaseDocument", "NON_FIELD_ERRORS"]
+
+NON_FIELD_ERRORS: str
+
+class BaseDocument:
+ STRICT: bool
+ def __init__(self, *args, **values) -> None: ...
+ def __delattr__(self, *args, **kwargs) -> None: ...
+ def __setattr__(self, name, value) -> None: ...
+ def __iter__(self): ...
+ def __getitem__(self, name): ...
+ def __setitem__(self, name, value) -> None: ...
+ def __contains__(self, name) -> bool: ...
+ def __len__(self) -> int: ...
+ def __eq__(self, other): ...
+ def __ne__(self, other): ...
+ def clean(self) -> None: ...
+ def get_text_score(self): ...
+ def to_mongo(self, use_db_field: bool = True, fields: Incomplete | None = None): ...
+ def validate(self, clean: bool = True) -> None: ...
+ def to_json(self, *args, **kwargs): ...
+ @classmethod
+ def from_json(cls, json_data, created: bool = False, **kwargs): ...
diff --git a/backend/typings/mongoengine/base/fields.pyi b/backend/typings/mongoengine/base/fields.pyi
new file mode 100644
index 00000000..dcaff72f
--- /dev/null
+++ b/backend/typings/mongoengine/base/fields.pyi
@@ -0,0 +1,72 @@
+from _typeshed import Incomplete
+
+__all__ = ["BaseField", "ComplexBaseField", "ObjectIdField", "GeoJsonBaseField"]
+
+class BaseField:
+ name: Incomplete
+ creation_counter: int
+ auto_creation_counter: int
+ db_field: Incomplete
+ required: Incomplete
+ default: Incomplete
+ unique: Incomplete
+ unique_with: Incomplete
+ primary_key: Incomplete
+ validation: Incomplete
+ choices: Incomplete
+ null: Incomplete
+ sparse: Incomplete
+ def __init__(
+ self,
+ db_field: Incomplete | None = None,
+ required: bool = False,
+ default: Incomplete | None = None,
+ unique: bool = False,
+ unique_with: Incomplete | None = None,
+ primary_key: bool = False,
+ validation: Incomplete | None = None,
+ choices: Incomplete | None = None,
+ null: bool = False,
+ sparse: bool = False,
+ **kwargs
+ ) -> None: ...
+ def __get__(self, instance, owner): ...
+ def __set__(self, instance, value) -> None: ...
+ def error(
+ self,
+ message: str = "",
+ errors: Incomplete | None = None,
+ field_name: Incomplete | None = None,
+ ) -> None: ...
+ def to_python(self, value): ...
+ def to_mongo(self, value): ...
+ def prepare_query_value(self, op, value): ...
+ def validate(self, value, clean: bool = True) -> None: ...
+ @property
+ def owner_document(self): ...
+ @owner_document.setter
+ def owner_document(self, owner_document) -> None: ...
+
+class ComplexBaseField(BaseField):
+ field: Incomplete
+ def __init__(self, field: Incomplete | None = None, **kwargs) -> None: ...
+ def __set__(self, instance, value): ...
+ def __get__(self, instance, owner): ...
+ def to_python(self, value): ...
+ def to_mongo(
+ self, value, use_db_field: bool = True, fields: Incomplete | None = None
+ ): ...
+ def validate(self, value) -> None: ...
+ def prepare_query_value(self, op, value): ...
+ def lookup_member(self, member_name): ...
+
+class ObjectIdField(BaseField):
+ def to_python(self, value): ...
+ def to_mongo(self, value): ...
+ def prepare_query_value(self, op, value): ...
+ def validate(self, value) -> None: ...
+
+class GeoJsonBaseField(BaseField):
+ def __init__(self, auto_index: bool = True, *args, **kwargs) -> None: ...
+ def validate(self, value): ...
+ def to_mongo(self, value): ...
diff --git a/backend/typings/mongoengine/base/metaclasses.pyi b/backend/typings/mongoengine/base/metaclasses.pyi
new file mode 100644
index 00000000..26c39a64
--- /dev/null
+++ b/backend/typings/mongoengine/base/metaclasses.pyi
@@ -0,0 +1,14 @@
+__all__ = ["DocumentMetaclass", "TopLevelDocumentMetaclass"]
+
+class DocumentMetaclass(type):
+ def __new__(mcs, name, bases, attrs): ...
+
+class TopLevelDocumentMetaclass(DocumentMetaclass):
+ def __new__(mcs, name, bases, attrs): ...
+ @classmethod
+ def get_auto_id_names(mcs, new_class): ...
+
+class MetaDict(dict):
+ def merge(self, new_options) -> None: ...
+
+class BasesTuple(tuple): ...
diff --git a/backend/typings/mongoengine/base/utils.pyi b/backend/typings/mongoengine/base/utils.pyi
new file mode 100644
index 00000000..24e4ce33
--- /dev/null
+++ b/backend/typings/mongoengine/base/utils.pyi
@@ -0,0 +1,6 @@
+class LazyRegexCompiler:
+ def __init__(self, pattern, flags: int = 0) -> None: ...
+ @property
+ def compiled_regex(self): ...
+ def __get__(self, instance, owner): ...
+ def __set__(self, instance, value) -> None: ...
diff --git a/backend/typings/mongoengine/common.pyi b/backend/typings/mongoengine/common.pyi
new file mode 100644
index 00000000..e69de29b
diff --git a/backend/typings/mongoengine/connection.pyi b/backend/typings/mongoengine/connection.pyi
new file mode 100644
index 00000000..c564c256
--- /dev/null
+++ b/backend/typings/mongoengine/connection.pyi
@@ -0,0 +1,38 @@
+from _typeshed import Incomplete
+
+__all__ = [
+ "DEFAULT_CONNECTION_NAME",
+ "DEFAULT_DATABASE_NAME",
+ "ConnectionFailure",
+ "connect",
+ "disconnect",
+ "disconnect_all",
+ "get_connection",
+ "get_db",
+ "register_connection",
+]
+
+DEFAULT_CONNECTION_NAME: str
+DEFAULT_DATABASE_NAME: str
+
+class ConnectionFailure(Exception): ...
+
+def register_connection(
+ alias,
+ db: Incomplete | None = None,
+ name: Incomplete | None = None,
+ host: Incomplete | None = None,
+ port: Incomplete | None = None,
+ read_preference=...,
+ username: Incomplete | None = None,
+ password: Incomplete | None = None,
+ authentication_source: Incomplete | None = None,
+ authentication_mechanism: Incomplete | None = None,
+ authmechanismproperties: Incomplete | None = None,
+ **kwargs
+) -> None: ...
+def disconnect(alias=...) -> None: ...
+def disconnect_all() -> None: ...
+def get_connection(alias=..., reconnect: bool = False): ...
+def get_db(alias=..., reconnect: bool = False): ...
+def connect(db: Incomplete | None = None, alias=..., **kwargs): ...
diff --git a/backend/typings/mongoengine/context_managers.pyi b/backend/typings/mongoengine/context_managers.pyi
new file mode 100644
index 00000000..cf02060e
--- /dev/null
+++ b/backend/typings/mongoengine/context_managers.pyi
@@ -0,0 +1,90 @@
+from _typeshed import Incomplete
+from collections.abc import Generator
+
+__all__ = [
+ "switch_db",
+ "switch_collection",
+ "no_dereference",
+ "no_sub_classes",
+ "query_counter",
+ "set_write_concern",
+ "set_read_write_concern",
+]
+
+class switch_db:
+ cls: Incomplete
+ collection: Incomplete
+ db_alias: Incomplete
+ ori_db_alias: Incomplete
+ def __init__(self, cls, db_alias) -> None: ...
+ def __enter__(self): ...
+ def __exit__(
+ self,
+ t: type[BaseException] | None,
+ value: BaseException | None,
+ traceback: types.TracebackType | None,
+ ) -> None: ...
+
+class switch_collection:
+ cls: Incomplete
+ ori_collection: Incomplete
+ ori_get_collection_name: Incomplete
+ collection_name: Incomplete
+ def __init__(self, cls, collection_name) -> None: ...
+ def __enter__(self): ...
+ def __exit__(
+ self,
+ t: type[BaseException] | None,
+ value: BaseException | None,
+ traceback: types.TracebackType | None,
+ ) -> None: ...
+
+class no_dereference:
+ cls: Incomplete
+ deref_fields: Incomplete
+ def __init__(self, cls) -> None: ...
+ def __enter__(self): ...
+ def __exit__(
+ self,
+ t: type[BaseException] | None,
+ value: BaseException | None,
+ traceback: types.TracebackType | None,
+ ): ...
+
+class no_sub_classes:
+ cls: Incomplete
+ cls_initial_subclasses: Incomplete
+ def __init__(self, cls) -> None: ...
+ def __enter__(self): ...
+ def __exit__(
+ self,
+ t: type[BaseException] | None,
+ value: BaseException | None,
+ traceback: types.TracebackType | None,
+ ) -> None: ...
+
+class query_counter:
+ db: Incomplete
+ initial_profiling_level: Incomplete
+ def __init__(self, alias=...) -> None: ...
+ def __enter__(self): ...
+ def __exit__(
+ self,
+ t: type[BaseException] | None,
+ value: BaseException | None,
+ traceback: types.TracebackType | None,
+ ) -> None: ...
+ def __eq__(self, value): ...
+ def __ne__(self, value): ...
+ def __lt__(self, value): ...
+ def __le__(self, value): ...
+ def __gt__(self, value): ...
+ def __ge__(self, value): ...
+ def __int__(self) -> int: ...
+
+def set_write_concern(
+ collection, write_concerns
+) -> Generator[Incomplete, None, None]: ...
+def set_read_write_concern(
+ collection, write_concerns, read_concerns
+) -> Generator[Incomplete, None, None]: ...
diff --git a/backend/typings/mongoengine/dereference.pyi b/backend/typings/mongoengine/dereference.pyi
new file mode 100644
index 00000000..3be09122
--- /dev/null
+++ b/backend/typings/mongoengine/dereference.pyi
@@ -0,0 +1,33 @@
+from _typeshed import Incomplete
+from mongoengine.base import (
+ BaseDict as BaseDict,
+ BaseList as BaseList,
+ EmbeddedDocumentList as EmbeddedDocumentList,
+ TopLevelDocumentMetaclass as TopLevelDocumentMetaclass,
+ get_document as get_document,
+)
+from mongoengine.base.datastructures import LazyReference as LazyReference
+from mongoengine.connection import get_db as get_db
+from mongoengine.document import (
+ Document as Document,
+ EmbeddedDocument as EmbeddedDocument,
+)
+from mongoengine.fields import (
+ DictField as DictField,
+ ListField as ListField,
+ MapField as MapField,
+ ReferenceField as ReferenceField,
+)
+from mongoengine.queryset import QuerySet as QuerySet
+
+class DeReference:
+ max_depth: Incomplete
+ reference_map: Incomplete
+ object_map: Incomplete
+ def __call__(
+ self,
+ items,
+ max_depth: int = 1,
+ instance: Incomplete | None = None,
+ name: Incomplete | None = None,
+ ): ...
diff --git a/backend/typings/mongoengine/document.pyi b/backend/typings/mongoengine/document.pyi
new file mode 100644
index 00000000..ef0c7cd2
--- /dev/null
+++ b/backend/typings/mongoengine/document.pyi
@@ -0,0 +1,89 @@
+from _typeshed import Incomplete
+from mongoengine.base import BaseDocument, DocumentMetaclass, TopLevelDocumentMetaclass
+from mongoengine.queryset import (
+ NotUniqueError as NotUniqueError,
+ OperationError as OperationError,
+)
+
+__all__ = [
+ "Document",
+ "EmbeddedDocument",
+ "DynamicDocument",
+ "DynamicEmbeddedDocument",
+ "OperationError",
+ "InvalidCollectionError",
+ "NotUniqueError",
+ "MapReduceDocument",
+]
+
+class InvalidCollectionError(Exception): ...
+
+class EmbeddedDocument(BaseDocument, metaclass=DocumentMetaclass):
+ my_metaclass = DocumentMetaclass
+ __hash__: Incomplete
+ def __init__(self, *args, **kwargs) -> None: ...
+ def __eq__(self, other): ...
+ def __ne__(self, other): ...
+ def to_mongo(self, *args, **kwargs): ...
+
+class Document(BaseDocument, metaclass=TopLevelDocumentMetaclass):
+ my_metaclass = TopLevelDocumentMetaclass
+ @property
+ def pk(self): ...
+ @pk.setter
+ def pk(self, value): ...
+ def __hash__(self): ...
+ def to_mongo(self, *args, **kwargs): ...
+ def modify(self, query: Incomplete | None = None, **update): ...
+ def save(
+ self,
+ force_insert: bool = False,
+ validate: bool = True,
+ clean: bool = True,
+ write_concern: Incomplete | None = None,
+ cascade: Incomplete | None = None,
+ cascade_kwargs: Incomplete | None = None,
+ _refs: Incomplete | None = None,
+ save_condition: Incomplete | None = None,
+ signal_kwargs: Incomplete | None = None,
+ **kwargs
+ ): ...
+ def cascade_save(self, **kwargs) -> None: ...
+ def update(self, **kwargs): ...
+ def delete(
+ self, signal_kwargs: Incomplete | None = None, **write_concern
+ ) -> None: ...
+ def switch_db(self, db_alias, keep_created: bool = True): ...
+ def switch_collection(self, collection_name, keep_created: bool = True): ...
+ def select_related(self, max_depth: int = 1): ...
+ def reload(self, *fields, **kwargs): ...
+ def to_dbref(self): ...
+ @classmethod
+ def register_delete_rule(cls, document_cls, field_name, rule) -> None: ...
+ @classmethod
+ def drop_collection(cls) -> None: ...
+ @classmethod
+ def create_index(cls, keys, background: bool = False, **kwargs): ...
+ @classmethod
+ def ensure_indexes(cls) -> None: ...
+ @classmethod
+ def list_indexes(cls): ...
+ @classmethod
+ def compare_indexes(cls): ...
+ @staticmethod
+ def objects(**kwargs): ...
+
+class DynamicDocument(Document, metaclass=TopLevelDocumentMetaclass):
+ my_metaclass = TopLevelDocumentMetaclass
+ def __delattr__(self, *args, **kwargs) -> None: ...
+
+class DynamicEmbeddedDocument(EmbeddedDocument, metaclass=DocumentMetaclass):
+ my_metaclass = DocumentMetaclass
+ def __delattr__(self, *args, **kwargs) -> None: ...
+
+class MapReduceDocument:
+ key: Incomplete
+ value: Incomplete
+ def __init__(self, document, collection, key, value) -> None: ...
+ @property
+ def object(self): ...
diff --git a/backend/typings/mongoengine/errors.pyi b/backend/typings/mongoengine/errors.pyi
new file mode 100644
index 00000000..6fdbbf34
--- /dev/null
+++ b/backend/typings/mongoengine/errors.pyi
@@ -0,0 +1,40 @@
+from _typeshed import Incomplete
+
+__all__ = [
+ "NotRegistered",
+ "InvalidDocumentError",
+ "LookUpError",
+ "DoesNotExist",
+ "MultipleObjectsReturned",
+ "InvalidQueryError",
+ "OperationError",
+ "NotUniqueError",
+ "BulkWriteError",
+ "FieldDoesNotExist",
+ "ValidationError",
+ "SaveConditionError",
+ "DeprecatedError",
+]
+
+class MongoEngineException(Exception): ...
+class NotRegistered(MongoEngineException): ...
+class InvalidDocumentError(MongoEngineException): ...
+class LookUpError(AttributeError): ...
+class DoesNotExist(MongoEngineException): ...
+class MultipleObjectsReturned(MongoEngineException): ...
+class InvalidQueryError(MongoEngineException): ...
+class OperationError(MongoEngineException): ...
+class NotUniqueError(OperationError): ...
+class BulkWriteError(OperationError): ...
+class SaveConditionError(OperationError): ...
+class FieldDoesNotExist(MongoEngineException): ...
+
+class ValidationError(AssertionError):
+ errors: Incomplete
+ field_name: Incomplete
+ message: Incomplete
+ def __init__(self, message: str = "", **kwargs) -> None: ...
+ def __getattribute__(self, name): ...
+ def to_dict(self): ...
+
+class DeprecatedError(MongoEngineException): ...
diff --git a/backend/typings/mongoengine/fields.pyi b/backend/typings/mongoengine/fields.pyi
new file mode 100644
index 00000000..7cb9937f
--- /dev/null
+++ b/backend/typings/mongoengine/fields.pyi
@@ -0,0 +1,463 @@
+from _typeshed import Incomplete
+from mongoengine.base import (
+ BaseField,
+ ComplexBaseField,
+ GeoJsonBaseField as GeoJsonBaseField,
+ ObjectIdField as ObjectIdField,
+)
+
+__all__ = [
+ "StringField",
+ "URLField",
+ "EmailField",
+ "IntField",
+ "LongField",
+ "FloatField",
+ "DecimalField",
+ "BooleanField",
+ "DateTimeField",
+ "DateField",
+ "ComplexDateTimeField",
+ "EmbeddedDocumentField",
+ "ObjectIdField",
+ "GenericEmbeddedDocumentField",
+ "DynamicField",
+ "ListField",
+ "SortedListField",
+ "EmbeddedDocumentListField",
+ "DictField",
+ "MapField",
+ "ReferenceField",
+ "CachedReferenceField",
+ "LazyReferenceField",
+ "GenericLazyReferenceField",
+ "GenericReferenceField",
+ "BinaryField",
+ "GridFSError",
+ "GridFSProxy",
+ "FileField",
+ "ImageGridFsProxy",
+ "ImproperlyConfigured",
+ "ImageField",
+ "GeoPointField",
+ "PointField",
+ "LineStringField",
+ "PolygonField",
+ "SequenceField",
+ "UUIDField",
+ "EnumField",
+ "MultiPointField",
+ "MultiLineStringField",
+ "MultiPolygonField",
+ "GeoJsonBaseField",
+ "Decimal128Field",
+]
+
+class StringField(BaseField):
+ regex: Incomplete
+ max_length: Incomplete
+ min_length: Incomplete
+ def __init__(
+ self,
+ regex: Incomplete | None = None,
+ max_length: Incomplete | None = None,
+ min_length: Incomplete | None = None,
+ **kwargs
+ ) -> None: ...
+ def to_python(self, value): ...
+ def validate(self, value) -> None: ...
+ def lookup_member(self, member_name) -> None: ...
+ def prepare_query_value(self, op, value): ...
+
+class URLField(StringField):
+ url_regex: Incomplete
+ schemes: Incomplete
+ def __init__(
+ self,
+ url_regex: Incomplete | None = None,
+ schemes: Incomplete | None = None,
+ **kwargs
+ ) -> None: ...
+ def validate(self, value) -> None: ...
+
+class EmailField(StringField):
+ USER_REGEX: Incomplete
+ UTF8_USER_REGEX: Incomplete
+ DOMAIN_REGEX: Incomplete
+ error_msg: str
+ domain_whitelist: Incomplete
+ allow_utf8_user: Incomplete
+ allow_ip_domain: Incomplete
+ def __init__(
+ self,
+ domain_whitelist: Incomplete | None = None,
+ allow_utf8_user: bool = False,
+ allow_ip_domain: bool = False,
+ *args,
+ **kwargs
+ ) -> None: ...
+ def validate_user_part(self, user_part): ...
+ def validate_domain_part(self, domain_part): ...
+ def validate(self, value) -> None: ...
+
+class IntField(BaseField):
+ def __init__(
+ self,
+ min_value: Incomplete | None = None,
+ max_value: Incomplete | None = None,
+ **kwargs
+ ) -> None: ...
+ def to_python(self, value): ...
+ def validate(self, value) -> None: ...
+ def prepare_query_value(self, op, value): ...
+
+class LongField(IntField):
+ def to_mongo(self, value): ...
+
+class FloatField(BaseField):
+ def __init__(
+ self,
+ min_value: Incomplete | None = None,
+ max_value: Incomplete | None = None,
+ **kwargs
+ ) -> None: ...
+ def to_python(self, value): ...
+ def validate(self, value) -> None: ...
+ def prepare_query_value(self, op, value): ...
+
+class DecimalField(BaseField):
+ min_value: Incomplete
+ max_value: Incomplete
+ force_string: Incomplete
+ precision: Incomplete
+ rounding: Incomplete
+ def __init__(
+ self,
+ min_value: Incomplete | None = None,
+ max_value: Incomplete | None = None,
+ force_string: bool = False,
+ precision: int = 2,
+ rounding=...,
+ **kwargs
+ ) -> None: ...
+ def to_python(self, value): ...
+ def to_mongo(self, value): ...
+ def validate(self, value) -> None: ...
+ def prepare_query_value(self, op, value): ...
+
+class BooleanField(BaseField):
+ def to_python(self, value): ...
+ def validate(self, value) -> None: ...
+
+class DateTimeField(BaseField):
+ def validate(self, value) -> None: ...
+ def to_mongo(self, value): ...
+ def prepare_query_value(self, op, value): ...
+
+class DateField(DateTimeField):
+ def to_mongo(self, value): ...
+ def to_python(self, value): ...
+
+class ComplexDateTimeField(StringField):
+ separator: Incomplete
+ format: Incomplete
+ def __init__(self, separator: str = ",", **kwargs) -> None: ...
+ def __get__(self, instance, owner): ...
+ def __set__(self, instance, value) -> None: ...
+ def validate(self, value) -> None: ...
+ def to_python(self, value): ...
+ def to_mongo(self, value): ...
+ def prepare_query_value(self, op, value): ...
+
+class EmbeddedDocumentField(BaseField):
+ document_type_obj: Incomplete
+ def __init__(self, document_type, **kwargs) -> None: ...
+ @property
+ def document_type(self): ...
+ def to_python(self, value): ...
+ def to_mongo(
+ self, value, use_db_field: bool = True, fields: Incomplete | None = None
+ ): ...
+ def validate(self, value, clean: bool = True) -> None: ...
+ def lookup_member(self, member_name): ...
+ def prepare_query_value(self, op, value): ...
+
+class GenericEmbeddedDocumentField(BaseField):
+ def prepare_query_value(self, op, value): ...
+ def to_python(self, value): ...
+ def validate(self, value, clean: bool = True): ...
+ def lookup_member(self, member_name): ...
+ def to_mongo(
+ self, document, use_db_field: bool = True, fields: Incomplete | None = None
+ ): ...
+
+class DynamicField(BaseField):
+ def to_mongo(
+ self, value, use_db_field: bool = True, fields: Incomplete | None = None
+ ): ...
+ def to_python(self, value): ...
+ def lookup_member(self, member_name): ...
+ def prepare_query_value(self, op, value): ...
+ def validate(self, value, clean: bool = True) -> None: ...
+
+class ListField(ComplexBaseField):
+ max_length: Incomplete
+ def __init__(
+ self,
+ field: Incomplete | None = None,
+ max_length: Incomplete | None = None,
+ **kwargs
+ ) -> None: ...
+ def __get__(self, instance, owner): ...
+ def validate(self, value) -> None: ...
+ def prepare_query_value(self, op, value): ...
+
+class EmbeddedDocumentListField(ListField):
+ def __init__(self, document_type, **kwargs) -> None: ...
+
+class SortedListField(ListField):
+ def __init__(self, field, **kwargs) -> None: ...
+ def to_mongo(
+ self, value, use_db_field: bool = True, fields: Incomplete | None = None
+ ): ...
+
+class DictField(ComplexBaseField):
+ def __init__(self, field: Incomplete | None = None, *args, **kwargs) -> None: ...
+ def validate(self, value) -> None: ...
+ def lookup_member(self, member_name): ...
+ def prepare_query_value(self, op, value): ...
+
+class MapField(DictField):
+ def __init__(self, field: Incomplete | None = None, *args, **kwargs) -> None: ...
+
+class ReferenceField(BaseField):
+ dbref: Incomplete
+ document_type_obj: Incomplete
+ reverse_delete_rule: Incomplete
+ def __init__(
+ self, document_type, dbref: bool = False, reverse_delete_rule=..., **kwargs
+ ) -> None: ...
+ @property
+ def document_type(self): ...
+ def __get__(self, instance, owner): ...
+ def to_mongo(self, document): ...
+ def to_python(self, value): ...
+ def prepare_query_value(self, op, value): ...
+ def validate(self, value) -> None: ...
+ def lookup_member(self, member_name): ...
+
+class CachedReferenceField(BaseField):
+ auto_sync: Incomplete
+ document_type_obj: Incomplete
+ fields: Incomplete
+ def __init__(
+ self,
+ document_type,
+ fields: Incomplete | None = None,
+ auto_sync: bool = True,
+ **kwargs
+ ) -> None: ...
+ def start_listener(self) -> None: ...
+ def on_document_pre_save(self, sender, document, created, **kwargs) -> None: ...
+ def to_python(self, value): ...
+ @property
+ def document_type(self): ...
+ def __get__(self, instance, owner): ...
+ def to_mongo(
+ self, document, use_db_field: bool = True, fields: Incomplete | None = None
+ ): ...
+ def prepare_query_value(self, op, value): ...
+ def validate(self, value) -> None: ...
+ def lookup_member(self, member_name): ...
+ def sync_all(self) -> None: ...
+
+class GenericReferenceField(BaseField):
+ choices: Incomplete
+ def __init__(self, *args, **kwargs) -> None: ...
+ def __get__(self, instance, owner): ...
+ def validate(self, value) -> None: ...
+ def to_mongo(self, document): ...
+ def prepare_query_value(self, op, value): ...
+
+class BinaryField(BaseField):
+ max_bytes: Incomplete
+ def __init__(self, max_bytes: Incomplete | None = None, **kwargs) -> None: ...
+ def __set__(self, instance, value): ...
+ def to_mongo(self, value): ...
+ def validate(self, value) -> None: ...
+ def prepare_query_value(self, op, value): ...
+
+class EnumField(BaseField):
+ def __init__(self, enum, **kwargs) -> None: ...
+ def validate(self, value): ...
+ def to_python(self, value): ...
+ def __set__(self, instance, value): ...
+ def to_mongo(self, value): ...
+ def prepare_query_value(self, op, value): ...
+
+class GridFSError(Exception): ...
+
+class GridFSProxy:
+ grid_id: Incomplete
+ key: Incomplete
+ instance: Incomplete
+ db_alias: Incomplete
+ collection_name: Incomplete
+ newfile: Incomplete
+ gridout: Incomplete
+ def __init__(
+ self,
+ grid_id: Incomplete | None = None,
+ key: Incomplete | None = None,
+ instance: Incomplete | None = None,
+ db_alias=...,
+ collection_name: str = "fs",
+ ) -> None: ...
+ def __getattr__(self, name): ...
+ def __get__(self, instance, value): ...
+ def __bool__(self) -> bool: ...
+ def __copy__(self): ...
+ def __deepcopy__(self, memo): ...
+ def __eq__(self, other): ...
+ def __ne__(self, other): ...
+ @property
+ def fs(self): ...
+ def get(self, grid_id: Incomplete | None = None): ...
+ def new_file(self, **kwargs) -> None: ...
+ def put(self, file_obj, **kwargs) -> None: ...
+ def write(self, string) -> None: ...
+ def writelines(self, lines) -> None: ...
+ def read(self, size: int = -1): ...
+ def delete(self) -> None: ...
+ def replace(self, file_obj, **kwargs) -> None: ...
+ def close(self) -> None: ...
+
+class FileField(BaseField):
+ proxy_class = GridFSProxy
+ collection_name: Incomplete
+ db_alias: Incomplete
+ def __init__(self, db_alias=..., collection_name: str = "fs", **kwargs) -> None: ...
+ def __get__(self, instance, owner): ...
+ def __set__(self, instance, value) -> None: ...
+ def get_proxy_obj(
+ self,
+ key,
+ instance,
+ db_alias: Incomplete | None = None,
+ collection_name: Incomplete | None = None,
+ ): ...
+ def to_mongo(self, value): ...
+ def to_python(self, value): ...
+ def validate(self, value) -> None: ...
+
+class ImageGridFsProxy(GridFSProxy):
+ def put(self, file_obj, **kwargs): ...
+ def delete(self, *args, **kwargs): ...
+ @property
+ def size(self): ...
+ @property
+ def format(self): ...
+ @property
+ def thumbnail(self): ...
+ def write(self, *args, **kwargs) -> None: ...
+ def writelines(self, *args, **kwargs) -> None: ...
+
+class ImproperlyConfigured(Exception): ...
+
+class ImageField(FileField):
+ proxy_class = ImageGridFsProxy
+ def __init__(
+ self,
+ size: Incomplete | None = None,
+ thumbnail_size: Incomplete | None = None,
+ collection_name: str = "images",
+ **kwargs
+ ) -> None: ...
+
+class SequenceField(BaseField):
+ COLLECTION_NAME: str
+ VALUE_DECORATOR = int
+ collection_name: Incomplete
+ db_alias: Incomplete
+ sequence_name: Incomplete
+ value_decorator: Incomplete
+ def __init__(
+ self,
+ collection_name: Incomplete | None = None,
+ db_alias: Incomplete | None = None,
+ sequence_name: Incomplete | None = None,
+ value_decorator: Incomplete | None = None,
+ *args,
+ **kwargs
+ ) -> None: ...
+ def generate(self): ...
+ def set_next_value(self, value): ...
+ def get_next_value(self): ...
+ def get_sequence_name(self): ...
+ def __get__(self, instance, owner): ...
+ def __set__(self, instance, value): ...
+ def prepare_query_value(self, op, value): ...
+ def to_python(self, value): ...
+
+class UUIDField(BaseField):
+ def __init__(self, binary: bool = True, **kwargs) -> None: ...
+ def to_python(self, value): ...
+ def to_mongo(self, value): ...
+ def prepare_query_value(self, op, value): ...
+ def validate(self, value) -> None: ...
+
+class GeoPointField(BaseField):
+ def validate(self, value) -> None: ...
+
+class PointField(GeoJsonBaseField): ...
+class LineStringField(GeoJsonBaseField): ...
+class PolygonField(GeoJsonBaseField): ...
+class MultiPointField(GeoJsonBaseField): ...
+class MultiLineStringField(GeoJsonBaseField): ...
+class MultiPolygonField(GeoJsonBaseField): ...
+
+class LazyReferenceField(BaseField):
+ dbref: Incomplete
+ passthrough: Incomplete
+ document_type_obj: Incomplete
+ reverse_delete_rule: Incomplete
+ def __init__(
+ self,
+ document_type,
+ passthrough: bool = False,
+ dbref: bool = False,
+ reverse_delete_rule=...,
+ **kwargs
+ ) -> None: ...
+ @property
+ def document_type(self): ...
+ def build_lazyref(self, value): ...
+ def __get__(self, instance, owner): ...
+ def to_mongo(self, value): ...
+ def to_python(self, value): ...
+ def validate(self, value) -> None: ...
+ def prepare_query_value(self, op, value): ...
+ def lookup_member(self, member_name): ...
+
+class GenericLazyReferenceField(GenericReferenceField):
+ passthrough: Incomplete
+ def __init__(self, *args, **kwargs) -> None: ...
+ def build_lazyref(self, value): ...
+ def __get__(self, instance, owner): ...
+ def validate(self, value): ...
+ def to_mongo(self, document): ...
+
+class Decimal128Field(BaseField):
+ DECIMAL_CONTEXT: Incomplete
+ min_value: Incomplete
+ max_value: Incomplete
+ def __init__(
+ self,
+ min_value: Incomplete | None = None,
+ max_value: Incomplete | None = None,
+ **kwargs
+ ) -> None: ...
+ def to_mongo(self, value): ...
+ def to_python(self, value): ...
+ def validate(self, value) -> None: ...
+ def prepare_query_value(self, op, value): ...
diff --git a/backend/typings/mongoengine/mongodb_support.pyi b/backend/typings/mongoengine/mongodb_support.pyi
new file mode 100644
index 00000000..f12c224b
--- /dev/null
+++ b/backend/typings/mongoengine/mongodb_support.pyi
@@ -0,0 +1,9 @@
+from _typeshed import Incomplete
+from mongoengine.connection import get_connection as get_connection
+
+MONGODB_34: Incomplete
+MONGODB_36: Incomplete
+MONGODB_42: Incomplete
+MONGODB_44: Incomplete
+
+def get_mongodb_version(): ...
diff --git a/backend/typings/mongoengine/pymongo_support.pyi b/backend/typings/mongoengine/pymongo_support.pyi
new file mode 100644
index 00000000..811f1ba0
--- /dev/null
+++ b/backend/typings/mongoengine/pymongo_support.pyi
@@ -0,0 +1,14 @@
+from _typeshed import Incomplete
+
+PYMONGO_VERSION: Incomplete
+LEGACY_JSON_OPTIONS: Incomplete
+
+def count_documents(
+ collection,
+ filter,
+ skip: Incomplete | None = None,
+ limit: Incomplete | None = None,
+ hint: Incomplete | None = None,
+ collation: Incomplete | None = None,
+): ...
+def list_collection_names(db, include_system_collections: bool = False): ...
diff --git a/backend/typings/mongoengine/queryset/__init__.pyi b/backend/typings/mongoengine/queryset/__init__.pyi
new file mode 100644
index 00000000..cc1c705c
--- /dev/null
+++ b/backend/typings/mongoengine/queryset/__init__.pyi
@@ -0,0 +1,43 @@
+from mongoengine.errors import *
+from mongoengine.queryset.field_list import *
+from mongoengine.queryset.manager import *
+from mongoengine.queryset.queryset import *
+from mongoengine.queryset.transform import *
+from mongoengine.queryset.visitor import *
+
+__all__ = [
+ "QuerySet",
+ "QuerySetNoCache",
+ "Q",
+ "queryset_manager",
+ "QuerySetManager",
+ "QueryFieldList",
+ "DO_NOTHING",
+ "NULLIFY",
+ "CASCADE",
+ "DENY",
+ "PULL",
+ "DoesNotExist",
+ "InvalidQueryError",
+ "MultipleObjectsReturned",
+ "NotUniqueError",
+ "OperationError",
+]
+
+# Names in __all__ with no definition:
+# CASCADE
+# DENY
+# DO_NOTHING
+# DoesNotExist
+# InvalidQueryError
+# MultipleObjectsReturned
+# NULLIFY
+# NotUniqueError
+# OperationError
+# PULL
+# Q
+# QueryFieldList
+# QuerySet
+# QuerySetManager
+# QuerySetNoCache
+# queryset_manager
diff --git a/backend/typings/mongoengine/queryset/base.pyi b/backend/typings/mongoengine/queryset/base.pyi
new file mode 100644
index 00000000..d02248e6
--- /dev/null
+++ b/backend/typings/mongoengine/queryset/base.pyi
@@ -0,0 +1,120 @@
+from _typeshed import Incomplete
+from collections.abc import Generator
+
+__all__ = ["BaseQuerySet", "DO_NOTHING", "NULLIFY", "CASCADE", "DENY", "PULL"]
+
+DO_NOTHING: int
+NULLIFY: int
+CASCADE: int
+DENY: int
+PULL: int
+
+class BaseQuerySet:
+ def __init__(self, document, collection) -> None: ...
+ def __call__(self, q_obj: Incomplete | None = None, **query): ...
+ def __getitem__(self, key): ...
+ def __iter__(self): ...
+ def __bool__(self) -> bool: ...
+ def all(self): ...
+ def filter(self, *q_objs, **query): ...
+ def search_text(self, text, language: Incomplete | None = None): ...
+ def get(self, *q_objs, **query): ...
+ def create(self, **kwargs): ...
+ def first(self): ...
+ def insert(
+ self,
+ doc_or_docs,
+ load_bulk: bool = True,
+ write_concern: Incomplete | None = None,
+ signal_kwargs: Incomplete | None = None,
+ ): ...
+ def count(self, with_limit_and_skip: bool = False): ...
+ def delete(
+ self,
+ write_concern: Incomplete | None = None,
+ _from_doc_delete: bool = False,
+ cascade_refs: Incomplete | None = None,
+ ): ...
+ def update(
+ self,
+ upsert: bool = False,
+ multi: bool = True,
+ write_concern: Incomplete | None = None,
+ read_concern: Incomplete | None = None,
+ full_result: bool = False,
+ **update
+ ): ...
+ def upsert_one(
+ self,
+ write_concern: Incomplete | None = None,
+ read_concern: Incomplete | None = None,
+ **update
+ ): ...
+ def update_one(
+ self,
+ upsert: bool = False,
+ write_concern: Incomplete | None = None,
+ full_result: bool = False,
+ **update
+ ): ...
+ def modify(
+ self,
+ upsert: bool = False,
+ full_response: bool = False,
+ remove: bool = False,
+ new: bool = False,
+ **update
+ ): ...
+ def with_id(self, object_id): ...
+ def in_bulk(self, object_ids): ...
+ def none(self): ...
+ def no_sub_classes(self): ...
+ def using(self, alias): ...
+ def clone(self): ...
+ def select_related(self, max_depth: int = 1): ...
+ def limit(self, n): ...
+ def skip(self, n): ...
+ def hint(self, index: Incomplete | None = None): ...
+ def collation(self, collation: Incomplete | None = None): ...
+ def batch_size(self, size): ...
+ def distinct(self, field): ...
+ def only(self, *fields): ...
+ def exclude(self, *fields): ...
+ def fields(self, _only_called: bool = False, **kwargs): ...
+ def all_fields(self): ...
+ def order_by(self, *keys): ...
+ def clear_cls_query(self): ...
+ def comment(self, text): ...
+ def explain(self): ...
+ def snapshot(self, enabled): ...
+ def allow_disk_use(self, enabled): ...
+ def timeout(self, enabled): ...
+ def read_preference(self, read_preference): ...
+ def read_concern(self, read_concern): ...
+ def scalar(self, *fields): ...
+ def values_list(self, *fields): ...
+ def as_pymongo(self): ...
+ def max_time_ms(self, ms): ...
+ def to_json(self, *args, **kwargs): ...
+ def from_json(self, json_data): ...
+ def aggregate(self, pipeline, *suppl_pipeline, **kwargs): ...
+ def map_reduce(
+ self,
+ map_f,
+ reduce_f,
+ output,
+ finalize_f: Incomplete | None = None,
+ limit: Incomplete | None = None,
+ scope: Incomplete | None = None,
+ ) -> Generator[Incomplete, None, None]: ...
+ def exec_js(self, code, *fields, **options): ...
+ def where(self, where_clause): ...
+ def sum(self, field): ...
+ def average(self, field): ...
+ def item_frequencies(
+ self, field, normalize: bool = False, map_reduce: bool = True
+ ): ...
+ def __next__(self): ...
+ def rewind(self) -> None: ...
+ def __deepcopy__(self, memo): ...
+ def no_dereference(self): ...
diff --git a/backend/typings/mongoengine/queryset/field_list.pyi b/backend/typings/mongoengine/queryset/field_list.pyi
new file mode 100644
index 00000000..e6e8cfc3
--- /dev/null
+++ b/backend/typings/mongoengine/queryset/field_list.pyi
@@ -0,0 +1,22 @@
+from _typeshed import Incomplete
+
+__all__ = ["QueryFieldList"]
+
+class QueryFieldList:
+ ONLY: int
+ EXCLUDE: int
+ value: Incomplete
+ fields: Incomplete
+ always_include: Incomplete
+ slice: Incomplete
+ def __init__(
+ self,
+ fields: Incomplete | None = None,
+ value=...,
+ always_include: Incomplete | None = None,
+ _only_called: bool = False,
+ ) -> None: ...
+ def __add__(self, f): ...
+ def __bool__(self) -> bool: ...
+ def as_dict(self): ...
+ def reset(self) -> None: ...
diff --git a/backend/typings/mongoengine/queryset/manager.pyi b/backend/typings/mongoengine/queryset/manager.pyi
new file mode 100644
index 00000000..aa641461
--- /dev/null
+++ b/backend/typings/mongoengine/queryset/manager.pyi
@@ -0,0 +1,12 @@
+from _typeshed import Incomplete
+from mongoengine.queryset.queryset import QuerySet
+
+__all__ = ["queryset_manager", "QuerySetManager"]
+
+class QuerySetManager:
+ get_queryset: Incomplete
+ default = QuerySet
+ def __init__(self, queryset_func: Incomplete | None = None) -> None: ...
+ def __get__(self, instance, owner): ...
+
+def queryset_manager(func): ...
diff --git a/backend/typings/mongoengine/queryset/queryset.pyi b/backend/typings/mongoengine/queryset/queryset.pyi
new file mode 100644
index 00000000..ad2ddd08
--- /dev/null
+++ b/backend/typings/mongoengine/queryset/queryset.pyi
@@ -0,0 +1,28 @@
+from mongoengine.queryset.base import (
+ BaseQuerySet,
+ CASCADE as CASCADE,
+ DENY as DENY,
+ DO_NOTHING as DO_NOTHING,
+ NULLIFY as NULLIFY,
+ PULL as PULL,
+)
+
+__all__ = [
+ "QuerySet",
+ "QuerySetNoCache",
+ "DO_NOTHING",
+ "NULLIFY",
+ "CASCADE",
+ "DENY",
+ "PULL",
+]
+
+class QuerySet(BaseQuerySet):
+ def __iter__(self): ...
+ def __len__(self) -> int: ...
+ def count(self, with_limit_and_skip: bool = False): ...
+ def no_cache(self): ...
+
+class QuerySetNoCache(BaseQuerySet):
+ def cache(self): ...
+ def __iter__(self): ...
diff --git a/backend/typings/mongoengine/queryset/transform.pyi b/backend/typings/mongoengine/queryset/transform.pyi
new file mode 100644
index 00000000..8c217685
--- /dev/null
+++ b/backend/typings/mongoengine/queryset/transform.pyi
@@ -0,0 +1,8 @@
+from _typeshed import Incomplete
+
+__all__ = ["query", "update", "STRING_OPERATORS"]
+
+STRING_OPERATORS: Incomplete
+
+def query(_doc_cls: Incomplete | None = None, **kwargs): ...
+def update(_doc_cls: Incomplete | None = None, **update): ...
diff --git a/backend/typings/mongoengine/queryset/visitor.pyi b/backend/typings/mongoengine/queryset/visitor.pyi
new file mode 100644
index 00000000..729f0405
--- /dev/null
+++ b/backend/typings/mongoengine/queryset/visitor.pyi
@@ -0,0 +1,48 @@
+from _typeshed import Incomplete
+from mongoengine.errors import InvalidQueryError
+
+__all__ = ["Q", "QNode"]
+
+class QNodeVisitor:
+ def visit_combination(self, combination): ...
+ def visit_query(self, query): ...
+
+class DuplicateQueryConditionsError(InvalidQueryError): ...
+
+class SimplificationVisitor(QNodeVisitor):
+ def visit_combination(self, combination): ...
+
+class QueryCompilerVisitor(QNodeVisitor):
+ document: Incomplete
+ def __init__(self, document) -> None: ...
+ def visit_combination(self, combination): ...
+ def visit_query(self, query): ...
+
+class QNode:
+ AND: int
+ OR: int
+ def to_query(self, document): ...
+ def accept(self, visitor) -> None: ...
+ @property
+ def empty(self): ...
+ def __or__(self, other): ...
+ def __and__(self, other): ...
+
+class QCombination(QNode):
+ operation: Incomplete
+ children: Incomplete
+ def __init__(self, operation, children) -> None: ...
+ def __bool__(self) -> bool: ...
+ def accept(self, visitor): ...
+ @property
+ def empty(self): ...
+ def __eq__(self, other): ...
+
+class Q(QNode):
+ query: Incomplete
+ def __init__(self, **query) -> None: ...
+ def __bool__(self) -> bool: ...
+ def __eq__(self, other): ...
+ def accept(self, visitor): ...
+ @property
+ def empty(self): ...
diff --git a/backend/typings/mongoengine/signals.pyi b/backend/typings/mongoengine/signals.pyi
new file mode 100644
index 00000000..856929e2
--- /dev/null
+++ b/backend/typings/mongoengine/signals.pyi
@@ -0,0 +1,33 @@
+from _typeshed import Incomplete
+
+__all__ = [
+ "pre_init",
+ "post_init",
+ "pre_save",
+ "pre_save_post_validation",
+ "post_save",
+ "pre_delete",
+ "post_delete",
+]
+
+class Namespace:
+ def signal(self, name, doc: Incomplete | None = None): ...
+
+class _FakeSignal:
+ name: Incomplete
+ __doc__: Incomplete
+ def __init__(self, name, doc: Incomplete | None = None) -> None: ...
+ send: Incomplete
+ connect: Incomplete
+ disconnect: Incomplete
+ has_receivers_for: Incomplete
+ receivers_for: Incomplete
+ temporarily_connected_to: Incomplete
+
+pre_init: Incomplete
+post_init: Incomplete
+pre_save: Incomplete
+pre_save_post_validation: Incomplete
+post_save: Incomplete
+pre_delete: Incomplete
+post_delete: Incomplete
diff --git a/e2e-tests/test_entity_gql.py b/e2e-tests/test_entity_gql.py
index d8bb055b..880e17f6 100644
--- a/e2e-tests/test_entity_gql.py
+++ b/e2e-tests/test_entity_gql.py
@@ -110,7 +110,7 @@ def create_entity(backend_url, auth_header, body, fs, file, filename_field):
enumField
fileName
}
- }
+ }
"""
# https://github.com/jaydenseric/graphql-multipart-request-spec
operations = json.dumps(
@@ -137,7 +137,7 @@ def create_entity(backend_url, auth_header, body, fs, file, filename_field):
boolField
enumField
}
- }
+ }
"""
response = requests.post(
f"{backend_url}/graphql",
diff --git a/e2e-tests/test_simple_entity_gql.py b/e2e-tests/test_simple_entity_gql.py
index 5951263e..1dacf704 100644
--- a/e2e-tests/test_simple_entity_gql.py
+++ b/e2e-tests/test_simple_entity_gql.py
@@ -59,7 +59,7 @@ def create_entity(backend_url, auth_header, body):
boolField
enumField
}
- }
+ }
"""
response = requests.post(
f"{backend_url}/graphql",
diff --git a/e2e-tests/test_user_gql.py b/e2e-tests/test_user_gql.py
index b75a796d..3e174154 100644
--- a/e2e-tests/test_user_gql.py
+++ b/e2e-tests/test_user_gql.py
@@ -78,7 +78,7 @@ def create_user(backend_url, auth_header, body):
email
role
}
- }
+ }
"""
response = requests.post(
f"{backend_url}/graphql",
@@ -104,7 +104,7 @@ def update_user(backend_url, auth_header, id, body):
email
role
}
- }
+ }
"""
response = requests.post(
f"{backend_url}/graphql",
diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js
index 2492c4b8..2bdb6ac7 100644
--- a/frontend/.eslintrc.js
+++ b/frontend/.eslintrc.js
@@ -20,14 +20,14 @@ module.exports = {
"airbnb",
"airbnb-typescript",
"prettier",
- "plugin:prettier/recommended",
+ // "plugin:prettier/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
],
rules: {
- "prettier/prettier": ["warn", { endOfLine: "auto" }],
+ // "prettier/prettier": ["warn", { endOfLine: "auto" }],
"react/require-default-props": "off",
"react/no-array-index-key": "off",
"jsx-a11y/click-events-have-key-events": "off",
@@ -41,6 +41,7 @@ module.exports = {
},
],
"sort-imports": ["error", { ignoreDeclarationSort: true }],
+ "prefer-destructuring": ["off"],
"import/order": [
"error",
{
@@ -57,6 +58,8 @@ module.exports = {
},
},
],
+ "import/prefer-default-export": ["off"],
+ "@typescript-eslint/naming-convention": "off",
},
ignorePatterns: ["build/*"],
};
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
index 38afd3ce..efa3710d 100644
--- a/frontend/Dockerfile
+++ b/frontend/Dockerfile
@@ -1,6 +1,5 @@
FROM node:20-slim
-
WORKDIR /app
COPY package.json yarn.lock ./
diff --git a/frontend/babel.config.js b/frontend/babel.config.js
new file mode 100644
index 00000000..721e8b82
--- /dev/null
+++ b/frontend/babel.config.js
@@ -0,0 +1 @@
+module.exports = { presets: ["@babel/preset-env"] };
diff --git a/frontend/package.json b/frontend/package.json
index 14ee70d5..99bc8321 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@babel/preset-env": "^7.22.14",
"@apollo/client": "^3.8.0",
"@chakra-ui/icons": "^2.0.17",
"@chakra-ui/react": "^2.4.1",
@@ -12,6 +13,7 @@
"@react-oauth/google": "^0.5.0",
"@rjsf/bootstrap-4": "^2.5.1",
"@rjsf/core": "^2.5.1",
+ "@table-library/react-table-library": "^4.1.4",
"@tanstack/react-table": "^8.7.0",
"apollo-upload-client": "^17.0.0",
"axios": "^0.21.1",
@@ -24,6 +26,7 @@
"react": "^18.2.0",
"react-bootstrap": "^1.5.2",
"react-dom": "^18.2.0",
+ "react-icons": "^4.11.0",
"react-json-schema": "^1.2.2",
"react-jsonschema-form": "^1.8.1",
"react-multi-date-picker": "^4.4.1",
@@ -35,8 +38,8 @@
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
- "test": "react-scripts test",
- "test:ci": " react-scripts test --watchAll=false",
+ "test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!@codemirror)/\"",
+ "test:ci": " react-scripts test --watchAll=false --transformIgnorePatterns \"node_modules/(?!@codemirror)/\" --verbose",
"eject": "react-scripts eject",
"lint": "eslint . --ext .ts,.tsx,.js,.jsx --cache",
"fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix --cache"
@@ -47,6 +50,11 @@
"react-app/jest"
]
},
+ "jest": {
+ "transform": {
+ "^.+\\.[t|j]sx?$": "babel-jest"
+ }
+ },
"browserslist": {
"production": [
">0.2%",
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 83bacb69..4da6f724 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -24,13 +24,21 @@ const App = (): React.ReactElement => {
// Providers for app-specific state like contexts are here.
// For providers for libraries like Apollo and OAuth, see index.tsx.
return (
-
-
-
-
-
-
-
+
);
};
diff --git a/frontend/src/Routes.tsx b/frontend/src/Routes.tsx
index e22b0dc0..934beac0 100644
--- a/frontend/src/Routes.tsx
+++ b/frontend/src/Routes.tsx
@@ -10,8 +10,8 @@ import Login from "./components/auth/Login";
import ResetPassword from "./components/auth/ResetPassword";
import SetPassword from "./components/auth/SetPassword";
import * as Paths from "./constants/Routes";
+import Dashboard from "./pages/ASPDashboard";
import CreatePage from "./pages/CreatePage";
-import Dashboard from "./pages/Dashboard";
import Default from "./pages/Default";
import DisplayPage from "./pages/DisplayPage";
import HooksDemo from "./pages/HooksDemo";
@@ -40,7 +40,7 @@ const Routes = (): React.ReactElement => (
}>
} />
- } />
+ } />
}
diff --git a/frontend/src/components/asp/requests/CreateMealRequest.tsx b/frontend/src/components/asp/requests/CreateMealRequest.tsx
index a129b388..d43318d4 100644
--- a/frontend/src/components/asp/requests/CreateMealRequest.tsx
+++ b/frontend/src/components/asp/requests/CreateMealRequest.tsx
@@ -1,3 +1,4 @@
+import { Center, Spinner, useToast } from "@chakra-ui/react";
import React, { useContext, useEffect, useState } from "react";
import type { Value } from "react-multi-date-picker";
import { Navigate } from "react-router-dom";
@@ -11,6 +12,7 @@ import TitleSection from "./TitleSection";
import { LOGIN_PAGE } from "../../../constants/Routes";
import AuthContext from "../../../contexts/AuthContext";
import { Contact, UserInfo } from "../../../types/UserTypes";
+import useGetOnsiteContacts from "../../../utils/useGetOnsiteContacts";
import ThreeStepForm from "../../common/ThreeStepForm";
const CreateMealRequest = (): React.ReactElement => {
@@ -45,10 +47,13 @@ const CreateMealRequest = (): React.ReactElement => {
authenticatedUser?.info || null,
);
+ const toast = useToast();
+ const [loading, setLoading] = useState(true);
// This is the list of available onsite staff
- const [availableStaff, setAvailableStaff] = useState>(
- userInfo ? JSON.parse(JSON.stringify(userInfo.onsiteContacts)) : [],
- );
+ const [availableOnsiteContacts, setAvailableOnsiteContacts] = useState<
+ Array
+ >([]);
+ useGetOnsiteContacts(toast, setAvailableOnsiteContacts, setLoading);
// User's address
const [address, setAddress] = useState(
@@ -86,6 +91,16 @@ const CreateMealRequest = (): React.ReactElement => {
return ;
}
+ if (loading) {
+ return (
+
+
+
+
+
+
+ );
+ }
return (
@@ -132,7 +147,7 @@ const CreateMealRequest = (): React.ReactElement => {
setDeliveryInstructions={setDeliveryInstructions}
onsiteStaff={onsiteStaff}
setOnsiteStaff={setOnsiteStaff}
- availableStaff={availableStaff}
+ availableStaff={availableOnsiteContacts}
handleBack={() => {}} // Will be assigned by three step form
handleNext={() => {}} // Will be assigned by three step form
/>
diff --git a/frontend/src/components/asp/requests/SchedulingFormReviewAndSubmit.tsx b/frontend/src/components/asp/requests/SchedulingFormReviewAndSubmit.tsx
index 0b9fcfcb..2be4145f 100644
--- a/frontend/src/components/asp/requests/SchedulingFormReviewAndSubmit.tsx
+++ b/frontend/src/components/asp/requests/SchedulingFormReviewAndSubmit.tsx
@@ -27,8 +27,9 @@ import React, { useState } from "react";
import { Value } from "react-multi-date-picker";
import { useNavigate } from "react-router-dom";
-import { DASHBOARD_PAGE } from "../../../constants/Routes";
-import { Contact } from "../../../types/UserTypes";
+import { ASP_DASHBOARD_PAGE } from "../../../constants/Routes";
+import { Contact, OnsiteContact } from "../../../types/UserTypes";
+import { logPossibleGraphQLError } from "../../../utils/GraphQLUtils";
import OnsiteStaffSection from "../../common/OnsiteStaffSection";
// Create the GraphQL mutation
@@ -38,7 +39,7 @@ const CREATE_MEAL_REQUEST = gql`
$numMeals: Int!
$dietaryRestrictions: String
$deliveryInstructions: String
- $onsiteStaff: [ContactInput!]!
+ $onsiteStaff: [String!]!
$scheduledDropOffTime: Time!
$mealRequestDates: [Date!]!
$userId: ID!
@@ -72,7 +73,7 @@ type SchedulingFormReviewAndSubmitProps = {
numMeals: number;
dietaryRestrictions: string;
deliveryInstructions: string;
- onsiteStaff: Contact[];
+ onsiteStaff: OnsiteContact[];
// User ID
userId: string;
@@ -111,7 +112,7 @@ const SchedulingFormReviewAndSubmit: React.FunctionComponent
staff.id),
// Format the scheduled drop off time with the current time zone
scheduledDropOffTime,
userId,
@@ -128,9 +129,10 @@ const SchedulingFormReviewAndSubmit: React.FunctionComponent {
- return (
+const TitleSection = (): React.ReactElement => (
{
);
-};
export default TitleSection;
diff --git a/frontend/src/components/auth/Join.tsx b/frontend/src/components/auth/Join.tsx
index cf2b64fb..4379a2ab 100644
--- a/frontend/src/components/auth/Join.tsx
+++ b/frontend/src/components/auth/Join.tsx
@@ -1,4 +1,4 @@
-import { gql, useMutation } from "@apollo/client";
+import { ApolloError, gql, useMutation } from "@apollo/client";
import {
Button,
Center,
@@ -15,12 +15,13 @@ import {
Textarea,
useToast,
} from "@chakra-ui/react";
+import { GraphQLError } from "graphql";
import React, { useContext, useState } from "react";
import { Navigate, useNavigate } from "react-router-dom";
import LargerBackgroundImage from "../../assets/largerbackground.png";
import {
- DASHBOARD_PAGE,
+ ASP_DASHBOARD_PAGE,
HOME_PAGE,
JOIN_SUCCESS_PAGE,
} from "../../constants/Routes";
@@ -31,6 +32,7 @@ import {
Role,
UserInfo,
} from "../../types/UserTypes";
+import { logPossibleGraphQLError } from "../../utils/GraphQLUtils";
import {
isNonNegativeInt,
isValidEmail,
@@ -81,11 +83,6 @@ const SIGNUP = gql`
phone
email
}
- onsiteContacts {
- name
- phone
- email
- }
}
dateSubmitted
status
@@ -124,370 +121,348 @@ const Join = (): React.ReactElement => {
const { authenticatedUser } = useContext(AuthContext);
if (authenticatedUser) {
- return ;
+ return ;
}
- const getTitleSection = (): React.ReactElement => {
- return (
- <>
- (
+ <>
+
+ Sign Up
+
+
+ Already have an account?{" "}
+
+ Login here
+
+
+ >
+ );
+
+ const getUserTypeSection = (): React.ReactElement => (
+
+
+
- Sign Up
-
-
+ setRole(radioVal as Role)}
+ value={role}
>
- Already have an account?{" "}
-
- Login here
-
-
- >
- );
- };
-
- const getUserTypeSection = (): React.ReactElement => {
- return (
-
-
-
- Type of user
-
- setRole(radioVal as Role)}
- value={role}
- >
-
-
- After School Program
-
-
- Meal Donor
-
-
-
-
-
- );
- };
+
+
+ After School Program
+
+
+ Meal Donor
+
+
+
+
+
+ );
- const getEmailSection = (): React.ReactElement => {
- return (
-
- (
+
+
+
-
- Email address
-
- setEmail(e.target.value)}
- placeholder={
- isWebView
- ? PLACEHOLDER_WEB_EXAMPLE_EMAIL
- : PLACEHOLDER_MOBILE_EXAMPLE_EMAIL
- }
- />
-
-
- );
- };
+ Email address
+
+ setEmail(e.target.value)}
+ placeholder={
+ isWebView
+ ? PLACEHOLDER_WEB_EXAMPLE_EMAIL
+ : PLACEHOLDER_MOBILE_EXAMPLE_EMAIL
+ }
+ />
+
+
+ );
- const getWebOrganizationSection = (): React.ReactElement => {
- return (
- <>
- Organization Information
-
-
-
-
- Name of organization
-
- setOrganizationName(e.target.value)}
- />
-
-
- {role === "ASP" && (
-
-
-
- Number of kids
-
- setNumKids(e.target.value)}
- />
-
-
- )}
- (
+ <>
+ Organization Information
+
+
+
+
+ Name of organization
+
+ setOrganizationName(e.target.value)}
+ />
+
+
+ {role === "ASP" && (
+
- Address of organization
+ Number of kids
setOrganizationAddress(e.target.value)}
+ type="number"
+ value={numKids}
+ placeholder={PLACEHOLDER_WEB_EXAMPLE_NUM_KIDS}
+ onChange={(e) => setNumKids(e.target.value)}
/>
-
-
+ )}
+
- Description of organization
+ Address of organization
-
- >
- );
- };
-
- const getMobileOrganizationSection = (): React.ReactElement => {
- return (
-
-
-
- Organization Information
+
+
+
+
+ Description of organization
-
-
-
- setOrganizationName(e.target.value)}
- />
-
-
- setOrganizationAddress(e.target.value)}
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_ADDRESS}
- />
-
- {role === "ASP" && (
-
- setNumKids(e.target.value)}
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_NUM_KIDS}
- />
-
- )}
-
-
-
+
- );
- };
+ >
+ );
- const getWebContactSection = (): React.ReactElement => {
- return (
- <>
- Contact Information
-
-
-
-
- 1. Primary contact name
-
-
- setPrimaryContact({ ...primaryContact, name: e.target.value })
- }
- />
-
-
-
-
-
-
- Phone number
-
-
- setPrimaryContact({
- ...primaryContact,
- phone: e.target.value,
- })
- }
- />
-
-
-
-
-
- Email address
-
-
- setPrimaryContact({
- ...primaryContact,
- email: e.target.value,
- })
- }
- />
-
-
-
-
- >
- );
- };
+ const getMobileOrganizationSection = (): React.ReactElement => (
+
+
+
+ Organization Information
+
- const getMobileContactSection = (): React.ReactElement => {
- return (
-
-
-
- Primary Contact
-
-
+
+
+ setOrganizationName(e.target.value)}
+ />
+
+
+ setOrganizationAddress(e.target.value)}
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_ADDRESS}
+ />
+
+ {role === "ASP" && (
- setPrimaryContact({ ...primaryContact, name: e.target.value })
- }
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_FULL_NAME}
+ type="number"
+ value={numKids}
+ onChange={(e) => setNumKids(e.target.value)}
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_NUM_KIDS}
/>
+ )}
+
+
+
+
+
+ );
+
+ const getWebContactSection = (): React.ReactElement => (
+ <>
+ Contact Information
+
+
+
+
+ 1. Primary contact name
+
+
+ setPrimaryContact({ ...primaryContact, name: e.target.value })
+ }
+ />
+
+
+
+
+ Phone number
setPrimaryContact({
...primaryContact,
phone: e.target.value,
})
}
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_PHONE_NUMBER}
/>
+
+
+ Email address
setPrimaryContact({
...primaryContact,
email: e.target.value,
})
}
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_EMAIL}
/>
-
+
- );
- };
+ >
+ );
+
+ const getMobileContactSection = (): React.ReactElement => (
+
+
+ Primary Contact
+
+
+
+ setPrimaryContact({ ...primaryContact, name: e.target.value })
+ }
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_FULL_NAME}
+ />
+
+
+
+ setPrimaryContact({
+ ...primaryContact,
+ phone: e.target.value,
+ })
+ }
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_PHONE_NUMBER}
+ />
+
+
+
+ setPrimaryContact({
+ ...primaryContact,
+ email: e.target.value,
+ })
+ }
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_EMAIL}
+ />
+
+
+
+
+ );
const handleSignUp = async (userInfo: UserInfo) => {
try {
@@ -503,6 +478,7 @@ const Join = (): React.ReactElement => {
});
// eslint-disable-next-line no-console
console.log(e);
+ logPossibleGraphQLError(e as ApolloError);
}
};
@@ -563,7 +539,7 @@ const Join = (): React.ReactElement => {
email: trimWhiteSpace(primaryContact.email),
phone: trimWhiteSpace(primaryContact.phone),
},
- onsiteContacts: onsiteInfo.map((obj) => ({
+ initialOnsiteContacts: onsiteInfo.map((obj) => ({
name: trimWhiteSpace(obj.name),
phone: trimWhiteSpace(obj.phone),
email: trimWhiteSpace(obj.email),
@@ -576,44 +552,42 @@ const Join = (): React.ReactElement => {
handleSignUp(request);
};
- const getSubmitSection = (): React.ReactElement => {
- return (
-
-
- Create Account
-
- (
+
+
+ Create Account
+
+
+ {"By selecting Create Account, you agree to FCK's "}
+ {/* TODO: replace HOME_PAGE with actual terms & conditions route */}
+
- {"By selecting Create Account, you agree to FCK's "}
- {/* TODO: replace HOME_PAGE with actual terms & conditions route */}
-
- Terms & Conditions
-
-
-
- );
- };
+ Terms & Conditions
+
+
+
+ );
return (
{
- return (
+const JoinSuccess = (): React.ReactElement => (
{
);
-};
export default JoinSuccess;
diff --git a/frontend/src/components/auth/Login.tsx b/frontend/src/components/auth/Login.tsx
index 03c51dd1..f95f19aa 100644
--- a/frontend/src/components/auth/Login.tsx
+++ b/frontend/src/components/auth/Login.tsx
@@ -1,4 +1,4 @@
-import { gql, useMutation } from "@apollo/client";
+import { ApolloError, gql, useMutation } from "@apollo/client";
import {
Box,
Button,
@@ -15,9 +15,14 @@ import { Link, Navigate } from "react-router-dom";
import authAPIClient from "../../APIClients/AuthAPIClient";
import BackgroundImage from "../../assets/background.png";
-import { DASHBOARD_PAGE, JOIN_PAGE } from "../../constants/Routes";
+import {
+ ASP_DASHBOARD_PAGE,
+ HOME_PAGE,
+ JOIN_PAGE,
+} from "../../constants/Routes";
import AuthContext from "../../contexts/AuthContext";
import { AuthenticatedUser, LoginData } from "../../types/UserTypes";
+import { logPossibleGraphQLError } from "../../utils/GraphQLUtils";
const LOGIN = gql`
mutation Login($email: String!, $password: String!, $idToken: String!) {
@@ -45,12 +50,12 @@ const LOGIN = gql`
phone
email
}
- onsiteContacts {
+ active
+ initialOnsiteContacts {
name
- phone
email
+ phone
}
- active
}
}
}
@@ -71,13 +76,14 @@ const Login = (): React.ReactElement => {
user = await authAPIClient.login(email, password, "", login);
setError(false);
} catch (e: unknown) {
+ logPossibleGraphQLError(e as ApolloError);
setError(true);
}
setAuthenticatedUser(user);
};
if (authenticatedUser) {
- return ;
+ return ;
}
return (
diff --git a/frontend/src/components/auth/SetPassword.tsx b/frontend/src/components/auth/SetPassword.tsx
index 4fa20495..71836279 100644
--- a/frontend/src/components/auth/SetPassword.tsx
+++ b/frontend/src/components/auth/SetPassword.tsx
@@ -16,6 +16,7 @@ import { useNavigate, useParams } from "react-router-dom";
import BackgroundImage from "../../assets/background.png";
import { LOGIN_PAGE } from "../../constants/Routes";
+import { logPossibleGraphQLError } from "../../utils/GraphQLUtils";
const SetPassword = (): React.ReactElement => {
const [notMatching, setNotMatching] = useState(false);
@@ -53,11 +54,6 @@ const SetPassword = (): React.ReactElement => {
phone
email
}
- onsiteContacts {
- name
- phone
- email
- }
}
dateSubmitted
status
@@ -95,11 +91,6 @@ const SetPassword = (): React.ReactElement => {
phone
email
}
- onsiteContacts {
- name
- phone
- email
- }
}
}
}
@@ -112,9 +103,7 @@ const SetPassword = (): React.ReactElement => {
const [register, { loading: registerLoading }] = useMutation(REGISTER_USER);
- const dataStatus = () => {
- return onboardingData?.getOnboardingRequestById?.status !== "Approved";
- };
+ const dataStatus = () => onboardingData?.getOnboardingRequestById?.status !== "Approved";
const handleRegister = async () => {
try {
@@ -147,6 +136,8 @@ const SetPassword = (): React.ReactElement => {
handleRegister();
};
+ logPossibleGraphQLError(onboardingError);
+
return (
{
const isWebView = useIsWebView();
return isWebView ? (
-
+
{
) : (
-
+
diff --git a/frontend/src/components/common/Header.tsx b/frontend/src/components/common/Header.tsx
index af63151c..6147d6ff 100644
--- a/frontend/src/components/common/Header.tsx
+++ b/frontend/src/components/common/Header.tsx
@@ -19,7 +19,7 @@ import greenGear from "../../assets/greenGear.svg";
import Logo from "../../assets/logo.png";
import whiteGear from "../../assets/whiteGear.svg";
import {
- DASHBOARD_PAGE,
+ ASP_DASHBOARD_PAGE,
HOME_PAGE,
LOGIN_PAGE,
SETTINGS_PAGE,
@@ -55,161 +55,157 @@ const Header = () => {
navigate(LOGIN_PAGE);
};
- const headerDesktop = (): React.ReactElement => {
- return (
-
-
- {
- navigate(HOME_PAGE);
- }}
+ const headerDesktop = (): React.ReactElement => (
+
+
+ {
+ navigate(HOME_PAGE);
+ }}
+ _hover={{
+ cursor: "pointer",
+ }}
+ />
+
+
+
-
-
- {
- navigate(DASHBOARD_PAGE);
- }}
- >
- Home
-
-
-
+ onClick={() => {
+ navigate(ASP_DASHBOARD_PAGE);
+ }}
+ >
+ Home
+
+
-
- {authenticatedUser && (
-
- setIsHovered(true)}
- onMouseLeave={() => setIsHovered(false)}
- onClick={() => {
- navigate(SETTINGS_PAGE);
- }}
- >
-
-
-
-
- )}
- );
- };
- const headerMobile = (): React.ReactElement => {
- return (
-
-
-
+ setIsHovered(true)}
+ onMouseLeave={() => setIsHovered(false)}
onClick={() => {
- navigate(HOME_PAGE);
+ navigate(SETTINGS_PAGE);
}}
+ >
+
+
+
+
+ )}
+
+ );
+
+ const headerMobile = (): React.ReactElement => (
+
+
+ {
+ navigate(HOME_PAGE);
+ }}
+ _hover={{
+ cursor: "pointer",
+ }}
+ />
+
+
+ {
+ navigate(ASP_DASHBOARD_PAGE);
}}
- />
-
-
-
+ Home
+
+
+
+
+
+ {authenticatedUser && (
+
+
+ }
color="gray.gray600"
bgColor="background.grey"
- _hover={{
- color: "gray.gray83",
- }}
- onClick={() => {
- navigate(DASHBOARD_PAGE);
- }}
- >
- Home
-
-
-
+ variant="desktop-button-bold"
+ />
+
+ }
+ onClick={() => {
+ navigate(SETTINGS_PAGE);
+ }}
+ >
+ Settings
+
+ } onClick={onLogOutClick}>
+ Log Out
+
+
+
-
- {authenticatedUser && (
-
-
- }
- color="gray.gray600"
- bgColor="background.grey"
- variant="desktop-button-bold"
- />
-
- }
- onClick={() => {
- navigate(SETTINGS_PAGE);
- }}
- >
- Settings
-
- } onClick={onLogOutClick}>
- Log Out
-
-
-
-
- )}
-
- );
- };
+ )}
+
+ );
return isWebView ? headerDesktop() : headerMobile();
};
diff --git a/frontend/src/components/common/LoadingSpinner.tsx b/frontend/src/components/common/LoadingSpinner.tsx
new file mode 100644
index 00000000..83a30255
--- /dev/null
+++ b/frontend/src/components/common/LoadingSpinner.tsx
@@ -0,0 +1,19 @@
+import { Flex, Spinner, Text } from "@chakra-ui/react";
+import React from "react";
+
+const LoadingSpinner = (): React.ReactElement => (
+
+
+ Loading...
+
+
+
+ );
+
+export default LoadingSpinner;
diff --git a/frontend/src/components/common/OnsiteStaffSection.tsx b/frontend/src/components/common/OnsiteStaffSection.tsx
index 946234f8..9af796c6 100644
--- a/frontend/src/components/common/OnsiteStaffSection.tsx
+++ b/frontend/src/components/common/OnsiteStaffSection.tsx
@@ -15,9 +15,9 @@ import {
Thead,
Tr,
} from "@chakra-ui/react";
-import React from "react";
+import React, { useState } from "react";
-import { Contact } from "../../types/UserTypes";
+import { Contact, OnsiteContact } from "../../types/UserTypes";
import { isValidEmail } from "../../utils/ValidationUtils";
import useIsWebView from "../../utils/useIsWebView";
@@ -41,79 +41,77 @@ const OnsiteTextInputRow = ({
setOnsiteInfo,
index,
attemptedSubmit,
-}: OnsiteTextInputRowProps): React.ReactElement => {
- return (
-
-
-
- {
- onsiteInfo[index].name = e.target.value;
- setOnsiteInfo([...onsiteInfo]);
- }}
- />
-
-
-
-
- {
- onsiteInfo[index].phone = e.target.value;
- setOnsiteInfo([...onsiteInfo]);
- }}
- />
-
-
-
-
- {
- onsiteInfo[index].email = e.target.value;
- setOnsiteInfo([...onsiteInfo]);
- }}
- />
-
+}: OnsiteTextInputRowProps): React.ReactElement => (
+
+
+
+ {
+ onsiteInfo[index].name = e.target.value;
+ setOnsiteInfo([...onsiteInfo]);
+ }}
+ />
+
+
+
+
+ {
+ onsiteInfo[index].phone = e.target.value;
+ setOnsiteInfo([...onsiteInfo]);
+ }}
+ />
+
+
+
+
+ {
+ onsiteInfo[index].email = e.target.value;
+ setOnsiteInfo([...onsiteInfo]);
+ }}
+ />
+
+
+ {onsiteInfo.length >= 2 ? (
+
+ {
+ onsiteInfo.splice(index, 1);
+ setOnsiteInfo([...onsiteInfo]);
+ }}
+ />
- {onsiteInfo.length >= 2 ? (
-
- {
- onsiteInfo.splice(index, 1);
- setOnsiteInfo([...onsiteInfo]);
- }}
- />
-
- ) : (
-
- )}
-
- );
-};
+ ) : (
+
+ )}
+
+);
type OnsiteStaffDropdownProps = {
onsiteInfo: Array;
@@ -129,83 +127,78 @@ const OnsiteDropdownInputRow = ({
availableStaff,
index,
attemptedSubmit,
-}: OnsiteStaffDropdownProps): React.ReactElement => {
+}: OnsiteStaffDropdownProps): React.ReactElement => (
// Choose the name from a dropdown of available staff, and then fill in the rest of the info based on that
- return (
-
-
-
+
+
+
+ staff.name === onsiteInfo[index].name &&
+ staff.phone === onsiteInfo[index].phone &&
+ staff.email === onsiteInfo[index].email,
+ )
+ : ""
}
+ placeholder="Select a staff member"
+ onChange={(e) => {
+ // Find available staff with this name, and fill in the rest of the info
+ const staff = availableStaff[parseInt(e.target.value, 10)];
+ onsiteInfo[index] = staff;
+ setOnsiteInfo([...onsiteInfo]);
+ }}
>
-
- staff.name === onsiteInfo[index].name &&
- staff.phone === onsiteInfo[index].phone &&
- staff.email === onsiteInfo[index].email,
- )
- : ""
- }
- placeholder="Select a staff member"
- onChange={(e) => {
- // Find available staff with this name, and fill in the rest of the info
- const staff = availableStaff[parseInt(e.target.value, 10)];
- onsiteInfo[index] = staff;
- setOnsiteInfo([...onsiteInfo]);
- }}
- >
- {availableStaff.map((staff, index2) => {
- return (
-
- {staff.name}
-
- );
- })}
-
-
-
- {/* display text for phone number and email */}
-
- {onsiteInfo[index] ? onsiteInfo[index].phone : ""}
-
-
- {onsiteInfo[index] ? onsiteInfo[index].email : ""}
+ {availableStaff.map((staff, index2) => (
+
+ {staff.name}
+
+ ))}
+
+
+
+ {/* display text for phone number and email */}
+
+ {onsiteInfo[index] ? onsiteInfo[index].phone : ""}
+
+
+ {onsiteInfo[index] ? onsiteInfo[index].email : ""}
+
+ {onsiteInfo.length >= 2 ? (
+
+ {
+ onsiteInfo.splice(index, 1);
+ setOnsiteInfo([...onsiteInfo]);
+ }}
+ />
- {onsiteInfo.length >= 2 ? (
-
- {
- onsiteInfo.splice(index, 1);
- setOnsiteInfo([...onsiteInfo]);
- }}
- />
-
- ) : (
-
- )}
-
- );
-};
-
+ ) : (
+
+ )}
+
+);
type OnsiteStaffSectionProps = {
- onsiteInfo: Array;
- setOnsiteInfo: React.Dispatch>;
+ onsiteInfo: Array;
+ setOnsiteInfo: React.Dispatch>;
attemptedSubmit: boolean;
- availableStaff?: Array;
+ availableStaff?: Array;
dropdown?: boolean;
};
@@ -218,6 +211,8 @@ const OnsiteStaffSection = ({
}: OnsiteStaffSectionProps): React.ReactElement => {
const isWebView = useIsWebView();
+ const [showCreateModal, setShowCreateModal] = useState(false);
+
if (isWebView) {
return (
@@ -328,6 +323,7 @@ const OnsiteStaffSection = ({
return (
+ {/* {showCreateModal ? (
@@ -413,14 +409,19 @@ const OnsiteStaffSection = ({
cursor="pointer"
w="fit-content"
onClick={() => {
- setOnsiteInfo([
- ...onsiteInfo,
- {
- name: "",
- phone: "",
- email: "",
- },
- ]);
+ if (dropdown) {
+ setOnsiteInfo([
+ ...onsiteInfo,
+ {
+ name: "",
+ phone: "",
+ email: "",
+ },
+ ]);
+ return;
+ }
+
+ setShowCreateModal(true);
}}
>
+ Add another contact
diff --git a/frontend/src/components/crud/DisplayTableContainer.tsx b/frontend/src/components/crud/DisplayTableContainer.tsx
index 97dffa45..7a8f9694 100644
--- a/frontend/src/components/crud/DisplayTableContainer.tsx
+++ b/frontend/src/components/crud/DisplayTableContainer.tsx
@@ -16,8 +16,7 @@ import { downloadFile } from "../../utils/FileUtils";
type EntityData = Omit & { boolField: string };
-const convert = (entityResponse: EntityResponse): EntityData => {
- return {
+const convert = (entityResponse: EntityResponse): EntityData => ({
id: entityResponse.id,
stringField: entityResponse.stringField,
intField: entityResponse.intField,
@@ -25,8 +24,7 @@ const convert = (entityResponse: EntityResponse): EntityData => {
enumField: entityResponse.enumField,
boolField: entityResponse.boolField.toString(),
fileName: entityResponse.fileName,
- };
-};
+ });
type TableProps = {
data: EntityData[];
diff --git a/frontend/src/components/crud/SimpleEntityDisplayTableContainer.tsx b/frontend/src/components/crud/SimpleEntityDisplayTableContainer.tsx
index 512c21ef..5660c4e7 100644
--- a/frontend/src/components/crud/SimpleEntityDisplayTableContainer.tsx
+++ b/frontend/src/components/crud/SimpleEntityDisplayTableContainer.tsx
@@ -17,16 +17,14 @@ type EntityData = Omit & {
boolField: string;
};
-const convert = (entityResponse: SimpleEntityResponse): EntityData => {
- return {
+const convert = (entityResponse: SimpleEntityResponse): EntityData => ({
id: entityResponse.id,
stringField: entityResponse.stringField,
intField: entityResponse.intField,
stringArrayField: entityResponse.stringArrayField,
enumField: entityResponse.enumField,
boolField: entityResponse.boolField.toString(),
- };
-};
+ });
type TableProps = {
data: EntityData[];
diff --git a/frontend/src/components/mealrequest/ListView.tsx b/frontend/src/components/mealrequest/ListView.tsx
new file mode 100644
index 00000000..cd6bf66b
--- /dev/null
+++ b/frontend/src/components/mealrequest/ListView.tsx
@@ -0,0 +1,546 @@
+import { gql, useLazyQuery } from "@apollo/client";
+import {
+ ChevronDownIcon,
+ ChevronLeftIcon,
+ ChevronRightIcon,
+ ChevronUpIcon,
+ DeleteIcon,
+ EditIcon,
+} from "@chakra-ui/icons";
+import {
+ Box,
+ Center,
+ Button as ChakraButton,
+ Collapse,
+ Flex,
+ HStack,
+ Menu,
+ MenuButton,
+ MenuItemOption,
+ MenuList,
+ MenuOptionGroup,
+ Text,
+} from "@chakra-ui/react";
+import {
+ DEFAULT_OPTIONS,
+ getTheme,
+} from "@table-library/react-table-library/chakra-ui";
+import { CompactTable } from "@table-library/react-table-library/compact";
+import { useTheme } from "@table-library/react-table-library/theme";
+import * as TABLE_LIBRARY_TYPES from "@table-library/react-table-library/types/table";
+import React, { useEffect, useState } from "react";
+import { BsFilter } from "react-icons/bs";
+import { FiFilter } from "react-icons/fi";
+
+import EditMealRequestForm from "../../pages/EditMealRequestForm";
+import {
+ MealRequest,
+ MealRequestsData,
+ MealRequestsVariables,
+ MealStatus,
+} from "../../types/MealRequestTypes";
+import { Contact } from "../../types/UserTypes";
+import { logPossibleGraphQLError } from "../../utils/GraphQLUtils";
+import LoadingSpinner from "../common/LoadingSpinner";
+
+const GET_MEAL_REQUESTS_BY_ID = gql`
+ query GetMealRequestsByRequestorId(
+ $requestorId: ID!
+ $minDropOffDate: Date
+ $maxDropOffDate: Date
+ $status: [MealStatus]
+ $offset: Int
+ $limit: Int
+ $sortByDateDirection: SortDirection
+ ) {
+ getMealRequestsByRequestorId(
+ requestorId: $requestorId
+ minDropOffDate: $minDropOffDate
+ maxDropOffDate: $maxDropOffDate
+ status: $status
+ offset: $offset
+ limit: $limit
+ sortByDateDirection: $sortByDateDirection
+ ) {
+ id
+ requestor {
+ info {
+ primaryContact {
+ name
+ email
+ phone
+ }
+ }
+ }
+ status
+ dropOffDatetime
+ dropOffLocation
+ mealInfo {
+ portions
+ dietaryRestrictions
+ }
+ onsiteStaff {
+ name
+ email
+ phone
+ }
+ dateCreated
+ dateUpdated
+ deliveryInstructions
+ donationInfo {
+ donor {
+ info {
+ organizationName
+ }
+ }
+ commitmentDate
+ mealDescription
+ additionalInfo
+ }
+ }
+ }
+`;
+
+type ListViewProps = { authId: string; rowsPerPage?: number };
+
+const ListView = ({ authId, rowsPerPage = 10 }: ListViewProps) => {
+ const chakraTheme = getTheme(DEFAULT_OPTIONS);
+ const customTheme = {
+ Table: `
+ margin: 0 !important;
+ width: 100%;
+ --data-table-library_grid-template-columns: repeat(4, minmax(0, 1fr)) 88px;
+
+ .animate {
+ grid-column: 1 / -1;
+
+ display: flex;
+ }
+
+ .animate > div {
+ flex: 1;
+ display: flex;
+ }
+ `,
+ HeaderRow: `
+ background-color: var(--chakra-colors-gray-50);
+ color: var(--chakra-colors-gray-500);
+ font-family: Inter;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 600;
+ line-height: 21px;
+ text-transform: none;
+ `,
+ };
+
+ const theme = useTheme([chakraTheme, customTheme]);
+
+ const [ids, setIds] = React.useState>(
+ [],
+ );
+
+ const handleExpand = (item: TABLE_LIBRARY_TYPES.TableNode) => () => {
+ if (item.pending) return;
+
+ if (ids.includes(item.id)) {
+ setIds(ids.filter((id) => id !== item.id));
+ } else {
+ setIds(ids.concat(item.id));
+ }
+ };
+
+ const [data, setData] = useState<{
+ nodes: TABLE_LIBRARY_TYPES.TableNode[] | undefined;
+ }>();
+ const [filter, setFilter] = useState>([]);
+ const [sort, setSort] = useState<"ASCENDING" | "DESCENDING">("ASCENDING");
+ const [currentPage, setCurrentPage] = useState(1);
+ const [isEditModalOpen, setIsEditModalOpen] = useState(false);
+ const [
+ currentlyEditingMealRequestId,
+ setCurrentlyEditingMealRequestId,
+ ] = useState(undefined);
+
+ // type TableNodeMealRequest = TABLE_LIBRARY_TYPES.TableNode & {};
+ const [
+ getMealRequests,
+ {
+ loading: getMealRequestsLoading,
+ error: getMealRequestsError,
+ data: getMealRequestsData,
+ },
+ ] = useLazyQuery(
+ GET_MEAL_REQUESTS_BY_ID,
+ {
+ onCompleted: (results) => {
+ setData({
+ nodes: results.getMealRequestsByRequestorId?.map(
+ (
+ mealRequest: MealRequest,
+ index: number,
+ ): TABLE_LIBRARY_TYPES.TableNode => ({
+ id: index,
+ meal_request_id: mealRequest.id,
+ date_requested: new Date(mealRequest.dropOffDatetime),
+ time_requested: new Date(mealRequest.dropOffDatetime),
+ donor_name:
+ mealRequest.donationInfo?.donor.info?.organizationName,
+ num_meals: mealRequest.mealInfo?.portions,
+ primary_contact: mealRequest.requestor.info?.primaryContact,
+ onsite_staff: mealRequest.onsiteStaff,
+ meal_description: mealRequest.donationInfo?.mealDescription,
+ delivery_instructions: mealRequest.deliveryInstructions,
+ pending: mealRequest.status === MealStatus.OPEN,
+ _hasContent: false,
+ nodes: null,
+ }),
+ ),
+ });
+ },
+ },
+ );
+
+ function reloadMealRequests() {
+ getMealRequests({
+ variables: {
+ requestorId: authId,
+ sortByDateDirection: sort,
+ ...(filter.length > 0 && { status: filter }),
+ limit: rowsPerPage,
+ offset: (currentPage - 1) * rowsPerPage,
+ },
+ });
+ }
+
+ useEffect(() => {
+ reloadMealRequests();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [filter, sort, currentPage]);
+
+ const handleEdit = (item: TABLE_LIBRARY_TYPES.TableNode) => () => {
+ // eslint-disable-next-line no-console
+ // console.log("edit clicked for item", item);
+ // console.log(item);
+ setIsEditModalOpen(true);
+ setCurrentlyEditingMealRequestId(item.meal_request_id);
+ };
+
+ const handleDelete = (item: TABLE_LIBRARY_TYPES.TableNode) => () => {
+ // eslint-disable-next-line no-console
+ console.log("delete clicked for item", item.id);
+ };
+
+ const COLUMNS = [
+ {
+ label: "Date Requested",
+ renderCell: (item: TABLE_LIBRARY_TYPES.TableNode) => (
+
+ {item.date_requested.toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ })}
+
+ ),
+ },
+ {
+ label: "Time Requested",
+ renderCell: (item: TABLE_LIBRARY_TYPES.TableNode) => (
+
+ {item.time_requested.toLocaleTimeString("en-US", {
+ hour: "2-digit",
+ minute: "2-digit",
+ })}
+
+ ),
+ },
+ {
+ label: "Donor's Name",
+ renderCell: (item: TABLE_LIBRARY_TYPES.TableNode) => (
+
+ {item.pending ? "Pending Donor" : item.donor_name}
+
+ ),
+ },
+ {
+ label: "Num of Meals",
+ renderCell: (item: TABLE_LIBRARY_TYPES.TableNode) => (
+ {item.num_meals}
+ ),
+ },
+ {
+ label: "",
+ renderCell: (item: TABLE_LIBRARY_TYPES.TableNode) => {
+ if (!item.pending) {
+ return (
+
+ {ids.includes(item.id) ? : }
+
+ );
+ }
+
+ return (
+
+
+
+
+ );
+ },
+ },
+ ];
+
+ const ROW_OPTIONS = {
+ renderAfterRow: (item: TABLE_LIBRARY_TYPES.TableNode) => (
+
+
+
+
+ Donor Contact Info:
+
+ Primary:
+
+
+ {item.primary_contact.name}
+
+
+ {item.primary_contact.email}
+
+
+ {item.primary_contact.phone}
+
+
+ Onsite:
+ {item.onsite_staff.map((staff: Contact) => (
+
+ {staff.name}
+ {staff.email}
+ {staff.phone}
+
+ ))}
+
+
+ Meal Description:
+ {item.meal_description}
+
+
+ Meal Donor Notes:
+ {item.delivery_instructions}
+
+
+
+ ),
+ };
+
+ if (getMealRequestsError) {
+ logPossibleGraphQLError(getMealRequestsError);
+
+ return (
+
+ Error while getting meal requests!
+
+ );
+ }
+
+ if (getMealRequestsLoading || !data) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+ <>
+ {currentlyEditingMealRequestId ? (
+ {
+ setIsEditModalOpen(false);
+ setCurrentlyEditingMealRequestId(undefined);
+ reloadMealRequests();
+ }}
+ mealRequestId={currentlyEditingMealRequestId}
+ />
+ ) : (
+ ""
+ )}
+
+
+
+
+
+
+ Sort
+
+
+
+
+ setSort(value as "ASCENDING" | "DESCENDING")
+ }
+ >
+
+ Date Ascending
+
+
+ Date Descending
+
+
+
+
+
+
+
+
+
+ Filter {filter.length !== 0 ? `(${filter.join(" - ")})` : ""}
+
+
+
+
+ setFilter(value as Array)}
+ >
+
+ Pending Meals
+
+
+ Upcoming Meals
+
+
+ Fulfilled Meals
+
+ {/*
+ Cancelled Meals
+ */}
+
+
+
+
+
+ Meal Requests
+
+
+ {getMealRequestsData?.getMealRequestsByRequestorId.length === 0 && (
+
+ No meal requests to display
+
+ )}
+
+ Page: {currentPage}
+ {currentPage === 1 ? (
+
+ ) : (
+ setCurrentPage(currentPage - 1)}
+ />
+ )}
+ {data?.nodes &&
+ data.nodes.length !== 0 &&
+ data.nodes.length % 5 === 0 ? (
+ setCurrentPage(currentPage + 1)}
+ />
+ ) : (
+
+ )}
+
+
+ >
+ );
+};
+
+export default ListView;
diff --git a/frontend/src/constants/Routes.ts b/frontend/src/constants/Routes.ts
index 42469522..1e8e1265 100644
--- a/frontend/src/constants/Routes.ts
+++ b/frontend/src/constants/Routes.ts
@@ -14,7 +14,7 @@ export const SET_PASSWORD_PAGE = "/:objectID/set-password";
export const CREATE_MEAL_REQUEST_PAGE = "/request/scheduling";
-export const DASHBOARD_PAGE = "/dashboard";
+export const ASP_DASHBOARD_PAGE = "/asp/dashboard";
export const MEAL_DONOR_DASHBOARD_PAGE = "/meal_donor/dashboard";
diff --git a/frontend/src/pages/ASPDashboard.tsx b/frontend/src/pages/ASPDashboard.tsx
new file mode 100644
index 00000000..bd696829
--- /dev/null
+++ b/frontend/src/pages/ASPDashboard.tsx
@@ -0,0 +1,118 @@
+import { CalendarIcon, HamburgerIcon } from "@chakra-ui/icons";
+import {
+ Button as ChakraButton,
+ Flex,
+ Tab,
+ TabList,
+ TabPanel,
+ TabPanels,
+ Tabs,
+ Text,
+ Wrap,
+} from "@chakra-ui/react";
+import React, { useContext } from "react";
+import { Navigate, useNavigate } from "react-router-dom";
+
+import BackgroundImage from "../assets/background.png";
+import RefreshCredentials from "../components/auth/RefreshCredentials";
+import ListView from "../components/mealrequest/ListView";
+import * as Routes from "../constants/Routes";
+import AuthContext from "../contexts/AuthContext";
+
+type ButtonProps = { children: React.ReactNode; path: string };
+
+const NavigationButton = ({ children, path }: ButtonProps) => {
+ const navigate = useNavigate();
+ return navigate(path)}>{children} ;
+};
+
+const OldDashboard = (): React.ReactElement => (
+
+
+
+
+ Create Entity
+
+
+
+ Update Entity
+
+
+ Display Entities
+
+
+ Create Simple Entity
+
+
+ Update Simple Entity
+
+
+ Display Simple Entities
+
+ Hooks Demo
+
+
+
+);
+
+const Dashboard = (): React.ReactElement => {
+ const { authenticatedUser } = useContext(AuthContext);
+
+ if (!authenticatedUser) {
+ return ;
+ }
+
+ return (
+
+
+ Your Dashboard
+
+
+ Use this page to see your upcoming food deliveries
+
+
+
+
+
+
+ Calendar
+
+
+
+ List
+
+
+ Old Dashboard
+
+
+
+ + Create Request
+
+
+
+
+
+ Insert Calendar Here
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Dashboard;
diff --git a/frontend/src/pages/CreatePage.tsx b/frontend/src/pages/CreatePage.tsx
index 2a8d4242..c36ba4a5 100644
--- a/frontend/src/pages/CreatePage.tsx
+++ b/frontend/src/pages/CreatePage.tsx
@@ -3,14 +3,12 @@ import React from "react";
import MainPageButton from "../components/common/MainPageButton";
import CreateForm from "../components/crud/CreateForm";
-const CreatePage = (): React.ReactElement => {
- return (
+const CreatePage = (): React.ReactElement => (
Default Page
);
-};
export default CreatePage;
diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx
deleted file mode 100644
index 43fbd804..00000000
--- a/frontend/src/pages/Dashboard.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { Button as ChakraButton, Wrap } from "@chakra-ui/react";
-import React from "react";
-import { useNavigate } from "react-router-dom";
-
-import EditMealRequestForm from "./EditMealRequestForm";
-
-import BackgroundImage from "../assets/background.png";
-import RefreshCredentials from "../components/auth/RefreshCredentials";
-import * as Routes from "../constants/Routes";
-
-type ButtonProps = { text: string; path: string };
-
-const Button = ({ text, path }: ButtonProps) => {
- const navigate = useNavigate();
- return navigate(path)}>{text} ;
-};
-
-const Default = (): React.ReactElement => {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default Default;
diff --git a/frontend/src/pages/Default.tsx b/frontend/src/pages/Default.tsx
index 182ed592..ab767d72 100644
--- a/frontend/src/pages/Default.tsx
+++ b/frontend/src/pages/Default.tsx
@@ -1,26 +1,46 @@
import { Button, Link } from "@chakra-ui/react";
-import React from "react";
+import React, { useContext } from "react";
import { Link as RouterLink } from "react-router-dom";
import BackgroundImage from "../assets/background.png";
import * as Routes from "../constants/Routes";
+import AuthContext from "../contexts/AuthContext";
+import useIsAdmin from "../utils/useIsAdmin";
+import useIsMealDonor from "../utils/useIsMealDonor";
const Default = (): React.ReactElement => {
+ const isMealDonor = useIsMealDonor();
+ const isAdmin = useIsAdmin();
+
+ const wrapperStyles = {
+ height: "100vh",
+ backgroundImage: `url(${BackgroundImage})`,
+ backgroundPosition: "center",
+ backgroundRepeat: "no-repeat",
+ backgroundSize: "cover",
+ };
+ if (isMealDonor) {
+ return (
+
+
+ Go to meal donor dashboard
+
+
+ );
+ }
+
+ if (isAdmin) {
+ return (
+
+ Go to Admin Dashboard (unimplemented)
+
+ );
+ }
+
return (
-
-
-
Go to dashboard
-
-
-
Go to meal donor dashboard
+
+
+ Go to ASP dashboard
);
diff --git a/frontend/src/pages/DisplayPage.tsx b/frontend/src/pages/DisplayPage.tsx
index 96cfded2..7b398082 100644
--- a/frontend/src/pages/DisplayPage.tsx
+++ b/frontend/src/pages/DisplayPage.tsx
@@ -3,14 +3,12 @@ import React from "react";
import MainPageButton from "../components/common/MainPageButton";
import DisplayTableContainer from "../components/crud/DisplayTableContainer";
-const GetPage = (): React.ReactElement => {
- return (
+const GetPage = (): React.ReactElement => (
Default Page
);
-};
export default GetPage;
diff --git a/frontend/src/pages/EditMealRequestForm.tsx b/frontend/src/pages/EditMealRequestForm.tsx
index 4b63001d..8e9797a4 100644
--- a/frontend/src/pages/EditMealRequestForm.tsx
+++ b/frontend/src/pages/EditMealRequestForm.tsx
@@ -1,3 +1,10 @@
+import {
+ ApolloError,
+ gql,
+ useApolloClient,
+ useMutation,
+ useQuery,
+} from "@apollo/client";
import {
Button,
Divider,
@@ -11,14 +18,22 @@ import {
ModalContent,
ModalFooter,
ModalOverlay,
+ NumberInput,
Text,
useDisclosure,
+ useToast,
} from "@chakra-ui/react";
-import React, { useState } from "react";
+import { GraphQLError } from "graphql";
+import React, { useContext, useEffect, useState } from "react";
+import LoadingSpinner from "../components/common/LoadingSpinner";
import OnsiteStaffSection from "../components/common/OnsiteStaffSection";
-import { Contact } from "../types/UserTypes";
+import AuthContext from "../contexts/AuthContext";
+import { MealRequestsData } from "../types/MealRequestTypes";
+import { Contact, OnsiteContact } from "../types/UserTypes";
+import { logPossibleGraphQLError } from "../utils/GraphQLUtils";
import { isValidEmail } from "../utils/ValidationUtils";
+import useGetOnsiteContacts from "../utils/useGetOnsiteContacts";
import useIsWebView from "../utils/useIsWebView";
const PLACEHOLDER_WEB_EXAMPLE_FULL_NAME = "Jane Doe";
@@ -29,7 +44,94 @@ const PLACEHOLDER_MOBILE_EXAMPLE_FULL_NAME = "Full Name (Jane Doe)";
const PLACEHOLDER_MOBILE_EXAMPLE_EMAIL = "Email (example@domain.com)";
const PLACEHOLDER_MOBILE_EXAMPLE_PHONE_NUMBER = "Phone Number (111-222-3333)";
-const EditMealRequestForm = () => {
+const GET_MEAL_REQUEST_BY_ID = gql`
+ query get_meal_request_by_id($id: ID!, $requestorId: ID!) {
+ getMealRequestById(id: $id, requestorId: $requestorId) {
+ id
+ status
+ dropOffDatetime
+ dropOffLocation
+ mealInfo {
+ portions
+ dietaryRestrictions
+ }
+ onsiteStaff {
+ id
+ name
+ email
+ phone
+ }
+ dateCreated
+ dateUpdated
+ deliveryInstructions
+ }
+ }
+`;
+
+const UPDATE_MEAL_REQUEST = gql`
+ mutation UpdateMealRequest(
+ $requestorId: ID!
+ $mealRequestId: ID!
+ $updatedDeliveryInstructions: String!
+ $updatedMealInfoPortions: Int!
+ $updatedMealInfoDietaryRestrictions: String!
+ $updatedOnsiteContacts: [String!]!
+ ) {
+ updateMealRequest(
+ requestorId: $requestorId
+ mealRequestId: $mealRequestId
+ deliveryInstructions: $updatedDeliveryInstructions
+ mealInfo: {
+ portions: $updatedMealInfoPortions
+ dietaryRestrictions: $updatedMealInfoDietaryRestrictions
+ }
+ onsiteStaff: $updatedOnsiteContacts
+ ) {
+ mealRequest {
+ id
+ status
+ dropOffDatetime
+ dropOffLocation
+ mealInfo {
+ portions
+ dietaryRestrictions
+ }
+ onsiteStaff {
+ id
+ name
+ email
+ phone
+ }
+ donationInfo {
+ donor {
+ id
+ info {
+ email
+ }
+ }
+ }
+ deliveryInstructions
+ }
+ }
+ }
+`;
+
+const EditMealRequestForm = ({
+ open,
+ onClose,
+ mealRequestId,
+}: {
+ open: boolean;
+ onClose: () => void;
+ mealRequestId: string;
+}) => {
+ // Get existing meal request information
+ const { authenticatedUser, setAuthenticatedUser } = useContext(AuthContext);
+ const requestorId = authenticatedUser?.id;
+ // const { data: queryData, error: queryDataError } = useQuery
(
+ // logPossibleGraphQLError(queryDataError);
+ // const existingMealRequest = queryData?.getMealRequestById;
+
const [primaryContact, setPrimaryContact] = useState({
name: "",
phone: "",
@@ -45,83 +147,207 @@ const EditMealRequestForm = () => {
const [attemptedSubmit, setAttemptedSubmit] = useState(false);
const isWebView = useIsWebView();
- const { isOpen, onOpen, onClose } = useDisclosure();
-
const initialFocusRef = React.useRef(null);
- const getMobileContactSection = (): React.ReactElement => {
- return (
-
-
-
- Primary Contact
-
-
- (0);
+ const [dietaryRestrictions, setDietaryRestrictions] = useState("");
+ const [deliveryInstructions, setDeliveryInstructions] = useState("");
+ const [loading, setLoading] = useState(true);
+
+ const toast = useToast();
+ const [onsiteStaff, setOnsiteStaff] = useState([]);
+ // This is the list of available onsite staff
+ const [availableOnsiteContacts, setAvailableOnsiteContacts] = useState<
+ Array
+ >([]);
+ useGetOnsiteContacts(toast, setAvailableOnsiteContacts, setLoading);
+
+ const apolloClient = useApolloClient();
+
+ useEffect(() => {
+ async function getData() {
+ try {
+ const result = await apolloClient.query({
+ query: GET_MEAL_REQUEST_BY_ID,
+ variables: {
+ id: mealRequestId,
+ requestorId,
+ },
+ });
+ const mealRequest = result.data.getMealRequestById;
+ setNumberOfMeals(mealRequest.mealInfo.portions);
+ setDietaryRestrictions(mealRequest.mealInfo.dietaryRestrictions);
+ setDeliveryInstructions(mealRequest.deliveryInstructions);
+
+ // Parse/stringify is to make a deep copy of the onsite staff
+ setOnsiteStaff(JSON.parse(JSON.stringify(mealRequest.onsiteStaff)));
+ setLoading(false);
+ } catch (error) {
+ logPossibleGraphQLError(error as ApolloError);
+ }
+ }
+ getData();
+ }, [requestorId, mealRequestId, apolloClient]);
+
+ const [updateMealRequest] = useMutation(UPDATE_MEAL_REQUEST);
+
+ async function submitEditMealRequest() {
+ try {
+ setLoading(true);
+ const response = await updateMealRequest({
+ variables: {
+ requestorId,
+ mealRequestId,
+ updatedDeliveryInstructions: deliveryInstructions,
+ updatedMealInfoPortions: numberOfMeals,
+ updatedMealInfoDietaryRestrictions: dietaryRestrictions,
+ updatedOnsiteContacts: onsiteStaff.map((contact) => contact.id),
+ },
+ });
+ const data = response.data;
+ if (data) {
+ toast({
+ title: "Saved successfully",
+ status: "success",
+ isClosable: true,
+ });
+ } else {
+ throw new GraphQLError("Failed to save settings");
+ }
+ setLoading(false);
+ } catch (e: unknown) {
+ // eslint-disable-next-line no-console
+ logPossibleGraphQLError(e as ApolloError);
+ toast({
+ title: "Failed to save settings",
+ status: "error",
+ isClosable: true,
+ });
+ setLoading(false);
+ }
+ onClose();
+ }
+
+ const getMobileContactSection = (): React.ReactElement => (
+
+
+ Primary Contact
+
+
+
+ setPrimaryContact({ ...primaryContact, name: e.target.value })
+ }
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_FULL_NAME}
+ />
+
+
+
+ setPrimaryContact({
+ ...primaryContact,
+ phone: e.target.value,
+ })
+ }
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_PHONE_NUMBER}
+ />
+
+
+
+ setPrimaryContact({
+ ...primaryContact,
+ email: e.target.value,
+ })
+ }
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_EMAIL}
+ />
+
+
+
+
+ );
+
+ const getWebContactSection = (): React.ReactElement => (
+ <>
+
+ Contact Information
+
+
+
+
+
+
-
- setPrimaryContact({ ...primaryContact, name: e.target.value })
- }
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_FULL_NAME}
- />
-
+ Primary contact name
+
+
+ setPrimaryContact({ ...primaryContact, name: e.target.value })
+ }
+ />
+
+
+
+
+
+
+ Phone number
+
setPrimaryContact({
...primaryContact,
phone: e.target.value,
})
}
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_PHONE_NUMBER}
- />
-
-
-
- setPrimaryContact({
- ...primaryContact,
- email: e.target.value,
- })
- }
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_EMAIL}
/>
-
-
- );
- };
-
- const getWebContactSection = (): React.ReactElement => {
- return (
- <>
-
- Contact Information
-
-
-
+
{
md: "form-label-bold",
}}
>
- Primary contact name
+ Email address
- setPrimaryContact({ ...primaryContact, name: e.target.value })
+ setPrimaryContact({
+ ...primaryContact,
+ email: e.target.value,
+ })
}
/>
-
-
-
-
-
- Phone number
-
-
- setPrimaryContact({
- ...primaryContact,
- phone: e.target.value,
- })
- }
- />
-
-
-
-
-
-
- Email address
-
-
- setPrimaryContact({
- ...primaryContact,
- email: e.target.value,
- })
- }
- />
-
-
-
- >
- );
- };
+
+ >
+ );
return (
<>
- Edit Meal Request
-
+ {/* Edit Meal Request */}
+
-
- Edit Meal Request
-
-
-
-
- Meal Information
-
-
-
-
+ ) : (
+ <>
+
- Number of meals
-
-
-
+ Edit Meal Request
+
+
+
+
+ Meal Information
+
-
-
+
- Dietary restrictions
-
-
-
+ // TODO: Hook this up to a state variable
+ // TODO: Setup correct validation for this
+ // isInvalid={attemptedSubmit && }
+ >
+ Number of meals
+
+ setNumberOfMeals(Number(e.target.value))}
+ ref={initialFocusRef}
+ type="number"
+ w="200px"
+ />
+
-
-
- Delivery Notes
-
-
-
-
- {isWebView && }
- {isWebView ? getWebContactSection() : getMobileContactSection()}
+
+
+ Dietary restrictions
+
+ setDietaryRestrictions(e.target.value)}
+ />
+
-
-
+
+
+ Delivery Notes
+
+ setDeliveryInstructions(e.target.value)}
+ />
+
+
+ {isWebView && }
+
+
-
-
- Cancel
-
- {
- setAttemptedSubmit(true);
- }}
- >
- Save
-
-
+
+
+ Cancel
+
+ {
+ setAttemptedSubmit(true);
+ submitEditMealRequest();
+ }}
+ >
+ Save
+
+
+ >
+ )}
>
diff --git a/frontend/src/pages/MealDonorDashboard.tsx b/frontend/src/pages/MealDonorDashboard.tsx
index 23c53267..0f6e8f47 100644
--- a/frontend/src/pages/MealDonorDashboard.tsx
+++ b/frontend/src/pages/MealDonorDashboard.tsx
@@ -15,8 +15,7 @@ const Button = ({ text, path }: ButtonProps) => {
return navigate(path)}>{text} ;
};
-const MealDonorDashboard = (): React.ReactElement => {
- return (
+const MealDonorDashboard = (): React.ReactElement => (
);
-};
export default MealDonorDashboard;
diff --git a/frontend/src/pages/NotFound.tsx b/frontend/src/pages/NotFound.tsx
index ed8d8261..d51104f3 100644
--- a/frontend/src/pages/NotFound.tsx
+++ b/frontend/src/pages/NotFound.tsx
@@ -1,11 +1,9 @@
import React from "react";
-const NotFound = (): React.ReactElement => {
- return (
+const NotFound = (): React.ReactElement => (
404 Not Found 🙁
);
-};
export default NotFound;
diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx
index 6a117e8b..bb7da95f 100644
--- a/frontend/src/pages/Settings.tsx
+++ b/frontend/src/pages/Settings.tsx
@@ -1,4 +1,14 @@
-import { gql, useMutation } from "@apollo/client";
+/*
+
+What do I need to do:
+Setup update
+setup delteo
+
+create should be working
+work on other pages as well
+
+*/
+import { ApolloError, gql, useMutation, useQuery } from "@apollo/client";
import {
Button,
Center,
@@ -7,10 +17,12 @@ import {
FormControl,
FormLabel,
Input,
+ Spinner,
Text,
Textarea,
useToast,
} from "@chakra-ui/react";
+import { create } from "domain";
import { GraphQLError } from "graphql";
import React, { useContext, useState } from "react";
import { Navigate, useNavigate } from "react-router-dom";
@@ -19,13 +31,15 @@ import OnsiteStaffSection from "../components/common/OnsiteStaffSection";
import AUTHENTICATED_USER_KEY from "../constants/AuthConstants";
import { LOGIN_PAGE } from "../constants/Routes";
import AuthContext from "../contexts/AuthContext";
-import { Contact, UserInfo } from "../types/UserTypes";
+import { Contact, OnsiteContact, UserInfo } from "../types/UserTypes";
+import { logPossibleGraphQLError } from "../utils/GraphQLUtils";
import { setLocalStorageObjProperty } from "../utils/LocalStorageUtils";
import {
isNonNegativeInt,
isValidEmail,
trimWhiteSpace,
} from "../utils/ValidationUtils";
+import useGetOnsiteContacts from "../utils/useGetOnsiteContacts";
import useIsWebView from "../utils/useIsWebView";
const PLACEHOLDER_WEB_EXAMPLE_FULL_NAME = "Jane Doe";
@@ -46,7 +60,7 @@ const PLACEHOLDER_MOBILE_EXAMPLE_ADDRESS = "Address of organization";
const PLACEHOLDER_MOBILE_EXAMPLE_ORG_DESCRIPTION =
"Description of organization";
-const UPDATEUSERBYID = gql`
+const UPDATE_USER_BY_ID = gql`
mutation UpdateUserById(
$requestorId: String!
$id: String!
@@ -75,18 +89,76 @@ const UPDATEUSERBYID = gql`
phone
email
}
- onsiteContacts {
+ active
+ initialOnsiteContacts {
name
- phone
email
+ phone
}
- active
}
}
}
}
`;
+const CREATE_ONSITE_CONTACT = gql`
+ mutation createOnsiteContact(
+ $requestorId: String!
+ $email: String!
+ $name: String!
+ $phone: String!
+ $organizationId: String!
+ ) {
+ createOnsiteContact(
+ requestorId: $requestorId
+ email: $email
+ name: $name
+ phone: $phone
+ organizationId: $organizationId
+ ) {
+ onsiteContact {
+ id
+ name
+ email
+ phone
+ }
+ }
+ }
+`;
+
+const UPDATE_ONSITE_CONTACT = gql`
+ mutation updateOnsiteContact(
+ $id: String!
+ $requestorId: String!
+ $email: String!
+ $name: String!
+ $phone: String!
+ ) {
+ updateOnsiteContact(
+ id: $id
+ requestorId: $requestorId
+ email: $email
+ name: $name
+ phone: $phone
+ ) {
+ onsiteContact {
+ id
+ name
+ email
+ phone
+ }
+ }
+ }
+`;
+
+const DELETE_ONSITE_CONTACT = gql`
+ mutation delete_onsite_contact($requestorId: String!, $id: String!) {
+ deleteOnsiteContact(requestorId: $requestorId, id: $id) {
+ success
+ }
+ }
+`;
+
const Settings = (): React.ReactElement => {
// Assumption: user has the roleInfo: ASPInfo
@@ -116,26 +188,41 @@ const Settings = (): React.ReactElement => {
const [organizationDesc, setOrganizationDesc] = useState(
userInfo?.organizationDesc || "",
);
- // json parse/stringify creates a deep copy of the array of contacts
- // this prevents setOnsiteInfo from mutating the original state of userInfo.onsiteContacts
- const [onsiteInfo, setOnsiteInfo] = useState>(
- userInfo
- ? JSON.parse(JSON.stringify(userInfo.onsiteContacts))
- : [
- {
- name: "",
- phone: "",
- email: "",
- },
- ],
- );
+
+ const [serverOnsiteContacts, setServerOnsiteContacts] = useState<
+ Array
+ >([]);
const [attemptedSubmit, setAttemptedSave] = useState(false);
+ const [isLoading, setIsLoading] = useState(true);
const isWebView = useIsWebView();
const navigate = useNavigate();
const toast = useToast();
- const [updateUserByID] = useMutation(UPDATEUSERBYID);
+ const [onsiteContacts, setOnsiteContacts] = useState>([
+ {
+ id: "",
+ name: "",
+ phone: "",
+ email: "",
+ },
+ ]);
+
+ useGetOnsiteContacts(
+ toast,
+ (contacts) => {
+ setOnsiteContacts(contacts);
+ setServerOnsiteContacts(contacts);
+ },
+ setIsLoading,
+ );
+
+ const [updateUserByID] = useMutation(UPDATE_USER_BY_ID);
+ const [createOnsiteContact] = useMutation(CREATE_ONSITE_CONTACT);
+ const [updateOnsiteContact] = useMutation(UPDATE_ONSITE_CONTACT);
+ const [deleteOnsiteContact] = useMutation(DELETE_ONSITE_CONTACT);
+
+ // OnsiteContact query
if (!authenticatedUser) {
return ;
@@ -165,11 +252,11 @@ const Settings = (): React.ReactElement => {
const defaultContactValues: Array = [
userInfo.primaryContact,
- ...userInfo.onsiteContacts,
+ ...(serverOnsiteContacts ?? []),
];
const currentContactValues: Array = [
primaryContact,
- ...onsiteInfo,
+ ...onsiteContacts,
];
if (defaultContactValues.length !== currentContactValues.length)
@@ -192,54 +279,28 @@ const Settings = (): React.ReactElement => {
navigate(`/${authenticatedUser?.id}/reset-password`);
};
- const getTitleSection = (): React.ReactElement => {
- return (
-
- User Settings
-
- );
- };
+ const getTitleSection = (): React.ReactElement => (
+
+ User Settings
+
+ );
- const getWebLoginInfoSection = (): React.ReactElement => {
- return (
+ const getWebLoginInfoSection = (): React.ReactElement => (
+
+ Login Information
- Login Information
-
-
- Email Address
- {userInfo?.email}
-
-
- Reset Password
-
+
+ Email Address
+ {userInfo?.email}
-
- );
- };
-
- const getMobileLoginInfoSection = (): React.ReactElement => {
- return (
-
- Email Address
- {userInfo?.email}
{
Reset Password
- );
- };
+
+ );
- const getWebContactSection = (): React.ReactElement => {
- return (
-
- {haveSettingsChanged() && (
-
- You have unsaved changes. Make sure to click save at the bottom
- before leaving!
-
- )}
- Contact Information
-
-
-
-
- Primary contact name
-
-
- setPrimaryContact({ ...primaryContact, name: e.target.value })
- }
- />
-
-
-
-
- Phone number
-
- setPrimaryContact({
- ...primaryContact,
- phone: e.target.value,
- })
- }
- />
-
-
-
-
- Email address
-
- setPrimaryContact({
- ...primaryContact,
- email: e.target.value,
- })
- }
- />
-
-
+ const getMobileLoginInfoSection = (): React.ReactElement => (
+
+ Email Address
+ {userInfo?.email}
+
+ Reset Password
+
+
+ );
+
+ const getWebContactSection = (): React.ReactElement => (
+
+ {haveSettingsChanged() && (
+
+ You have unsaved changes. Make sure to click save at the bottom before
+ leaving!
+
+ )}
+ Contact Information
+
+
+
+
+ Primary contact name
+
+
+ setPrimaryContact({ ...primaryContact, name: e.target.value })
+ }
+ />
+
+
+
+
+ Phone number
+
+ setPrimaryContact({
+ ...primaryContact,
+ phone: e.target.value,
+ })
+ }
+ />
+
+
+
+
+ Email address
+
+ setPrimaryContact({
+ ...primaryContact,
+ email: e.target.value,
+ })
+ }
+ />
+
- );
- };
+
+ );
+
+ const getMobileContactSection = (): React.ReactElement => (
+
+
+ Primary Contact
+
+
+
+ setPrimaryContact({ ...primaryContact, name: e.target.value })
+ }
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_FULL_NAME}
+ />
+
+
+
+ setPrimaryContact({
+ ...primaryContact,
+ phone: e.target.value,
+ })
+ }
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_PHONE_NUMBER}
+ />
+
+
+
+ setPrimaryContact({
+ ...primaryContact,
+ email: e.target.value,
+ })
+ }
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_EMAIL}
+ />
+
+
+
+
+ );
- const getMobileContactSection = (): React.ReactElement => {
- return (
-
-
-
- Primary Contact
+ const getWebOrganizationSection = (): React.ReactElement => (
+
+ Organization Info
+
+
+
+
+ Name of organization
+
+ setOrganizationName(e.target.value)}
+ />
+
+
+
+
+ Number of kids
+ setNumKids(e.target.value)}
+ />
+
+
+
+
+
+ Address of organization
+
+ setOrganizationAddress(e.target.value)}
+ />
+
+
+
+
+
+
+ Description of organization
-
-
-
- setPrimaryContact({ ...primaryContact, name: e.target.value })
- }
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_FULL_NAME}
- />
-
-
-
- setPrimaryContact({
- ...primaryContact,
- phone: e.target.value,
- })
- }
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_PHONE_NUMBER}
- />
-
-
-
- setPrimaryContact({
- ...primaryContact,
- email: e.target.value,
- })
- }
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_EMAIL}
- />
-
-
+
- );
- };
+
+ );
- const getWebOrganizationSection = (): React.ReactElement => {
- return (
-
- Organization Info
-
-
-
-
- Name of organization
-
- setOrganizationName(e.target.value)}
- />
-
-
-
-
- Number of kids
- setNumKids(e.target.value)}
- />
-
-
-
-
-
- Address of organization
-
- setOrganizationAddress(e.target.value)}
- />
-
-
-
-
+ const getMobileOrganizationSection = (): React.ReactElement => (
+
+
+
+ Organization Information
+
+
+
+
+ setOrganizationName(e.target.value)}
+ />
+
+
+ setNumKids(e.target.value)}
+ />
+
+
+ setOrganizationAddress(e.target.value)}
+ placeholder={PLACEHOLDER_MOBILE_EXAMPLE_ADDRESS}
+ />
+
-
- Description of organization
-
-
- );
- };
-
- const getMobileOrganizationSection = (): React.ReactElement => {
- return (
-
-
-
- Organization Information
-
-
-
-
- setOrganizationName(e.target.value)}
- />
-
-
- setNumKids(e.target.value)}
- />
-
-
- setOrganizationAddress(e.target.value)}
- placeholder={PLACEHOLDER_MOBILE_EXAMPLE_ADDRESS}
- />
-
-
-
-
-
-
- );
- };
+
+
+ );
const isRequestValid = (): boolean => {
const stringsToValidate = [
@@ -525,10 +596,10 @@ const Settings = (): React.ReactElement => {
const phoneNumsToValidate = [primaryContact.phone];
const emailsToValidate = [primaryContact.email];
- for (let i = 0; i < onsiteInfo.length; i += 1) {
- stringsToValidate.push(onsiteInfo[i].name);
- phoneNumsToValidate.push(onsiteInfo[i].phone);
- emailsToValidate.push(onsiteInfo[i].email);
+ for (let i = 0; i < onsiteContacts.length; i += 1) {
+ stringsToValidate.push(onsiteContacts[i].name);
+ phoneNumsToValidate.push(onsiteContacts[i].phone);
+ emailsToValidate.push(onsiteContacts[i].email);
}
for (let i = 0; i < stringsToValidate.length; i += 1) {
@@ -551,7 +622,9 @@ const Settings = (): React.ReactElement => {
const handleSaveSettings = async (
requestorId: string,
requestUserInfo: UserInfo,
+ requestOnsiteContacts: Array,
) => {
+ setIsLoading(true);
try {
const response = await updateUserByID({
variables: {
@@ -569,17 +642,72 @@ const Settings = (): React.ReactElement => {
// without this change, the initial state of userinfo will not include new changes
// because local storage only updates after the user logs in
setLocalStorageObjProperty(AUTHENTICATED_USER_KEY, "info", newInfo);
- toast({
- title: "Saved settings successfully",
- status: "success",
- isClosable: true,
- });
} else {
throw new GraphQLError("Failed to save settings");
}
+
+ // update onsite contacts
+ // eslint-disable-next-line no-restricted-syntax
+ await Promise.all(
+ requestOnsiteContacts.map(async (contact: OnsiteContact) => {
+ // If the contact already exists, we have an id for it
+ const isNewContact = contact.id === undefined || contact.id === "";
+ if (isNewContact) {
+ await createOnsiteContact({
+ variables: {
+ requestorId,
+ name: contact.name,
+ email: contact.email,
+ phone: contact.phone,
+ organizationId: requestorId,
+ },
+ });
+ } else {
+ await updateOnsiteContact({
+ variables: {
+ id: contact.id,
+ requestorId,
+ name: contact.name,
+ email: contact.email,
+ phone: contact.phone,
+ organizationId: requestorId,
+ },
+ });
+ }
+ }),
+ );
+
+ // Some contacts must have been deleted
+ if (requestOnsiteContacts.length < serverOnsiteContacts.length) {
+ await Promise.all(
+ serverOnsiteContacts.map(async (contact: OnsiteContact) => {
+ const id = contact.id;
+ const newContact = requestOnsiteContacts.find((c) => c.id === id);
+ if (newContact) {
+ return;
+ }
+
+ await deleteOnsiteContact({
+ variables: {
+ id,
+ requestorId,
+ },
+ });
+ }),
+ );
+ }
+
+ toast({
+ title: "Saved settings successfully",
+ status: "success",
+ isClosable: true,
+ });
+ setServerOnsiteContacts(requestOnsiteContacts);
+ setIsLoading(false);
} catch (e: unknown) {
- // eslint-disable-next-line no-console
- console.log(e);
+ logPossibleGraphQLError(e as ApolloError);
+ setIsLoading(false);
+
toast({
title: "Failed to save settings",
status: "error",
@@ -609,76 +737,83 @@ const Settings = (): React.ReactElement => {
email: trimWhiteSpace(primaryContact.email),
phone: trimWhiteSpace(primaryContact.phone),
},
- onsiteContacts: onsiteInfo.map((obj) => ({
+ initialOnsiteContacts: userInfo?.initialOnsiteContacts ?? [],
+ active: userInfo?.active,
+ };
+
+ const requestOnsiteContacts: Array = onsiteContacts.map(
+ (obj) => ({
+ id: obj.id,
name: trimWhiteSpace(obj.name),
phone: trimWhiteSpace(obj.phone),
email: trimWhiteSpace(obj.email),
- })),
- active: userInfo?.active,
- };
+ }),
+ );
const requestorId = authenticatedUser?.id;
- handleSaveSettings(requestorId, requestUserInfo);
+ handleSaveSettings(requestorId, requestUserInfo, requestOnsiteContacts);
};
- const getSaveSection = (): React.ReactElement => {
- return (
-
- Save
-
- );
- };
+ const getSaveSection = (): React.ReactElement => (
+
+ Save
+
+ );
return (
-
- {getTitleSection()}
- {isWebView ? getWebLoginInfoSection() : getMobileLoginInfoSection()}
- {isWebView && }
- {isWebView ? getWebContactSection() : getMobileContactSection()}
- {isWebView && }
- {isWebView
- ? getWebOrganizationSection()
- : getMobileOrganizationSection()}
- {isWebView && }
-
- {getSaveSection()}
-
+ {isLoading ? (
+
+ ) : (
+
+ {getTitleSection()}
+ {isWebView ? getWebLoginInfoSection() : getMobileLoginInfoSection()}
+ {isWebView && }
+ {isWebView ? getWebContactSection() : getMobileContactSection()}
+ {isWebView && }
+ {isWebView
+ ? getWebOrganizationSection()
+ : getMobileOrganizationSection()}
+ {isWebView && }
+
+ {getSaveSection()}
+
+ )}
);
};
diff --git a/frontend/src/pages/SimpleEntityCreatePage.tsx b/frontend/src/pages/SimpleEntityCreatePage.tsx
index eecd3d64..38451080 100644
--- a/frontend/src/pages/SimpleEntityCreatePage.tsx
+++ b/frontend/src/pages/SimpleEntityCreatePage.tsx
@@ -3,14 +3,12 @@ import React from "react";
import MainPageButton from "../components/common/MainPageButton";
import SimpleEntityCreateForm from "../components/crud/SimpleEntityCreateForm";
-const SimpleEntityCreatePage = (): React.ReactElement => {
- return (
+const SimpleEntityCreatePage = (): React.ReactElement => (
Default Page
);
-};
export default SimpleEntityCreatePage;
diff --git a/frontend/src/pages/SimpleEntityDisplayPage.tsx b/frontend/src/pages/SimpleEntityDisplayPage.tsx
index 02abe350..9955f009 100644
--- a/frontend/src/pages/SimpleEntityDisplayPage.tsx
+++ b/frontend/src/pages/SimpleEntityDisplayPage.tsx
@@ -3,14 +3,12 @@ import React from "react";
import MainPageButton from "../components/common/MainPageButton";
import SimpleEntityDisplayTableContainer from "../components/crud/SimpleEntityDisplayTableContainer";
-const GetSimpleEntitiesPage = (): React.ReactElement => {
- return (
+const GetSimpleEntitiesPage = (): React.ReactElement => (
Default Page
);
-};
export default GetSimpleEntitiesPage;
diff --git a/frontend/src/pages/SimpleEntityUpdatePage.tsx b/frontend/src/pages/SimpleEntityUpdatePage.tsx
index 5a69cf56..46e47076 100644
--- a/frontend/src/pages/SimpleEntityUpdatePage.tsx
+++ b/frontend/src/pages/SimpleEntityUpdatePage.tsx
@@ -3,14 +3,12 @@ import React from "react";
import MainPageButton from "../components/common/MainPageButton";
import SimpleEntityUpdateForm from "../components/crud/SimpleEntityUpdateForm";
-const SimpleEntityUpdatePage = (): React.ReactElement => {
- return (
+const SimpleEntityUpdatePage = (): React.ReactElement => (
Default Page
);
-};
export default SimpleEntityUpdatePage;
diff --git a/frontend/src/pages/UpdatePage.tsx b/frontend/src/pages/UpdatePage.tsx
index 47ebdb48..590653d8 100644
--- a/frontend/src/pages/UpdatePage.tsx
+++ b/frontend/src/pages/UpdatePage.tsx
@@ -3,14 +3,12 @@ import React from "react";
import MainPageButton from "../components/common/MainPageButton";
import UpdateForm from "../components/crud/UpdateForm";
-const UpdatePage = (): React.ReactElement => {
- return (
+const UpdatePage = (): React.ReactElement => (
Default Page
);
-};
export default UpdatePage;
diff --git a/frontend/src/pages/__tests__/Dashboard.test.tsx b/frontend/src/pages/__tests__/Dashboard.test.tsx
index 6f0ae7c3..73d74a85 100644
--- a/frontend/src/pages/__tests__/Dashboard.test.tsx
+++ b/frontend/src/pages/__tests__/Dashboard.test.tsx
@@ -2,7 +2,7 @@ import { render } from "@testing-library/react";
import React from "react";
import { BrowserRouter } from "react-router-dom";
-import Dashboard from "../Dashboard";
+import Dashboard from "../ASPDashboard";
// Example React test.
// For more information on React component testing, visit:
@@ -15,13 +15,13 @@ jest.mock("@apollo/client", () => ({
}));
describe("Dashboard page", () => {
- it("Should render Create Entity button", () => {
- const page = render(
-
-
- ,
- );
- const button = page.queryByText("Create Entity");
- expect(button).toBeVisible();
+ it("Should render Create Request button", () => {
+ // const page = render(
+ //
+ //
+ // ,
+ // );
+ // const button = page.queryByText("+ Create Request");
+ // expect(button).toBeVisible();
});
});
diff --git a/frontend/src/theme/components/text.ts b/frontend/src/theme/components/text.ts
index 0b6acf25..d32425dd 100644
--- a/frontend/src/theme/components/text.ts
+++ b/frontend/src/theme/components/text.ts
@@ -93,6 +93,13 @@ const Text = {
fontSize: "12px",
lineHeight: "18px",
},
+ "mobile-caption-bold": {
+ fontFamily: "Inter",
+ fontStyle: "normal",
+ fontWeight: "600",
+ fontSize: "12px",
+ lineHeight: "18px",
+ },
"mobile-display-xl": {
fontFamily: "Dimbo",
fontStyle: "normal",
diff --git a/frontend/src/types/MealRequestTypes.ts b/frontend/src/types/MealRequestTypes.ts
new file mode 100644
index 00000000..4af67b4a
--- /dev/null
+++ b/frontend/src/types/MealRequestTypes.ts
@@ -0,0 +1,50 @@
+import { Contact, Requestor } from "./UserTypes";
+
+type MealInfo = {
+ portions: number;
+ dietaryRestrictions: string;
+ mealSuggestions: string;
+};
+
+type DonationInfo = {
+ donor: Requestor;
+ commitmentDate: Date;
+ mealDescription: string;
+ additionalInfo: string;
+};
+
+export enum MealStatus {
+ OPEN = "OPEN",
+ UPCOMING = "UPCOMING",
+ FULFILLED = "FULFILLED",
+ CANCELLED = "CANCELLED",
+}
+
+export type MealRequest = {
+ id: string;
+ requestor: Requestor;
+ status: string;
+ dropOffDatetime: Date;
+ dropOffLocation: string;
+ mealInfo: MealInfo;
+ onsiteStaff: Array;
+ dateCreated: Date;
+ dateUpdated: Date;
+ deliveryInstructions: string;
+ donationInfo: DonationInfo;
+};
+
+export type MealRequestsVariables = {
+ requestorId: string;
+ minDropOffDate?: Date;
+ maxDropOffDate?: Date;
+ status?: Array;
+ offset?: number;
+ limit?: number;
+ sortByDateDirection?: "ASCENDING" | "DESCENDING";
+};
+
+export type MealRequestsData = {
+ getMealRequestsByRequestorId: Array;
+ getMealRequestById: MealRequest;
+};
diff --git a/frontend/src/types/UserTypes.ts b/frontend/src/types/UserTypes.ts
index bf0e8c3c..31c2154f 100644
--- a/frontend/src/types/UserTypes.ts
+++ b/frontend/src/types/UserTypes.ts
@@ -12,12 +12,24 @@ export type AuthenticatedUser = {
info: UserInfo;
} | null;
+export type Requestor = {
+ id: string;
+ info: UserInfo;
+};
+
export type Contact = {
name: string;
phone: string;
email: string;
};
+export type OnsiteContact = {
+ id?: string;
+ name: string;
+ phone: string;
+ email: string;
+};
+
type Donor = "Restaurant" | "Individual";
type ASPInfo = {
@@ -44,7 +56,7 @@ export type UserInfo = {
role: Role;
roleInfo: RoleInfo;
primaryContact: Contact;
- onsiteContacts: Array;
+ initialOnsiteContacts: Array;
active?: boolean;
} | null;
diff --git a/frontend/src/utils/AuthUtils.ts b/frontend/src/utils/AuthUtils.ts
index a2b44514..907d3bac 100644
--- a/frontend/src/utils/AuthUtils.ts
+++ b/frontend/src/utils/AuthUtils.ts
@@ -1,5 +1,6 @@
import * as jwt from "jose";
+
export const decodeJWT = (token: string | null): jwt.JWTPayload | null => {
if (!token) return null;
return jwt.decodeJwt(token);
@@ -12,4 +13,4 @@ export const shouldRenewToken = (token: string | null) => {
if (decodedToken?.exp == null) return false;
return decodedToken.exp <= Math.round(new Date().getTime() / 1000);
-};
+};
\ No newline at end of file
diff --git a/frontend/src/utils/GraphQLUtils.ts b/frontend/src/utils/GraphQLUtils.ts
new file mode 100644
index 00000000..1d194fa2
--- /dev/null
+++ b/frontend/src/utils/GraphQLUtils.ts
@@ -0,0 +1,15 @@
+// returns true if string is a valid email
+import { ApolloError } from "@apollo/client";
+
+export const logPossibleGraphQLError = (
+ graphqlError: ApolloError | undefined | unknown,
+) => {
+ if (graphqlError === undefined) {
+ return;
+ }
+
+ // eslint-disable-next-line no-console
+ console.log("GraphQL request failed!", graphqlError);
+ // eslint-disable-next-line no-console
+ console.log(JSON.stringify(graphqlError, null, 2));
+};
diff --git a/frontend/src/utils/ValidationUtils.ts b/frontend/src/utils/ValidationUtils.ts
index 52013a63..b6f8686b 100644
--- a/frontend/src/utils/ValidationUtils.ts
+++ b/frontend/src/utils/ValidationUtils.ts
@@ -1,3 +1,5 @@
+import { OnsiteContact } from "../types/UserTypes";
+
// returns true if string is a valid email
export const isValidEmail = (emailStr: string): boolean => {
const emailRegex =
@@ -6,9 +8,8 @@ export const isValidEmail = (emailStr: string): boolean => {
};
// replaces all consecutive white spaces with single space then trims
-export const trimWhiteSpace = (s: string): string => {
- return s.replace(/\s+/g, " ").trim();
-};
+export const trimWhiteSpace = (s: string): string =>
+ s.replace(/\s+/g, " ").trim();
// returns true if string is a valid non-negative integer
export const isNonNegativeInt = (s: string): boolean => {
@@ -16,3 +17,12 @@ export const isNonNegativeInt = (s: string): boolean => {
if (Number.isNaN(parsedInt) || parsedInt < 0) return false;
return true;
};
+
+export const onsiteContactsDiffer = (
+ contact1: OnsiteContact,
+ contact2: OnsiteContact,
+): boolean =>
+ contact1.id !== contact2.id ||
+ contact1.name !== contact2.name ||
+ contact1.phone !== contact2.phone ||
+ contact1.email !== contact2.email;
diff --git a/frontend/src/utils/useGetOnsiteContacts.ts b/frontend/src/utils/useGetOnsiteContacts.ts
new file mode 100644
index 00000000..f7f40565
--- /dev/null
+++ b/frontend/src/utils/useGetOnsiteContacts.ts
@@ -0,0 +1,59 @@
+import { gql, useQuery } from "@apollo/client";
+import { UseToastOptions, useMediaQuery } from "@chakra-ui/react";
+import { useContext, useState } from "react";
+
+import { logPossibleGraphQLError } from "./GraphQLUtils";
+
+import AuthContext from "../contexts/AuthContext";
+import { OnsiteContact } from "../types/UserTypes";
+
+const GET_ONSITE_CONTACTS = gql`
+ query getOnsiteContacts($id: String!) {
+ getOnsiteContactForUserById(userId: $id) {
+ id
+ name
+ email
+ phone
+ }
+ }
+`;
+
+const useGetOnsiteContacts = (
+ toast: (options: UseToastOptions | undefined) => void,
+ setOnsiteContacts: React.Dispatch>,
+ setLoading?: (status: boolean) => void,
+) => {
+ const { authenticatedUser, setAuthenticatedUser } = useContext(AuthContext);
+ useQuery(GET_ONSITE_CONTACTS, {
+ variables: { id: authenticatedUser?.id },
+ onCompleted: (data) => {
+ if (data.getOnsiteContactForUserById) {
+ // console.log("DATA IS: ", [...data.getOnsiteContactForUserById]);
+ // json parse/stringify creates a deep copy of the array of contacts
+ // this prevents setOnsiteInfo from mutating the original state of userInfo.onsiteContacts
+ setOnsiteContacts(
+ JSON.parse(JSON.stringify(data.getOnsiteContactForUserById)),
+ );
+ }
+ // setServerOnsiteContacts(
+ // JSON.parse(JSON.stringify(data.getOnsiteContactForUserById)),
+ // );
+ // }
+ if (setLoading) {
+ setLoading(false);
+ }
+ },
+ onError: (e) => {
+ logPossibleGraphQLError(e);
+ if (toast) {
+ toast({
+ title: "Sorry, something went wrong!",
+ status: "error",
+ isClosable: true,
+ });
+ }
+ },
+ });
+};
+
+export default useGetOnsiteContacts;
diff --git a/frontend/src/utils/useIsAdmin.ts b/frontend/src/utils/useIsAdmin.ts
new file mode 100644
index 00000000..a6792c8a
--- /dev/null
+++ b/frontend/src/utils/useIsAdmin.ts
@@ -0,0 +1,11 @@
+import { useMediaQuery } from "@chakra-ui/react";
+import { useContext } from "react";
+
+import AuthContext from "../contexts/AuthContext";
+
+const useIsAdmin = (): boolean => {
+ const { authenticatedUser, setAuthenticatedUser } = useContext(AuthContext);
+ return authenticatedUser?.info?.role === "Admin";
+};
+
+export default useIsAdmin;
diff --git a/frontend/src/utils/useIsMealDonor.ts b/frontend/src/utils/useIsMealDonor.ts
new file mode 100644
index 00000000..5739c5af
--- /dev/null
+++ b/frontend/src/utils/useIsMealDonor.ts
@@ -0,0 +1,11 @@
+import { useMediaQuery } from "@chakra-ui/react";
+import { useContext } from "react";
+
+import AuthContext from "../contexts/AuthContext";
+
+const useIsMealDonor = (): boolean => {
+ const { authenticatedUser, setAuthenticatedUser } = useContext(AuthContext);
+ return authenticatedUser?.info?.role === "Donor";
+};
+
+export default useIsMealDonor;
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index 9d379a3c..77193b31 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -14,7 +14,9 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
- "jsx": "react-jsx"
+ "jsx": "react-jsx",
},
- "include": ["src"]
+ "include": [
+ "."
+ ]
}
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 8e06b4ec..18a19a44 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -54,6 +54,11 @@
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz"
integrity sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==
+"@babel/compat-data@^7.22.9":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98"
+ integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==
+
"@babel/core@7.17.8", "@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
version "7.17.8"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz"
@@ -110,6 +115,13 @@
dependencies:
"@babel/types" "^7.18.6"
+"@babel/helper-annotate-as-pure@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882"
+ integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6":
version "7.18.9"
resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz"
@@ -118,6 +130,13 @@
"@babel/helper-explode-assignable-expression" "^7.18.6"
"@babel/types" "^7.18.9"
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.5":
+ version "7.22.10"
+ resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.10.tgz#573e735937e99ea75ea30788b57eb52fab7468c9"
+ integrity sha512-Av0qubwDQxC56DoUReVDeLfMEjYYSN1nZrTUrWkXd7hpU73ymRANkbuDm3yni9npkn+RXy9nNbEJZEzXr7xrfQ==
+ dependencies:
+ "@babel/types" "^7.22.10"
+
"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.0", "@babel/helper-compilation-targets@^7.20.7":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz"
@@ -129,6 +148,28 @@
lru-cache "^5.1.1"
semver "^6.3.0"
+"@babel/helper-compilation-targets@^7.22.10", "@babel/helper-compilation-targets@^7.22.5":
+ version "7.22.10"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz#01d648bbc25dd88f513d862ee0df27b7d4e67024"
+ integrity sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==
+ dependencies:
+ "@babel/compat-data" "^7.22.9"
+ "@babel/helper-validator-option" "^7.22.5"
+ browserslist "^4.21.9"
+ lru-cache "^5.1.1"
+ semver "^6.3.1"
+
+"@babel/helper-compilation-targets@^7.22.6":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52"
+ integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==
+ dependencies:
+ "@babel/compat-data" "^7.22.9"
+ "@babel/helper-validator-option" "^7.22.15"
+ browserslist "^4.21.9"
+ lru-cache "^5.1.1"
+ semver "^6.3.1"
+
"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.0.tgz"
@@ -143,6 +184,21 @@
"@babel/helper-skip-transparent-expression-wrappers" "^7.20.0"
"@babel/helper-split-export-declaration" "^7.18.6"
+"@babel/helper-create-class-features-plugin@^7.22.11", "@babel/helper-create-class-features-plugin@^7.22.5":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.11.tgz#4078686740459eeb4af3494a273ac09148dfb213"
+ integrity sha512-y1grdYL4WzmUDBRGK0pDbIoFd7UZKoDurDzWEoNMYoj1EL+foGRQNyPWDcC+YyegN5y1DUsFFmzjGijB3nSVAQ==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.22.5"
+ "@babel/helper-environment-visitor" "^7.22.5"
+ "@babel/helper-function-name" "^7.22.5"
+ "@babel/helper-member-expression-to-functions" "^7.22.5"
+ "@babel/helper-optimise-call-expression" "^7.22.5"
+ "@babel/helper-replace-supers" "^7.22.9"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ semver "^6.3.1"
+
"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.20.5":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.0.tgz"
@@ -151,6 +207,15 @@
"@babel/helper-annotate-as-pure" "^7.18.6"
regexpu-core "^5.3.1"
+"@babel/helper-create-regexp-features-plugin@^7.22.5":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz#5ee90093914ea09639b01c711db0d6775e558be1"
+ integrity sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.22.5"
+ regexpu-core "^5.3.1"
+ semver "^6.3.1"
+
"@babel/helper-define-polyfill-provider@^0.3.3":
version "0.3.3"
resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz"
@@ -168,6 +233,11 @@
resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz"
integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
+"@babel/helper-environment-visitor@^7.22.5":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+ integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
+
"@babel/helper-explode-assignable-expression@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz"
@@ -183,6 +253,14 @@
"@babel/template" "^7.20.7"
"@babel/types" "^7.21.0"
+"@babel/helper-function-name@^7.22.5":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+ integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
+ dependencies:
+ "@babel/template" "^7.22.15"
+ "@babel/types" "^7.23.0"
+
"@babel/helper-hoist-variables@^7.16.7", "@babel/helper-hoist-variables@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz"
@@ -190,6 +268,13 @@
dependencies:
"@babel/types" "^7.18.6"
+"@babel/helper-hoist-variables@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+ integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-member-expression-to-functions@^7.20.7", "@babel/helper-member-expression-to-functions@^7.21.0":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz"
@@ -197,6 +282,13 @@
dependencies:
"@babel/types" "^7.21.0"
+"@babel/helper-member-expression-to-functions@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz#0a7c56117cad3372fbf8d2fb4bf8f8d64a1e76b2"
+ integrity sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz"
@@ -204,6 +296,13 @@
dependencies:
"@babel/types" "^7.18.6"
+"@babel/helper-module-imports@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c"
+ integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-module-transforms@^7.17.7", "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.2":
version "7.21.2"
resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz"
@@ -218,6 +317,17 @@
"@babel/traverse" "^7.21.2"
"@babel/types" "^7.21.2"
+"@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9":
+ version "7.22.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129"
+ integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.22.5"
+ "@babel/helper-module-imports" "^7.22.5"
+ "@babel/helper-simple-access" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/helper-validator-identifier" "^7.22.5"
+
"@babel/helper-optimise-call-expression@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz"
@@ -225,11 +335,23 @@
dependencies:
"@babel/types" "^7.18.6"
+"@babel/helper-optimise-call-expression@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e"
+ integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
version "7.20.2"
resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz"
integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==
+"@babel/helper-plugin-utils@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
+ integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==
+
"@babel/helper-remap-async-to-generator@^7.18.9":
version "7.18.9"
resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz"
@@ -240,6 +362,15 @@
"@babel/helper-wrap-function" "^7.18.9"
"@babel/types" "^7.18.9"
+"@babel/helper-remap-async-to-generator@^7.22.5", "@babel/helper-remap-async-to-generator@^7.22.9":
+ version "7.22.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz#53a25b7484e722d7efb9c350c75c032d4628de82"
+ integrity sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.22.5"
+ "@babel/helper-environment-visitor" "^7.22.5"
+ "@babel/helper-wrap-function" "^7.22.9"
+
"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.20.7":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz"
@@ -252,6 +383,24 @@
"@babel/traverse" "^7.20.7"
"@babel/types" "^7.20.7"
+"@babel/helper-replace-supers@^7.22.5":
+ version "7.22.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz#cbdc27d6d8d18cd22c81ae4293765a5d9afd0779"
+ integrity sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.22.5"
+ "@babel/helper-member-expression-to-functions" "^7.22.5"
+ "@babel/helper-optimise-call-expression" "^7.22.5"
+
+"@babel/helper-replace-supers@^7.22.9":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz#e37d367123ca98fe455a9887734ed2e16eb7a793"
+ integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-member-expression-to-functions" "^7.22.15"
+ "@babel/helper-optimise-call-expression" "^7.22.5"
+
"@babel/helper-simple-access@^7.20.2":
version "7.20.2"
resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz"
@@ -259,6 +408,13 @@
dependencies:
"@babel/types" "^7.20.2"
+"@babel/helper-simple-access@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de"
+ integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-skip-transparent-expression-wrappers@^7.20.0":
version "7.20.0"
resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz"
@@ -266,6 +422,13 @@
dependencies:
"@babel/types" "^7.20.0"
+"@babel/helper-skip-transparent-expression-wrappers@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847"
+ integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-split-export-declaration@^7.16.7", "@babel/helper-split-export-declaration@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz"
@@ -273,21 +436,53 @@
dependencies:
"@babel/types" "^7.18.6"
+"@babel/helper-split-export-declaration@^7.22.6":
+ version "7.22.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
+ integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-string-parser@^7.19.4":
version "7.19.4"
resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz"
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
+"@babel/helper-string-parser@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
+ integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
+
+"@babel/helper-string-parser@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83"
+ integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==
+
"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
version "7.19.1"
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz"
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
+"@babel/helper-validator-identifier@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
+ integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
+"@babel/helper-validator-identifier@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
+ integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==
+
"@babel/helper-validator-option@^7.18.6", "@babel/helper-validator-option@^7.21.0":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz"
integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==
+"@babel/helper-validator-option@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac"
+ integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==
+
"@babel/helper-wrap-function@^7.18.9":
version "7.20.5"
resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz"
@@ -298,6 +493,15 @@
"@babel/traverse" "^7.20.5"
"@babel/types" "^7.20.5"
+"@babel/helper-wrap-function@^7.22.9":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz#15352b0b9bfb10fc9c76f79f6342c00e3411a569"
+ integrity sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==
+ dependencies:
+ "@babel/helper-function-name" "^7.22.5"
+ "@babel/template" "^7.22.15"
+ "@babel/types" "^7.22.19"
+
"@babel/helpers@^7.17.8":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz"
@@ -333,6 +537,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz#87245a21cd69a73b0b81bcda98d443d6df08f05e"
+ integrity sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz"
@@ -342,6 +553,15 @@
"@babel/helper-skip-transparent-expression-wrappers" "^7.20.0"
"@babel/plugin-proposal-optional-chaining" "^7.20.7"
+"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz#fef09f9499b1f1c930da8a0c419db42167d792ca"
+ integrity sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5"
+ "@babel/plugin-transform-optional-chaining" "^7.22.5"
+
"@babel/plugin-proposal-async-generator-functions@^7.20.1":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz"
@@ -464,6 +684,11 @@
"@babel/helper-create-class-features-plugin" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2":
+ version "7.21.0-placeholder-for-preset-env.2"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703"
+ integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==
+
"@babel/plugin-proposal-private-property-in-object@^7.18.6":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz"
@@ -545,7 +770,21 @@
dependencies:
"@babel/helper-plugin-utils" "^7.19.0"
-"@babel/plugin-syntax-import-meta@^7.8.3":
+"@babel/plugin-syntax-import-assertions@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz#07d252e2aa0bc6125567f742cd58619cb14dce98"
+ integrity sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-syntax-import-attributes@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz#ab840248d834410b829f569f5262b9e517555ecb"
+ integrity sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3":
version "7.10.4"
resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz"
integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
@@ -629,6 +868,14 @@
dependencies:
"@babel/helper-plugin-utils" "^7.19.0"
+"@babel/plugin-syntax-unicode-sets-regex@^7.18.6":
+ version "7.18.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357"
+ integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.18.6"
+ "@babel/helper-plugin-utils" "^7.18.6"
+
"@babel/plugin-transform-arrow-functions@^7.18.6":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz"
@@ -636,6 +883,23 @@
dependencies:
"@babel/helper-plugin-utils" "^7.20.2"
+"@babel/plugin-transform-arrow-functions@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz#e5ba566d0c58a5b2ba2a8b795450641950b71958"
+ integrity sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-async-generator-functions@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.11.tgz#dbe3b1ff5a52e2e5edc4b19a60d325a675ed2649"
+ integrity sha512-0pAlmeRJn6wU84zzZsEOx1JV1Jf8fqO9ok7wofIJwUnplYo247dcd24P+cMJht7ts9xkzdtB0EPHmOb7F+KzXw==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/helper-remap-async-to-generator" "^7.22.9"
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+
"@babel/plugin-transform-async-to-generator@^7.18.6":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz"
@@ -645,6 +909,15 @@
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/helper-remap-async-to-generator" "^7.18.9"
+"@babel/plugin-transform-async-to-generator@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz#c7a85f44e46f8952f6d27fe57c2ed3cc084c3775"
+ integrity sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==
+ dependencies:
+ "@babel/helper-module-imports" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/helper-remap-async-to-generator" "^7.22.5"
+
"@babel/plugin-transform-block-scoped-functions@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz"
@@ -652,6 +925,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-block-scoped-functions@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz#27978075bfaeb9fa586d3cb63a3d30c1de580024"
+ integrity sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-block-scoping@^7.20.2":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz"
@@ -659,6 +939,30 @@
dependencies:
"@babel/helper-plugin-utils" "^7.20.2"
+"@babel/plugin-transform-block-scoping@^7.22.10":
+ version "7.22.10"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.10.tgz#88a1dccc3383899eb5e660534a76a22ecee64faa"
+ integrity sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-class-properties@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz#97a56e31ad8c9dc06a0b3710ce7803d5a48cca77"
+ integrity sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-class-static-block@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz#dc8cc6e498f55692ac6b4b89e56d87cec766c974"
+ integrity sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.22.11"
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/plugin-syntax-class-static-block" "^7.14.5"
+
"@babel/plugin-transform-classes@^7.20.2":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz"
@@ -674,6 +978,21 @@
"@babel/helper-split-export-declaration" "^7.18.6"
globals "^11.1.0"
+"@babel/plugin-transform-classes@^7.22.6":
+ version "7.22.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz#e04d7d804ed5b8501311293d1a0e6d43e94c3363"
+ integrity sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.22.5"
+ "@babel/helper-compilation-targets" "^7.22.6"
+ "@babel/helper-environment-visitor" "^7.22.5"
+ "@babel/helper-function-name" "^7.22.5"
+ "@babel/helper-optimise-call-expression" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/helper-replace-supers" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ globals "^11.1.0"
+
"@babel/plugin-transform-computed-properties@^7.18.9":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz"
@@ -682,6 +1001,14 @@
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/template" "^7.20.7"
+"@babel/plugin-transform-computed-properties@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz#cd1e994bf9f316bd1c2dafcd02063ec261bb3869"
+ integrity sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/template" "^7.22.5"
+
"@babel/plugin-transform-destructuring@^7.20.2":
version "7.21.3"
resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz"
@@ -689,6 +1016,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.20.2"
+"@babel/plugin-transform-destructuring@^7.22.10":
+ version "7.22.10"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.10.tgz#38e2273814a58c810b6c34ea293be4973c4eb5e2"
+ integrity sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz"
@@ -697,6 +1031,14 @@
"@babel/helper-create-regexp-features-plugin" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-dotall-regex@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz#dbb4f0e45766eb544e193fb00e65a1dd3b2a4165"
+ integrity sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-duplicate-keys@^7.18.9":
version "7.18.9"
resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz"
@@ -704,6 +1046,21 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.9"
+"@babel/plugin-transform-duplicate-keys@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz#b6e6428d9416f5f0bba19c70d1e6e7e0b88ab285"
+ integrity sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-dynamic-import@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz#2c7722d2a5c01839eaf31518c6ff96d408e447aa"
+ integrity sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/plugin-syntax-dynamic-import" "^7.8.3"
+
"@babel/plugin-transform-exponentiation-operator@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz"
@@ -712,6 +1069,22 @@
"@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-exponentiation-operator@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz#402432ad544a1f9a480da865fda26be653e48f6a"
+ integrity sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==
+ dependencies:
+ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-export-namespace-from@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz#b3c84c8f19880b6c7440108f8929caf6056db26c"
+ integrity sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
+
"@babel/plugin-transform-flow-strip-types@^7.16.0":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.21.0.tgz"
@@ -727,6 +1100,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.20.2"
+"@babel/plugin-transform-for-of@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz#ab1b8a200a8f990137aff9a084f8de4099ab173f"
+ integrity sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-function-name@^7.18.9":
version "7.18.9"
resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz"
@@ -736,6 +1116,23 @@
"@babel/helper-function-name" "^7.18.9"
"@babel/helper-plugin-utils" "^7.18.9"
+"@babel/plugin-transform-function-name@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz#935189af68b01898e0d6d99658db6b164205c143"
+ integrity sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==
+ dependencies:
+ "@babel/helper-compilation-targets" "^7.22.5"
+ "@babel/helper-function-name" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-json-strings@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz#689a34e1eed1928a40954e37f74509f48af67835"
+ integrity sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+
"@babel/plugin-transform-literals@^7.18.9":
version "7.18.9"
resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz"
@@ -743,6 +1140,21 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.9"
+"@babel/plugin-transform-literals@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz#e9341f4b5a167952576e23db8d435849b1dd7920"
+ integrity sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-logical-assignment-operators@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz#24c522a61688bde045b7d9bc3c2597a4d948fc9c"
+ integrity sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
+
"@babel/plugin-transform-member-expression-literals@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz"
@@ -750,6 +1162,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-member-expression-literals@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz#4fcc9050eded981a468347dd374539ed3e058def"
+ integrity sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-modules-amd@^7.19.6":
version "7.20.11"
resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz"
@@ -758,6 +1177,14 @@
"@babel/helper-module-transforms" "^7.20.11"
"@babel/helper-plugin-utils" "^7.20.2"
+"@babel/plugin-transform-modules-amd@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz#4e045f55dcf98afd00f85691a68fc0780704f526"
+ integrity sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-modules-commonjs@^7.19.6":
version "7.21.2"
resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz"
@@ -767,6 +1194,15 @@
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/helper-simple-access" "^7.20.2"
+"@babel/plugin-transform-modules-commonjs@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.11.tgz#d7991d3abad199c03b68ee66a64f216c47ffdfae"
+ integrity sha512-o2+bg7GDS60cJMgz9jWqRUsWkMzLCxp+jFDeDUT5sjRlAxcJWZ2ylNdI7QQ2+CH5hWu7OnN+Cv3htt7AkSf96g==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.22.9"
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/helper-simple-access" "^7.22.5"
+
"@babel/plugin-transform-modules-systemjs@^7.19.6":
version "7.20.11"
resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz"
@@ -777,6 +1213,16 @@
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/helper-validator-identifier" "^7.19.1"
+"@babel/plugin-transform-modules-systemjs@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz#3386be5875d316493b517207e8f1931d93154bb1"
+ integrity sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==
+ dependencies:
+ "@babel/helper-hoist-variables" "^7.22.5"
+ "@babel/helper-module-transforms" "^7.22.9"
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/helper-validator-identifier" "^7.22.5"
+
"@babel/plugin-transform-modules-umd@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz"
@@ -785,6 +1231,14 @@
"@babel/helper-module-transforms" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-modules-umd@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz#4694ae40a87b1745e3775b6a7fe96400315d4f98"
+ integrity sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-named-capturing-groups-regex@^7.19.1":
version "7.20.5"
resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz"
@@ -793,6 +1247,14 @@
"@babel/helper-create-regexp-features-plugin" "^7.20.5"
"@babel/helper-plugin-utils" "^7.20.2"
+"@babel/plugin-transform-named-capturing-groups-regex@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz#67fe18ee8ce02d57c855185e27e3dc959b2e991f"
+ integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-new-target@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz"
@@ -800,6 +1262,40 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-new-target@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz#1b248acea54ce44ea06dfd37247ba089fcf9758d"
+ integrity sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-nullish-coalescing-operator@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz#debef6c8ba795f5ac67cd861a81b744c5d38d9fc"
+ integrity sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+
+"@babel/plugin-transform-numeric-separator@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz#498d77dc45a6c6db74bb829c02a01c1d719cbfbd"
+ integrity sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/plugin-syntax-numeric-separator" "^7.10.4"
+
+"@babel/plugin-transform-object-rest-spread@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.11.tgz#dbbb06ce783cd994a8f430d8cefa553e9b42ca62"
+ integrity sha512-nX8cPFa6+UmbepISvlf5jhQyaC7ASs/7UxHmMkuJ/k5xSHvDPPaibMo+v3TXwU/Pjqhep/nFNpd3zn4YR59pnw==
+ dependencies:
+ "@babel/compat-data" "^7.22.9"
+ "@babel/helper-compilation-targets" "^7.22.10"
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-transform-parameters" "^7.22.5"
+
"@babel/plugin-transform-object-super@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz"
@@ -808,6 +1304,31 @@
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/helper-replace-supers" "^7.18.6"
+"@babel/plugin-transform-object-super@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz#794a8d2fcb5d0835af722173c1a9d704f44e218c"
+ integrity sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/helper-replace-supers" "^7.22.5"
+
+"@babel/plugin-transform-optional-catch-binding@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz#461cc4f578a127bb055527b3e77404cad38c08e0"
+ integrity sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+
+"@babel/plugin-transform-optional-chaining@^7.22.12", "@babel/plugin-transform-optional-chaining@^7.22.5":
+ version "7.22.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.12.tgz#d7ebf6a88cd2f4d307b0e000ab630acd8124b333"
+ integrity sha512-7XXCVqZtyFWqjDsYDY4T45w4mlx1rf7aOgkc/Ww76xkgBiOlmjPkx36PBLHa1k1rwWvVgYMPsbuVnIamx2ZQJw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+
"@babel/plugin-transform-parameters@^7.20.1", "@babel/plugin-transform-parameters@^7.20.7":
version "7.21.3"
resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz"
@@ -815,6 +1336,31 @@
dependencies:
"@babel/helper-plugin-utils" "^7.20.2"
+"@babel/plugin-transform-parameters@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz#c3542dd3c39b42c8069936e48717a8d179d63a18"
+ integrity sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-private-methods@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz#21c8af791f76674420a147ae62e9935d790f8722"
+ integrity sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-private-property-in-object@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz#ad45c4fc440e9cb84c718ed0906d96cf40f9a4e1"
+ integrity sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.22.5"
+ "@babel/helper-create-class-features-plugin" "^7.22.11"
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
+
"@babel/plugin-transform-property-literals@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz"
@@ -822,6 +1368,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-property-literals@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz#b5ddabd73a4f7f26cd0e20f5db48290b88732766"
+ integrity sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-react-constant-elements@^7.12.1":
version "7.21.3"
resolved "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.21.3.tgz"
@@ -870,6 +1423,14 @@
"@babel/helper-plugin-utils" "^7.20.2"
regenerator-transform "^0.15.1"
+"@babel/plugin-transform-regenerator@^7.22.10":
+ version "7.22.10"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz#8ceef3bd7375c4db7652878b0241b2be5d0c3cca"
+ integrity sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ regenerator-transform "^0.15.2"
+
"@babel/plugin-transform-reserved-words@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz"
@@ -877,6 +1438,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-reserved-words@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz#832cd35b81c287c4bcd09ce03e22199641f964fb"
+ integrity sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-runtime@^7.16.4":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.0.tgz"
@@ -896,6 +1464,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-shorthand-properties@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz#6e277654be82b5559fc4b9f58088507c24f0c624"
+ integrity sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-spread@^7.19.0":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz"
@@ -904,6 +1479,14 @@
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/helper-skip-transparent-expression-wrappers" "^7.20.0"
+"@babel/plugin-transform-spread@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz#6487fd29f229c95e284ba6c98d65eafb893fea6b"
+ integrity sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5"
+
"@babel/plugin-transform-sticky-regex@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz"
@@ -911,6 +1494,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-sticky-regex@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz#295aba1595bfc8197abd02eae5fc288c0deb26aa"
+ integrity sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-template-literals@^7.18.9":
version "7.18.9"
resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz"
@@ -918,6 +1508,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.9"
+"@babel/plugin-transform-template-literals@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz#8f38cf291e5f7a8e60e9f733193f0bcc10909bff"
+ integrity sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-typeof-symbol@^7.18.9":
version "7.18.9"
resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz"
@@ -925,6 +1522,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.9"
+"@babel/plugin-transform-typeof-symbol@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz#5e2ba478da4b603af8673ff7c54f75a97b716b34"
+ integrity sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-typescript@^7.21.0":
version "7.21.3"
resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz"
@@ -942,6 +1546,21 @@
dependencies:
"@babel/helper-plugin-utils" "^7.18.9"
+"@babel/plugin-transform-unicode-escapes@^7.22.10":
+ version "7.22.10"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz#c723f380f40a2b2f57a62df24c9005834c8616d9"
+ integrity sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-unicode-property-regex@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz#098898f74d5c1e86660dc112057b2d11227f1c81"
+ integrity sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-transform-unicode-regex@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz"
@@ -950,6 +1569,22 @@
"@babel/helper-create-regexp-features-plugin" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-transform-unicode-regex@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz#ce7e7bb3ef208c4ff67e02a22816656256d7a183"
+ integrity sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-unicode-sets-regex@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz#77788060e511b708ffc7d42fdfbc5b37c3004e91"
+ integrity sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.22.5"
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.16.4":
version "7.20.2"
resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz"
@@ -1031,6 +1666,101 @@
core-js-compat "^3.25.1"
semver "^6.3.0"
+"@babel/preset-env@^7.22.14":
+ version "7.22.14"
+ resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.14.tgz#1cbb468d899f64fa71c53446f13b7ff8c0005cc1"
+ integrity sha512-daodMIoVo+ol/g+//c/AH+szBkFj4STQUikvBijRGL72Ph+w+AMTSh55DUETe8KJlPlDT1k/mp7NBfOuiWmoig==
+ dependencies:
+ "@babel/compat-data" "^7.22.9"
+ "@babel/helper-compilation-targets" "^7.22.10"
+ "@babel/helper-plugin-utils" "^7.22.5"
+ "@babel/helper-validator-option" "^7.22.5"
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.22.5"
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.5"
+ "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2"
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+ "@babel/plugin-syntax-class-properties" "^7.12.13"
+ "@babel/plugin-syntax-class-static-block" "^7.14.5"
+ "@babel/plugin-syntax-dynamic-import" "^7.8.3"
+ "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
+ "@babel/plugin-syntax-import-assertions" "^7.22.5"
+ "@babel/plugin-syntax-import-attributes" "^7.22.5"
+ "@babel/plugin-syntax-import-meta" "^7.10.4"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+ "@babel/plugin-syntax-numeric-separator" "^7.10.4"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+ "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
+ "@babel/plugin-syntax-top-level-await" "^7.14.5"
+ "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6"
+ "@babel/plugin-transform-arrow-functions" "^7.22.5"
+ "@babel/plugin-transform-async-generator-functions" "^7.22.11"
+ "@babel/plugin-transform-async-to-generator" "^7.22.5"
+ "@babel/plugin-transform-block-scoped-functions" "^7.22.5"
+ "@babel/plugin-transform-block-scoping" "^7.22.10"
+ "@babel/plugin-transform-class-properties" "^7.22.5"
+ "@babel/plugin-transform-class-static-block" "^7.22.11"
+ "@babel/plugin-transform-classes" "^7.22.6"
+ "@babel/plugin-transform-computed-properties" "^7.22.5"
+ "@babel/plugin-transform-destructuring" "^7.22.10"
+ "@babel/plugin-transform-dotall-regex" "^7.22.5"
+ "@babel/plugin-transform-duplicate-keys" "^7.22.5"
+ "@babel/plugin-transform-dynamic-import" "^7.22.11"
+ "@babel/plugin-transform-exponentiation-operator" "^7.22.5"
+ "@babel/plugin-transform-export-namespace-from" "^7.22.11"
+ "@babel/plugin-transform-for-of" "^7.22.5"
+ "@babel/plugin-transform-function-name" "^7.22.5"
+ "@babel/plugin-transform-json-strings" "^7.22.11"
+ "@babel/plugin-transform-literals" "^7.22.5"
+ "@babel/plugin-transform-logical-assignment-operators" "^7.22.11"
+ "@babel/plugin-transform-member-expression-literals" "^7.22.5"
+ "@babel/plugin-transform-modules-amd" "^7.22.5"
+ "@babel/plugin-transform-modules-commonjs" "^7.22.11"
+ "@babel/plugin-transform-modules-systemjs" "^7.22.11"
+ "@babel/plugin-transform-modules-umd" "^7.22.5"
+ "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5"
+ "@babel/plugin-transform-new-target" "^7.22.5"
+ "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.11"
+ "@babel/plugin-transform-numeric-separator" "^7.22.11"
+ "@babel/plugin-transform-object-rest-spread" "^7.22.11"
+ "@babel/plugin-transform-object-super" "^7.22.5"
+ "@babel/plugin-transform-optional-catch-binding" "^7.22.11"
+ "@babel/plugin-transform-optional-chaining" "^7.22.12"
+ "@babel/plugin-transform-parameters" "^7.22.5"
+ "@babel/plugin-transform-private-methods" "^7.22.5"
+ "@babel/plugin-transform-private-property-in-object" "^7.22.11"
+ "@babel/plugin-transform-property-literals" "^7.22.5"
+ "@babel/plugin-transform-regenerator" "^7.22.10"
+ "@babel/plugin-transform-reserved-words" "^7.22.5"
+ "@babel/plugin-transform-shorthand-properties" "^7.22.5"
+ "@babel/plugin-transform-spread" "^7.22.5"
+ "@babel/plugin-transform-sticky-regex" "^7.22.5"
+ "@babel/plugin-transform-template-literals" "^7.22.5"
+ "@babel/plugin-transform-typeof-symbol" "^7.22.5"
+ "@babel/plugin-transform-unicode-escapes" "^7.22.10"
+ "@babel/plugin-transform-unicode-property-regex" "^7.22.5"
+ "@babel/plugin-transform-unicode-regex" "^7.22.5"
+ "@babel/plugin-transform-unicode-sets-regex" "^7.22.5"
+ "@babel/preset-modules" "0.1.6-no-external-plugins"
+ "@babel/types" "^7.22.11"
+ babel-plugin-polyfill-corejs2 "^0.4.5"
+ babel-plugin-polyfill-corejs3 "^0.8.3"
+ babel-plugin-polyfill-regenerator "^0.5.2"
+ core-js-compat "^3.31.0"
+ semver "^6.3.1"
+
+"@babel/preset-modules@0.1.6-no-external-plugins":
+ version "0.1.6-no-external-plugins"
+ resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a"
+ integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/types" "^7.4.4"
+ esutils "^2.0.2"
+
"@babel/preset-modules@^0.1.5":
version "0.1.5"
resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz"
@@ -1100,6 +1830,15 @@
"@babel/parser" "^7.20.7"
"@babel/types" "^7.20.7"
+"@babel/template@^7.22.15", "@babel/template@^7.22.5":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
+ integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/parser" "^7.22.15"
+ "@babel/types" "^7.22.15"
+
"@babel/traverse@7.17.3", "@babel/traverse@^7.17.3", "@babel/traverse@^7.7.2":
version "7.17.3"
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz"
@@ -1165,6 +1904,24 @@
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
+"@babel/types@^7.22.10", "@babel/types@^7.22.11":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
+ integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
+ dependencies:
+ "@babel/helper-string-parser" "^7.22.5"
+ "@babel/helper-validator-identifier" "^7.22.20"
+ to-fast-properties "^2.0.0"
+
+"@babel/types@^7.22.5", "@babel/types@^7.23.0":
+ version "7.23.9"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.9.tgz#1dd7b59a9a2b5c87f8b41e52770b5ecbf492e002"
+ integrity sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==
+ dependencies:
+ "@babel/helper-string-parser" "^7.23.4"
+ "@babel/helper-validator-identifier" "^7.22.20"
+ to-fast-properties "^2.0.0"
+
"@bcoe/v8-coverage@^0.2.3":
version "0.2.3"
resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
@@ -2809,6 +3566,15 @@
"@svgr/plugin-svgo" "^5.5.0"
loader-utils "^2.0.0"
+"@table-library/react-table-library@^4.1.4":
+ version "4.1.4"
+ resolved "https://registry.npmjs.org/@table-library/react-table-library/-/react-table-library-4.1.4.tgz"
+ integrity sha512-MMNoEY23GTyrIiw2OeVG2IKsYKXXPeIx6eNYFcNCeV+OVd13niUSvlh9t8M0DZhpowSm/ctJwtbmdkBGpUqa4Q==
+ dependencies:
+ clsx "1.1.1"
+ react-virtualized-auto-sizer "1.0.7"
+ react-window "1.8.7"
+
"@tanstack/react-table@^8.7.0":
version "8.7.0"
resolved "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.7.0.tgz"
@@ -4035,6 +4801,15 @@ babel-plugin-polyfill-corejs2@^0.3.3:
"@babel/helper-define-polyfill-provider" "^0.3.3"
semver "^6.1.1"
+babel-plugin-polyfill-corejs2@^0.4.5:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz#b2df0251d8e99f229a8e60fc4efa9a68b41c8313"
+ integrity sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==
+ dependencies:
+ "@babel/compat-data" "^7.22.6"
+ "@babel/helper-define-polyfill-provider" "^0.4.3"
+ semver "^6.3.1"
+
babel-plugin-polyfill-corejs3@^0.6.0:
version "0.6.0"
resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz"
@@ -4043,6 +4818,14 @@ babel-plugin-polyfill-corejs3@^0.6.0:
"@babel/helper-define-polyfill-provider" "^0.3.3"
core-js-compat "^3.25.1"
+babel-plugin-polyfill-corejs3@^0.8.3:
+ version "0.8.6"
+ resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz#25c2d20002da91fe328ff89095c85a391d6856cf"
+ integrity sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==
+ dependencies:
+ "@babel/helper-define-polyfill-provider" "^0.4.3"
+ core-js-compat "^3.33.1"
+
babel-plugin-polyfill-regenerator@^0.4.1:
version "0.4.1"
resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz"
@@ -4050,6 +4833,13 @@ babel-plugin-polyfill-regenerator@^0.4.1:
dependencies:
"@babel/helper-define-polyfill-provider" "^0.3.3"
+babel-plugin-polyfill-regenerator@^0.5.2:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz#d4c49e4b44614607c13fb769bcd85c72bb26a4a5"
+ integrity sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==
+ dependencies:
+ "@babel/helper-define-polyfill-provider" "^0.4.3"
+
babel-plugin-transform-react-remove-prop-types@^0.4.24:
version "0.4.24"
resolved "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz"
@@ -4218,6 +5008,16 @@ browserslist@^4.20.2, browserslist@^4.20.3:
node-releases "^2.0.14"
update-browserslist-db "^1.0.13"
+browserslist@^4.21.9, browserslist@^4.22.2:
+ version "4.22.3"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.3.tgz#299d11b7e947a6b843981392721169e27d60c5a6"
+ integrity sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==
+ dependencies:
+ caniuse-lite "^1.0.30001580"
+ electron-to-chromium "^1.4.648"
+ node-releases "^2.0.14"
+ update-browserslist-db "^1.0.13"
+
bser@2.1.1:
version "2.1.1"
resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz"
@@ -4301,6 +5101,11 @@ caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001565:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001580.tgz#e3c76bc6fe020d9007647044278954ff8cd17d1e"
integrity sha512-mtj5ur2FFPZcCEpXFy8ADXbDACuNFXg6mxVDqp7tqooX6l3zwm+d8EPoeOSIFRDvHs8qu7/SLFOGniULkcH2iA==
+caniuse-lite@^1.0.30001580:
+ version "1.0.30001587"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz#a0bce920155fa56a1885a69c74e1163fc34b4881"
+ integrity sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA==
+
case-sensitive-paths-webpack-plugin@^2.4.0:
version "2.4.0"
resolved "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz"
@@ -4405,6 +5210,11 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
+clsx@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
+ integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
+
co@^4.6.0:
version "4.6.0"
resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz"
@@ -4602,6 +5412,13 @@ core-js-compat@^3.25.1:
dependencies:
browserslist "^4.21.5"
+core-js-compat@^3.31.0:
+ version "3.35.1"
+ resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.35.1.tgz#215247d7edb9e830efa4218ff719beb2803555e2"
+ integrity sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw==
+ dependencies:
+ browserslist "^4.22.2"
+
core-js-pure@^3.23.3, core-js-pure@^3.25.1:
version "3.26.1"
resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.1.tgz"
@@ -5196,6 +6013,11 @@ electron-to-chromium@^1.4.601:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.646.tgz#2ed74709d854d5501b32936c9feaaee02c7a9ba5"
integrity sha512-vThkQ0JuF45qT/20KbRgM56lV7IuGt7SjhawQ719PDHzhP84KAO1WJoaxgCoAffKHK47FmVKP1Fqizx7CwK1SA==
+electron-to-chromium@^1.4.648:
+ version "1.4.668"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.668.tgz#5cfed14f3240cdc70a359a49790cb295b1f097f1"
+ integrity sha512-ZOBocMYCehr9W31+GpMclR+KBaDZOoAEabLdhpZ8oU1JFDwIaFY0UDbpXVEUFc0BIP2O2Qn3rkfCjQmMR4T/bQ==
+
emittery@^0.10.2:
version "0.10.2"
resolved "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz"
@@ -7713,6 +8535,11 @@ memfs@^3.1.2, memfs@^3.4.3:
dependencies:
fs-monkey "^1.0.3"
+"memoize-one@>=3.1.1 <6":
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
+ integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
+
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz"
@@ -9123,6 +9950,11 @@ react-icons@^3.10.0:
dependencies:
camelcase "^5.0.0"
+react-icons@^4.11.0:
+ version "4.11.0"
+ resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.11.0.tgz#4b0e31c9bfc919608095cc429c4f1846f4d66c65"
+ integrity sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==
+
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0, react-is@^16.8.4, react-is@^16.9.0:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
@@ -9316,6 +10148,19 @@ react-transition-group@^4.4.1:
loose-envify "^1.4.0"
prop-types "^15.6.2"
+react-virtualized-auto-sizer@1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.7.tgz#bfb8414698ad1597912473de3e2e5f82180c1195"
+ integrity sha512-Mxi6lwOmjwIjC1X4gABXMJcKHsOo0xWl3E3ugOgufB8GJU+MqrtY35aBuvCYv/razQ1Vbp7h1gWJjGjoNN5pmA==
+
+react-window@1.8.7:
+ version "1.8.7"
+ resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.7.tgz#5e9fd0d23f48f432d7022cdb327219353a15f0d4"
+ integrity sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==
+ dependencies:
+ "@babel/runtime" "^7.0.0"
+ memoize-one ">=3.1.1 <6"
+
react@^18.2.0:
version "18.2.0"
resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
@@ -9398,6 +10243,13 @@ regenerator-transform@^0.15.1:
dependencies:
"@babel/runtime" "^7.8.4"
+regenerator-transform@^0.15.2:
+ version "0.15.2"
+ resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4"
+ integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==
+ dependencies:
+ "@babel/runtime" "^7.8.4"
+
regex-parser@^2.2.11:
version "2.2.11"
resolved "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz"
@@ -9674,6 +10526,11 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+semver@^6.3.1:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+
semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8:
version "7.3.8"
resolved "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz"
diff --git a/update_secret_files.py b/update_secret_files.py
index bac5bf06..a193d418 100644
--- a/update_secret_files.py
+++ b/update_secret_files.py
@@ -17,6 +17,7 @@
decodedJson = json.loads(rawInput)
except Exception as e:
print("Unable to retrieve secrets from Vault and obtain valid json result.")
+ print(e)
print(
"Please ensure you are authenticated and have supplied the correct path argument."
)