From cd2397f4f707abda451548dc790d77b0703d04c1 Mon Sep 17 00:00:00 2001
From: swve
Date: Tue, 2 Jul 2024 20:37:00 +0200
Subject: [PATCH 01/25] wip1
---
apps/api/src/db/assignments.py | 133 +++++++++++++++++++++++++++++++++
1 file changed, 133 insertions(+)
create mode 100644 apps/api/src/db/assignments.py
diff --git a/apps/api/src/db/assignments.py b/apps/api/src/db/assignments.py
new file mode 100644
index 00000000..9d8788d5
--- /dev/null
+++ b/apps/api/src/db/assignments.py
@@ -0,0 +1,133 @@
+from typing import Optional
+from openai import BaseModel
+from sqlalchemy import JSON, Column, ForeignKey
+from sqlmodel import Field, SQLModel
+from enum import Enum
+
+
+class AssignmentTypeEnum(str, Enum):
+ FILE_SUBMISSION = "FILE_SUBMISSION"
+ QUIZ = "QUIZ"
+ OTHER = "OTHER"
+
+
+class Assignment(SQLModel, table=True):
+ id: Optional[int] = Field(default=None, primary_key=True)
+ assignment_uuid: str
+ title: str
+ description: str
+ due_date: str
+
+ org_id: int = Field(
+ sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE"))
+ )
+ course_id: int = Field(
+ sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
+ )
+ chapter_id: int = Field(
+ sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
+ )
+ activity_id: int = Field(
+ sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
+ )
+
+ creation_date: str
+ update_date: str
+
+
+class AssignmentTask(SQLModel, table=True):
+ id: Optional[int] = Field(default=None, primary_key=True)
+ assignment_task_uuid: str = ""
+ title: str = ""
+ description: str = ""
+ hint: str = ""
+ assignment_type: AssignmentTypeEnum
+ contents: dict = Field(default={}, sa_column=Column(JSON))
+ max_grade_value: int = (
+ 0 # Value is always between 0-100 and is used as the maximum grade for the task
+ )
+
+ # Foreign keys
+ assignment_id: int = Field(
+ sa_column=Column(
+ "assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
+ )
+ )
+ org_id: int = Field(
+ sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE"))
+ )
+ course_id: int = Field(
+ sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
+ )
+ chapter_id: int = Field(
+ sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
+ )
+ activity_id: int = Field(
+ sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
+ )
+ creation_date: str
+ update_date: str
+
+
+class AssignmentTaskSubmission(SQLModel, table=True):
+ id: Optional[int] = Field(default=None, primary_key=True)
+ assignment_task_submission_uuid: str = ""
+ task_submission: dict = Field(default={}, sa_column=Column(JSON))
+ grade: int = (
+ 0 # Value is always between 0-100 depending on the questions, this is used to calculate the final grade on the AssignmentUser model
+ )
+ task_submission_grade_feedback: str = "" # Feedback given by the teacher
+
+ # Foreign keys
+ user_id: int = Field(
+ sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
+ )
+ activity_id: int = Field(
+ sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
+ )
+ course_id: int = Field(
+ sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
+ )
+ chapter_id: int = Field(
+ sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
+ )
+ assignment_task_id: int = Field(
+ sa_column=Column(
+ "assignment_task_id", ForeignKey("assignment_task.id", ondelete="CASCADE")
+ )
+ )
+ creation_date: str = ""
+ update_date: str = ""
+
+
+# Note on grading :
+# To calculate the final grade :
+
+
+
+
+class AssignmentUserSubmissionStatus(str, Enum):
+ PENDING = "PENDING"
+ SUBMITTED = "SUBMITTED"
+ GRADED = "GRADED"
+ LATE = "LATE"
+ NOT_SUBMITTED = "NOT_SUBMITTED"
+
+
+class AssignmentUserSubmission(SQLModel, table=True):
+ id: Optional[int] = Field(default=None, primary_key=True)
+ assignment_user_uuid: str = ""
+ submission_status: AssignmentUserSubmissionStatus = (
+ AssignmentUserSubmissionStatus.PENDING
+ )
+ grading: str = ""
+ user_id: int = Field(
+ sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
+ )
+ assignment_id: int = Field(
+ sa_column=Column(
+ "assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
+ )
+ )
+ creation_date: str = ""
+ update_date: str = ""
From 47782b57bc224a194eb1e0f34cc38a791f3bf198 Mon Sep 17 00:00:00 2001
From: swve
Date: Wed, 10 Jul 2024 23:35:32 +0200
Subject: [PATCH 02/25] feat: add Assignments, Tasks, Submissions CRUD
---
apps/api/poetry.lock | 61 +-
apps/api/src/db/assignments.py | 133 ---
apps/api/src/db/{ => courses}/activities.py | 0
apps/api/src/db/courses/assignments.py | 317 ++++++
apps/api/src/db/{ => courses}/blocks.py | 2 +-
.../db/{ => courses}/chapter_activities.py | 0
apps/api/src/db/{ => courses}/chapters.py | 8 +-
.../src/db/{ => courses}/course_chapters.py | 0
.../src/db/{ => courses}/course_updates.py | 0
apps/api/src/db/{ => courses}/courses.py | 4 +-
apps/api/src/db/trails.py | 9 +-
apps/api/src/router.py | 6 +-
.../courses/{ => activities}/activities.py | 2 +-
.../{ => courses/activities}/blocks.py | 2 +-
apps/api/src/routers/courses/assignments.py | 310 ++++++
apps/api/src/routers/courses/chapters.py | 2 +-
apps/api/src/routers/courses/courses.py | 4 +-
apps/api/src/security/rbac/rbac.py | 2 +-
apps/api/src/services/ai/ai.py | 4 +-
.../block_types/imageBlock/imageBlock.py | 6 +-
.../blocks/block_types/pdfBlock/pdfBlock.py | 6 +-
.../block_types/videoBlock/videoBlock.py | 6 +-
.../services/courses/activities/activities.py | 10 +-
.../courses/activities/assignments.py | 997 ++++++++++++++++++
.../src/services/courses/activities/pdf.py | 10 +-
.../src/services/courses/activities/utils.py | 4 +-
.../src/services/courses/activities/video.py | 10 +-
apps/api/src/services/courses/chapters.py | 8 +-
apps/api/src/services/courses/collections.py | 2 +-
apps/api/src/services/courses/courses.py | 2 +-
apps/api/src/services/courses/updates.py | 4 +-
apps/api/src/services/trail/trail.py | 6 +-
32 files changed, 1719 insertions(+), 218 deletions(-)
delete mode 100644 apps/api/src/db/assignments.py
rename apps/api/src/db/{ => courses}/activities.py (100%)
create mode 100644 apps/api/src/db/courses/assignments.py
rename apps/api/src/db/{ => courses}/blocks.py (96%)
rename apps/api/src/db/{ => courses}/chapter_activities.py (100%)
rename apps/api/src/db/{ => courses}/chapters.py (90%)
rename apps/api/src/db/{ => courses}/course_chapters.py (100%)
rename apps/api/src/db/{ => courses}/course_updates.py (100%)
rename apps/api/src/db/{ => courses}/courses.py (95%)
rename apps/api/src/routers/courses/{ => activities}/activities.py (97%)
rename apps/api/src/routers/{ => courses/activities}/blocks.py (98%)
create mode 100644 apps/api/src/routers/courses/assignments.py
create mode 100644 apps/api/src/services/courses/activities/assignments.py
diff --git a/apps/api/poetry.lock b/apps/api/poetry.lock
index 85625d58..deb41715 100644
--- a/apps/api/poetry.lock
+++ b/apps/api/poetry.lock
@@ -215,17 +215,17 @@ typecheck = ["mypy"]
[[package]]
name = "boto3"
-version = "1.34.137"
+version = "1.34.143"
description = "The AWS SDK for Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "boto3-1.34.137-py3-none-any.whl", hash = "sha256:7cb697d67fd138ceebc6f789919ae370c092a50c6b0ccc4ef483027935502eab"},
- {file = "boto3-1.34.137.tar.gz", hash = "sha256:0b21b84db4619b3711a6f643d465a5a25e81231ee43615c55a20ff6b89c6cc3c"},
+ {file = "boto3-1.34.143-py3-none-any.whl", hash = "sha256:0d16832f23e6bd3ae94e35ea8e625529850bfad9baccd426de96ad8f445d8e03"},
+ {file = "boto3-1.34.143.tar.gz", hash = "sha256:b590ce80c65149194def43ebf0ea1cf0533945502507837389a8d22e3ecbcf05"},
]
[package.dependencies]
-botocore = ">=1.34.137,<1.35.0"
+botocore = ">=1.34.143,<1.35.0"
jmespath = ">=0.7.1,<2.0.0"
s3transfer = ">=0.10.0,<0.11.0"
@@ -234,13 +234,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
[[package]]
name = "botocore"
-version = "1.34.137"
+version = "1.34.143"
description = "Low-level, data-driven core of boto 3."
optional = false
python-versions = ">=3.8"
files = [
- {file = "botocore-1.34.137-py3-none-any.whl", hash = "sha256:a980fa4adec4bfa23fff70a3512622e9412c69c791898a52cafc2458b0be6040"},
- {file = "botocore-1.34.137.tar.gz", hash = "sha256:e29c8e9bfda0b20a1997792968e85868bfce42fefad9730f633a81adcff3f2ef"},
+ {file = "botocore-1.34.143-py3-none-any.whl", hash = "sha256:094aea179e8aaa1bc957ad49cc27d93b189dd3a1f3075d8b0ca7c445a2a88430"},
+ {file = "botocore-1.34.143.tar.gz", hash = "sha256:059f032ec05733a836e04e869c5a15534420102f93116f3bc9a5b759b0651caf"},
]
[package.dependencies]
@@ -844,13 +844,13 @@ tqdm = ["tqdm"]
[[package]]
name = "google-auth"
-version = "2.31.0"
+version = "2.32.0"
description = "Google Authentication Library"
optional = false
python-versions = ">=3.7"
files = [
- {file = "google-auth-2.31.0.tar.gz", hash = "sha256:87805c36970047247c8afe614d4e3af8eceafc1ebba0c679fe75ddd1d575e871"},
- {file = "google_auth-2.31.0-py2.py3-none-any.whl", hash = "sha256:042c4702efa9f7d3c48d3a69341c209381b125faa6dbf3ebe56bc7e40ae05c23"},
+ {file = "google_auth-2.32.0-py2.py3-none-any.whl", hash = "sha256:53326ea2ebec768070a94bee4e1b9194c9646ea0c2bd72422785bd0f9abfad7b"},
+ {file = "google_auth-2.32.0.tar.gz", hash = "sha256:49315be72c55a6a37d62819e3573f6b416aca00721f7e3e31a008d928bf64022"},
]
[package.dependencies]
@@ -1877,13 +1877,13 @@ sympy = "*"
[[package]]
name = "openai"
-version = "1.35.8"
+version = "1.35.13"
description = "The official Python library for the openai API"
optional = false
python-versions = ">=3.7.1"
files = [
- {file = "openai-1.35.8-py3-none-any.whl", hash = "sha256:69d5b0f47f0c806d5da83fb0f84c147661395226d7f79acc78aa1d9b8c635887"},
- {file = "openai-1.35.8.tar.gz", hash = "sha256:3f6101888bb516647edade74c503f2b937b8bab73408e799d58f2aba68bbe51c"},
+ {file = "openai-1.35.13-py3-none-any.whl", hash = "sha256:36ec3e93e0d1f243f69be85c89b9221a471c3e450dfd9df16c9829e3cdf63e60"},
+ {file = "openai-1.35.13.tar.gz", hash = "sha256:c684f3945608baf7d2dcc0ef3ee6f3e27e4c66f21076df0b47be45d57e6ae6e4"},
]
[package.dependencies]
@@ -2732,13 +2732,13 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
[[package]]
name = "resend"
-version = "2.1.0"
+version = "2.2.0"
description = "Resend Python SDK"
optional = false
python-versions = ">=3.7"
files = [
- {file = "resend-2.1.0-py2.py3-none-any.whl", hash = "sha256:7f2a221983fab74a09f669c0c14a75daf547ffa4b4930141626d9cca55bca767"},
- {file = "resend-2.1.0.tar.gz", hash = "sha256:92dc8e035c2ce8cf8210c1c322e86b0a4f509e0c82a80932d3323cd2f3a43d2d"},
+ {file = "resend-2.2.0-py2.py3-none-any.whl", hash = "sha256:be420762885de25c816497f09207da1cd54d253c44d9f81f441367893a42d099"},
+ {file = "resend-2.2.0.tar.gz", hash = "sha256:f44976e4a37bb66445280bd8ef201eaac536b07bbe7c4da8f1717f4fcc63da7e"},
]
[package.dependencies]
@@ -2796,13 +2796,13 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"]
[[package]]
name = "sentry-sdk"
-version = "2.7.1"
+version = "2.9.0"
description = "Python client for Sentry (https://sentry.io)"
optional = false
python-versions = ">=3.6"
files = [
- {file = "sentry_sdk-2.7.1-py2.py3-none-any.whl", hash = "sha256:ef1b3d54eb715825657cd4bb3cb42bb4dc85087bac14c56b0fd8c21abd968c9a"},
- {file = "sentry_sdk-2.7.1.tar.gz", hash = "sha256:25006c7e68b75aaa5e6b9c6a420ece22e8d7daec4b7a906ffd3a8607b67c037b"},
+ {file = "sentry_sdk-2.9.0-py2.py3-none-any.whl", hash = "sha256:0bea5fa8b564cc0d09f2e6f55893e8f70286048b0ffb3a341d5b695d1af0e6ee"},
+ {file = "sentry_sdk-2.9.0.tar.gz", hash = "sha256:4c85bad74df9767976afb3eeddc33e0e153300e887d637775a753a35ef99bee6"},
]
[package.dependencies]
@@ -2847,13 +2847,13 @@ tornado = ["tornado (>=6)"]
[[package]]
name = "setuptools"
-version = "70.2.0"
+version = "70.3.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
- {file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"},
- {file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"},
+ {file = "setuptools-70.3.0-py3-none-any.whl", hash = "sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc"},
+ {file = "setuptools-70.3.0.tar.gz", hash = "sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5"},
]
[package.extras]
@@ -3014,27 +3014,30 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7
[[package]]
name = "sympy"
-version = "1.12.1"
+version = "1.13.0"
description = "Computer algebra system (CAS) in Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "sympy-1.12.1-py3-none-any.whl", hash = "sha256:9b2cbc7f1a640289430e13d2a56f02f867a1da0190f2f99d8968c2f74da0e515"},
- {file = "sympy-1.12.1.tar.gz", hash = "sha256:2877b03f998cd8c08f07cd0de5b767119cd3ef40d09f41c30d722f6686b0fb88"},
+ {file = "sympy-1.13.0-py3-none-any.whl", hash = "sha256:6b0b32a4673fb91bd3cac3b55406c8e01d53ae22780be467301cc452f6680c92"},
+ {file = "sympy-1.13.0.tar.gz", hash = "sha256:3b6af8f4d008b9a1a6a4268b335b984b23835f26d1d60b0526ebc71d48a25f57"},
]
[package.dependencies]
-mpmath = ">=1.1.0,<1.4.0"
+mpmath = ">=1.1.0,<1.4"
+
+[package.extras]
+dev = ["hypothesis (>=6.70.0)", "pytest (>=7.1.0)"]
[[package]]
name = "tenacity"
-version = "8.4.2"
+version = "8.5.0"
description = "Retry code until it succeeds"
optional = false
python-versions = ">=3.8"
files = [
- {file = "tenacity-8.4.2-py3-none-any.whl", hash = "sha256:9e6f7cf7da729125c7437222f8a522279751cdfbe6b67bfe64f75d3a348661b2"},
- {file = "tenacity-8.4.2.tar.gz", hash = "sha256:cd80a53a79336edba8489e767f729e4f391c896956b57140b5d7511a64bbd3ef"},
+ {file = "tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687"},
+ {file = "tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78"},
]
[package.extras]
diff --git a/apps/api/src/db/assignments.py b/apps/api/src/db/assignments.py
deleted file mode 100644
index 9d8788d5..00000000
--- a/apps/api/src/db/assignments.py
+++ /dev/null
@@ -1,133 +0,0 @@
-from typing import Optional
-from openai import BaseModel
-from sqlalchemy import JSON, Column, ForeignKey
-from sqlmodel import Field, SQLModel
-from enum import Enum
-
-
-class AssignmentTypeEnum(str, Enum):
- FILE_SUBMISSION = "FILE_SUBMISSION"
- QUIZ = "QUIZ"
- OTHER = "OTHER"
-
-
-class Assignment(SQLModel, table=True):
- id: Optional[int] = Field(default=None, primary_key=True)
- assignment_uuid: str
- title: str
- description: str
- due_date: str
-
- org_id: int = Field(
- sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE"))
- )
- course_id: int = Field(
- sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
- )
- chapter_id: int = Field(
- sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
- )
- activity_id: int = Field(
- sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
- )
-
- creation_date: str
- update_date: str
-
-
-class AssignmentTask(SQLModel, table=True):
- id: Optional[int] = Field(default=None, primary_key=True)
- assignment_task_uuid: str = ""
- title: str = ""
- description: str = ""
- hint: str = ""
- assignment_type: AssignmentTypeEnum
- contents: dict = Field(default={}, sa_column=Column(JSON))
- max_grade_value: int = (
- 0 # Value is always between 0-100 and is used as the maximum grade for the task
- )
-
- # Foreign keys
- assignment_id: int = Field(
- sa_column=Column(
- "assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
- )
- )
- org_id: int = Field(
- sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE"))
- )
- course_id: int = Field(
- sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
- )
- chapter_id: int = Field(
- sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
- )
- activity_id: int = Field(
- sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
- )
- creation_date: str
- update_date: str
-
-
-class AssignmentTaskSubmission(SQLModel, table=True):
- id: Optional[int] = Field(default=None, primary_key=True)
- assignment_task_submission_uuid: str = ""
- task_submission: dict = Field(default={}, sa_column=Column(JSON))
- grade: int = (
- 0 # Value is always between 0-100 depending on the questions, this is used to calculate the final grade on the AssignmentUser model
- )
- task_submission_grade_feedback: str = "" # Feedback given by the teacher
-
- # Foreign keys
- user_id: int = Field(
- sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
- )
- activity_id: int = Field(
- sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
- )
- course_id: int = Field(
- sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
- )
- chapter_id: int = Field(
- sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
- )
- assignment_task_id: int = Field(
- sa_column=Column(
- "assignment_task_id", ForeignKey("assignment_task.id", ondelete="CASCADE")
- )
- )
- creation_date: str = ""
- update_date: str = ""
-
-
-# Note on grading :
-# To calculate the final grade :
-
-
-
-
-class AssignmentUserSubmissionStatus(str, Enum):
- PENDING = "PENDING"
- SUBMITTED = "SUBMITTED"
- GRADED = "GRADED"
- LATE = "LATE"
- NOT_SUBMITTED = "NOT_SUBMITTED"
-
-
-class AssignmentUserSubmission(SQLModel, table=True):
- id: Optional[int] = Field(default=None, primary_key=True)
- assignment_user_uuid: str = ""
- submission_status: AssignmentUserSubmissionStatus = (
- AssignmentUserSubmissionStatus.PENDING
- )
- grading: str = ""
- user_id: int = Field(
- sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
- )
- assignment_id: int = Field(
- sa_column=Column(
- "assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
- )
- )
- creation_date: str = ""
- update_date: str = ""
diff --git a/apps/api/src/db/activities.py b/apps/api/src/db/courses/activities.py
similarity index 100%
rename from apps/api/src/db/activities.py
rename to apps/api/src/db/courses/activities.py
diff --git a/apps/api/src/db/courses/assignments.py b/apps/api/src/db/courses/assignments.py
new file mode 100644
index 00000000..78632aa2
--- /dev/null
+++ b/apps/api/src/db/courses/assignments.py
@@ -0,0 +1,317 @@
+from typing import Optional, Dict
+from sqlalchemy import JSON, Column, ForeignKey
+from sqlmodel import Field, SQLModel
+from enum import Enum
+
+
+
+## Assignment ##
+class GradingTypeEnum(str, Enum):
+ ALPHABET = "ALPHABET"
+ NUMERIC = "NUMERIC"
+ PERCENTAGE = "PERCENTAGE"
+
+
+class AssignmentBase(SQLModel):
+ """Represents the common fields for an assignment."""
+
+ title: str
+ description: str
+ due_date: str
+ published: Optional[bool] = False
+ grading_type: GradingTypeEnum
+
+ org_id: int
+ course_id: int
+ chapter_id: int
+ activity_id: int
+
+
+class AssignmentCreate(AssignmentBase):
+ """Model for creating a new assignment."""
+
+ pass # Inherits all fields from AssignmentBase
+
+
+class AssignmentRead(AssignmentBase):
+ """Model for reading an assignment."""
+
+ id: int
+ assignment_uuid: str
+ creation_date: Optional[str]
+ update_date: Optional[str]
+
+
+class AssignmentUpdate(SQLModel):
+ """Model for updating an assignment."""
+
+ title: Optional[str]
+ description: Optional[str]
+ due_date: Optional[str]
+ published: Optional[bool]
+ grading_type: Optional[GradingTypeEnum]
+ org_id: Optional[int]
+ course_id: Optional[int]
+ chapter_id: Optional[int]
+ activity_id: Optional[int]
+ update_date: Optional[str]
+
+
+class Assignment(AssignmentBase, table=True):
+ """Represents an assignment with relevant details and foreign keys."""
+
+ id: Optional[int] = Field(default=None, primary_key=True)
+ creation_date: Optional[str]
+ update_date: Optional[str]
+ assignment_uuid: str
+
+ org_id: int = Field(
+ sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE"))
+ )
+ course_id: int = Field(
+ sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
+ )
+ chapter_id: int = Field(
+ sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
+ )
+ activity_id: int = Field(
+ sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
+ )
+
+
+## Assignment ##
+
+## AssignmentTask ##
+
+
+class AssignmentTaskTypeEnum(str, Enum):
+ FILE_SUBMISSION = "FILE_SUBMISSION"
+ QUIZ = "QUIZ"
+ FORM = "FORM" # soon to be implemented
+ OTHER = "OTHER"
+
+
+class AssignmentTaskBase(SQLModel):
+ """Represents the common fields for an assignment task."""
+
+ title: str
+ description: str
+ hint: str
+ assignment_type: AssignmentTaskTypeEnum
+ contents: Dict = Field(default={}, sa_column=Column(JSON))
+ max_grade_value: int = 0 # Value is always between 0-100
+
+ assignment_id: int
+ org_id: int
+ course_id: int
+ chapter_id: int
+ activity_id: int
+
+
+class AssignmentTaskCreate(AssignmentTaskBase ):
+ """Model for creating a new assignment task."""
+
+ pass # Inherits all fields from AssignmentTaskBase
+
+
+class AssignmentTaskRead(AssignmentTaskBase):
+ """Model for reading an assignment task."""
+
+ id: int
+ assignment_task_uuid: str
+
+
+class AssignmentTaskUpdate(SQLModel):
+ """Model for updating an assignment task."""
+
+ title: Optional[str]
+ description: Optional[str]
+ hint: Optional[str]
+ assignment_type: Optional[AssignmentTaskTypeEnum]
+ contents: Optional[Dict] = Field(default={}, sa_column=Column(JSON))
+ max_grade_value: Optional[int]
+ assignment_id: Optional[int]
+ org_id: Optional[int]
+ course_id: Optional[int]
+ chapter_id: Optional[int]
+ activity_id: Optional[int]
+
+
+class AssignmentTask(AssignmentTaskBase, table=True):
+ """Represents a task within an assignment with various attributes and foreign keys."""
+
+ id: Optional[int] = Field(default=None, primary_key=True)
+
+ assignment_task_uuid: str
+ creation_date: str
+ update_date: str
+
+ assignment_id: int = Field(
+ sa_column=Column(
+ "assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
+ )
+ )
+ org_id: int = Field(
+ sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE"))
+ )
+ course_id: int = Field(
+ sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
+ )
+ chapter_id: int = Field(
+ sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
+ )
+ activity_id: int = Field(
+ sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
+ )
+
+
+## AssignmentTask ##
+
+
+## AssignmentTaskSubmission ##
+
+
+class AssignmentTaskSubmissionBase(SQLModel):
+ """Represents the common fields for an assignment task submission."""
+
+ task_submission: Dict = Field(default={}, sa_column=Column(JSON))
+ grade: int = 0 # Value is always between 0-100
+ task_submission_grade_feedback: str
+ assignment_type: AssignmentTaskTypeEnum
+
+ user_id: int
+ activity_id: int
+ course_id: int
+ chapter_id: int
+ assignment_task_id: int
+
+
+class AssignmentTaskSubmissionCreate(AssignmentTaskSubmissionBase):
+ """Model for creating a new assignment task submission."""
+
+ pass # Inherits all fields from AssignmentTaskSubmissionBase
+
+
+class AssignmentTaskSubmissionRead(AssignmentTaskSubmissionBase):
+ """Model for reading an assignment task submission."""
+
+ id: int
+ creation_date: str
+ update_date: str
+
+
+class AssignmentTaskSubmissionUpdate(SQLModel):
+ """Model for updating an assignment task submission."""
+
+ assignment_task_submission_uuid: Optional[str]
+ task_submission: Optional[Dict] = Field(default={}, sa_column=Column(JSON))
+ grade: Optional[int]
+ task_submission_grade_feedback: Optional[str]
+ assignment_type: Optional[AssignmentTaskTypeEnum]
+ user_id: Optional[int]
+ activity_id: Optional[int]
+ course_id: Optional[int]
+ chapter_id: Optional[int]
+ assignment_task_id: Optional[int]
+
+
+class AssignmentTaskSubmission(AssignmentTaskSubmissionBase, table=True):
+ """Represents a submission for a specific assignment task with grade and feedback."""
+
+ id: Optional[int] = Field(default=None, primary_key=True)
+ assignment_task_submission_uuid: str
+ task_submission: Dict = Field(default={}, sa_column=Column(JSON))
+ grade: int = 0 # Value is always between 0-100
+ task_submission_grade_feedback: str
+ assignment_type: AssignmentTaskTypeEnum
+
+ user_id: int = Field(
+ sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
+ )
+ activity_id: int = Field(
+ sa_column=Column("activity_id", ForeignKey("activity.id", ondelete="CASCADE"))
+ )
+ course_id: int = Field(
+ sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE"))
+ )
+ chapter_id: int = Field(
+ sa_column=Column("chapter_id", ForeignKey("chapter.id", ondelete="CASCADE"))
+ )
+ assignment_task_id: int = Field(
+ sa_column=Column(
+ "assignment_task_id", ForeignKey("assignmenttask.id", ondelete="CASCADE")
+ )
+ )
+
+ creation_date: str
+ update_date: str
+
+## AssignmentTaskSubmission ##
+
+## AssignmentUserSubmission ##
+
+class AssignmentUserSubmissionStatus(str, Enum):
+ PENDING = "PENDING"
+ SUBMITTED = "SUBMITTED"
+ GRADED = "GRADED"
+ LATE = "LATE"
+ NOT_SUBMITTED = "NOT_SUBMITTED"
+
+
+class AssignmentUserSubmissionBase(SQLModel):
+ """Represents the submission status of an assignment for a user."""
+
+
+ submission_status: AssignmentUserSubmissionStatus = (
+ AssignmentUserSubmissionStatus.PENDING
+ )
+ grade: str
+ user_id: int = Field(
+ sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
+ )
+ assignment_id: int = Field(
+ sa_column=Column(
+ "assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
+ )
+ )
+
+class AssignmentUserSubmissionCreate(AssignmentUserSubmissionBase):
+ """Model for creating a new assignment user submission."""
+
+ pass # Inherits all fields from AssignmentUserSubmissionBase
+
+class AssignmentUserSubmissionRead(AssignmentUserSubmissionBase):
+ """Model for reading an assignment user submission."""
+
+ id: int
+ creation_date: str
+ update_date: str
+
+class AssignmentUserSubmissionUpdate(SQLModel):
+ """Model for updating an assignment user submission."""
+
+ submission_status: Optional[AssignmentUserSubmissionStatus]
+ grade: Optional[str]
+ user_id: Optional[int]
+ assignment_id: Optional[int]
+
+class AssignmentUserSubmission(AssignmentUserSubmissionBase, table=True):
+ """Represents the submission status of an assignment for a user."""
+
+ id: Optional[int] = Field(default=None, primary_key=True)
+ creation_date: str
+ update_date: str
+
+ submission_status: AssignmentUserSubmissionStatus = (
+ AssignmentUserSubmissionStatus.PENDING
+ )
+ grade: str
+ user_id: int = Field(
+ sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
+ )
+ assignment_id: int = Field(
+ sa_column=Column(
+ "assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
+ )
+ )
+
diff --git a/apps/api/src/db/blocks.py b/apps/api/src/db/courses/blocks.py
similarity index 96%
rename from apps/api/src/db/blocks.py
rename to apps/api/src/db/courses/blocks.py
index 453429f7..c8723cf9 100644
--- a/apps/api/src/db/blocks.py
+++ b/apps/api/src/db/courses/blocks.py
@@ -35,7 +35,7 @@ class BlockCreate(BlockBase):
class BlockRead(BlockBase):
- id: int
+ id: int = Field(default=None, primary_key=True)
org_id: int = Field(default=None, foreign_key="organization.id")
course_id: int = Field(default=None, foreign_key="course.id")
chapter_id: int = Field(default=None, foreign_key="chapter.id")
diff --git a/apps/api/src/db/chapter_activities.py b/apps/api/src/db/courses/chapter_activities.py
similarity index 100%
rename from apps/api/src/db/chapter_activities.py
rename to apps/api/src/db/courses/chapter_activities.py
diff --git a/apps/api/src/db/chapters.py b/apps/api/src/db/courses/chapters.py
similarity index 90%
rename from apps/api/src/db/chapters.py
rename to apps/api/src/db/courses/chapters.py
index 4e94dc62..d5c30b3d 100644
--- a/apps/api/src/db/chapters.py
+++ b/apps/api/src/db/courses/chapters.py
@@ -2,7 +2,7 @@ from typing import Any, List, Optional
from pydantic import BaseModel
from sqlalchemy import Column, ForeignKey
from sqlmodel import Field, SQLModel
-from src.db.activities import ActivityRead
+from src.db.courses.activities import ActivityRead
class ChapterBase(SQLModel):
@@ -33,10 +33,10 @@ class ChapterCreate(ChapterBase):
class ChapterUpdate(ChapterBase):
name: Optional[str]
- description: Optional[str]
- thumbnail_image: Optional[str]
+ description: Optional[str] = ""
+ thumbnail_image: Optional[str] = ""
course_id: Optional[int]
- org_id: Optional[int]
+ org_id: Optional[int] # type: ignore
class ChapterRead(ChapterBase):
diff --git a/apps/api/src/db/course_chapters.py b/apps/api/src/db/courses/course_chapters.py
similarity index 100%
rename from apps/api/src/db/course_chapters.py
rename to apps/api/src/db/courses/course_chapters.py
diff --git a/apps/api/src/db/course_updates.py b/apps/api/src/db/courses/course_updates.py
similarity index 100%
rename from apps/api/src/db/course_updates.py
rename to apps/api/src/db/courses/course_updates.py
diff --git a/apps/api/src/db/courses.py b/apps/api/src/db/courses/courses.py
similarity index 95%
rename from apps/api/src/db/courses.py
rename to apps/api/src/db/courses/courses.py
index 31586d25..bbc97af6 100644
--- a/apps/api/src/db/courses.py
+++ b/apps/api/src/db/courses/courses.py
@@ -3,7 +3,7 @@ from sqlalchemy import Column, ForeignKey, Integer
from sqlmodel import Field, SQLModel
from src.db.users import UserRead
from src.db.trails import TrailRead
-from src.db.chapters import ChapterRead
+from src.db.courses.chapters import ChapterRead
class CourseBase(SQLModel):
@@ -21,7 +21,7 @@ class Course(CourseBase, table=True):
org_id: int = Field(
sa_column=Column(Integer, ForeignKey("organization.id", ondelete="CASCADE"))
)
- course_uuid: str = ""
+ course_uuid: str = ""
creation_date: str = ""
update_date: str = ""
diff --git a/apps/api/src/db/trails.py b/apps/api/src/db/trails.py
index da6238c0..afce3b7d 100644
--- a/apps/api/src/db/trails.py
+++ b/apps/api/src/db/trails.py
@@ -6,8 +6,12 @@ from src.db.trail_runs import TrailRunRead
class TrailBase(SQLModel):
- org_id: int = Field(default=None, foreign_key="organization.id")
- user_id: int = Field(default=None, foreign_key="user.id")
+ org_id: int = Field(
+ sa_column=Column(Integer, ForeignKey("organization.id", ondelete="CASCADE"))
+ )
+ user_id: int = Field(
+ sa_column=Column(Integer, ForeignKey("user.id", ondelete="CASCADE"))
+ )
class Trail(TrailBase, table=True):
@@ -20,6 +24,7 @@ class Trail(TrailBase, table=True):
class TrailCreate(TrailBase):
pass
+
# TODO: This is a hacky way to get around the list[TrailRun] issue, find a better way to do this
class TrailRead(BaseModel):
id: Optional[int] = Field(default=None, primary_key=True)
diff --git a/apps/api/src/router.py b/apps/api/src/router.py
index fd171096..cc4d908c 100644
--- a/apps/api/src/router.py
+++ b/apps/api/src/router.py
@@ -1,8 +1,9 @@
from fastapi import APIRouter, Depends
from src.routers import usergroups
-from src.routers import blocks, dev, trail, users, auth, orgs, roles
+from src.routers import dev, trail, users, auth, orgs, roles
from src.routers.ai import ai
-from src.routers.courses import chapters, collections, courses, activities
+from src.routers.courses import chapters, collections, courses, assignments
+from src.routers.courses.activities import activities, blocks
from src.routers.install import install
from src.services.dev.dev import isDevModeEnabledOrRaise
from src.services.install.install import isInstallModeEnabled
@@ -19,6 +20,7 @@ v1_router.include_router(orgs.router, prefix="/orgs", tags=["orgs"])
v1_router.include_router(roles.router, prefix="/roles", tags=["roles"])
v1_router.include_router(blocks.router, prefix="/blocks", tags=["blocks"])
v1_router.include_router(courses.router, prefix="/courses", tags=["courses"])
+v1_router.include_router(assignments.router, prefix="/assignments", tags=["assignments"])
v1_router.include_router(chapters.router, prefix="/chapters", tags=["chapters"])
v1_router.include_router(activities.router, prefix="/activities", tags=["activities"])
v1_router.include_router(collections.router, prefix="/collections", tags=["collections"])
diff --git a/apps/api/src/routers/courses/activities.py b/apps/api/src/routers/courses/activities/activities.py
similarity index 97%
rename from apps/api/src/routers/courses/activities.py
rename to apps/api/src/routers/courses/activities/activities.py
index 8afad228..d7c69035 100644
--- a/apps/api/src/routers/courses/activities.py
+++ b/apps/api/src/routers/courses/activities/activities.py
@@ -1,6 +1,6 @@
from typing import List
from fastapi import APIRouter, Depends, UploadFile, Form, Request
-from src.db.activities import ActivityCreate, ActivityRead, ActivityUpdate
+from src.db.courses.activities import ActivityCreate, ActivityRead, ActivityUpdate
from src.db.users import PublicUser
from src.core.events.database import get_db_session
from src.services.courses.activities.activities import (
diff --git a/apps/api/src/routers/blocks.py b/apps/api/src/routers/courses/activities/blocks.py
similarity index 98%
rename from apps/api/src/routers/blocks.py
rename to apps/api/src/routers/courses/activities/blocks.py
index 19f4b03b..fea2f20d 100644
--- a/apps/api/src/routers/blocks.py
+++ b/apps/api/src/routers/courses/activities/blocks.py
@@ -1,5 +1,5 @@
from fastapi import APIRouter, Depends, UploadFile, Form, Request
-from src.db.blocks import BlockRead
+from src.db.courses.blocks import BlockRead
from src.core.events.database import get_db_session
from src.security.auth import get_current_user
from src.services.blocks.block_types.imageBlock.imageBlock import (
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
new file mode 100644
index 00000000..6bcd334e
--- /dev/null
+++ b/apps/api/src/routers/courses/assignments.py
@@ -0,0 +1,310 @@
+from fastapi import APIRouter, Depends, Request
+from src.db.courses.assignments import (
+ AssignmentCreate,
+ AssignmentRead,
+ AssignmentTaskCreate,
+ AssignmentTaskSubmissionCreate,
+ AssignmentTaskUpdate,
+ AssignmentUpdate,
+ AssignmentUserSubmissionCreate,
+)
+from src.db.users import PublicUser
+from src.core.events.database import get_db_session
+from src.security.auth import get_current_user
+from src.services.courses.activities.assignments import (
+ create_assignment,
+ create_assignment_submission,
+ create_assignment_task,
+ create_assignment_task_submission,
+ delete_assignment,
+ delete_assignment_submission,
+ delete_assignment_task,
+ delete_assignment_task_submission,
+ read_assignment,
+ read_assignment_submissions,
+ read_assignment_task_submissions,
+ read_assignment_tasks,
+ read_user_assignment_submissions,
+ read_user_assignment_task_submissions,
+ update_assignment,
+ update_assignment_submission,
+ update_assignment_task,
+)
+
+router = APIRouter()
+
+## ASSIGNMENTS ##
+
+
+@router.post("/")
+async def api_create_assignments(
+ request: Request,
+ assignment_object: AssignmentCreate,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+) -> AssignmentRead:
+ """
+ Create new activity
+ """
+ return await create_assignment(request, assignment_object, current_user, db_session)
+
+
+@router.get("/{assignment_uuid}")
+async def api_read_assignment(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+) -> AssignmentRead:
+ """
+ Read an assignment
+ """
+ return await read_assignment(request, assignment_uuid, current_user, db_session)
+
+
+@router.put("/{assignment_uuid}")
+async def api_update_assignment(
+ request: Request,
+ assignment_uuid: str,
+ assignment_object: AssignmentUpdate,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+) -> AssignmentRead:
+ """
+ Update an assignment
+ """
+ return await update_assignment(
+ request, assignment_uuid, assignment_object, current_user, db_session
+ )
+
+
+@router.delete("/{assignment_uuid}")
+async def api_delete_assignment(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Delete an assignment
+ """
+ return await delete_assignment(request, assignment_uuid, current_user, db_session)
+
+
+## ASSIGNMENTS Tasks ##
+
+
+@router.post("/{assignment_uuid}/tasks")
+async def api_create_assignment_tasks(
+ request: Request,
+ assignment_uuid: str,
+ assignment_task_object: AssignmentTaskCreate,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Create new tasks for an assignment
+ """
+ return await create_assignment_task(
+ request, assignment_uuid, assignment_task_object, current_user, db_session
+ )
+
+
+@router.get("/{assignment_uuid}/tasks")
+async def api_read_assignment_tasks(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Read tasks for an assignment
+ """
+ return await read_assignment_tasks(
+ request, assignment_uuid, current_user, db_session
+ )
+
+
+@router.put("/{assignment_uuid}/tasks/{task_uuid}")
+async def api_update_assignment_tasks(
+ request: Request,
+ assignment_task_uuid: str,
+ assignment_task_object: AssignmentTaskUpdate,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Update tasks for an assignment
+ """
+ return await update_assignment_task(
+ request, assignment_task_uuid, assignment_task_object, current_user, db_session
+ )
+
+
+@router.delete("/{assignment_uuid}/tasks/{task_uuid}")
+async def api_delete_assignment_tasks(
+ request: Request,
+ assignment_task_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Delete tasks for an assignment
+ """
+ return await delete_assignment_task(
+ request, assignment_task_uuid, current_user, db_session
+ )
+
+
+## ASSIGNMENTS Tasks Submissions ##
+
+
+@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions")
+async def api_create_assignment_task_submissions(
+ request: Request,
+ assignment_task_submission_object: AssignmentTaskSubmissionCreate,
+ assignment_task_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Create new task submissions for an assignment
+ """
+ return await create_assignment_task_submission(
+ request,
+ assignment_task_uuid,
+ assignment_task_submission_object,
+ current_user,
+ db_session,
+ )
+
+
+@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/{user_id}")
+async def api_read_user_assignment_task_submissions(
+ request: Request,
+ assignment_task_uuid: str,
+ user_id: int,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Read task submissions for an assignment from a user
+ """
+ return await read_user_assignment_task_submissions(
+ request, assignment_task_uuid, user_id, current_user, db_session
+ )
+
+
+@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions")
+async def api_read_assignment_task_submissions(
+ request: Request,
+ assignment_task_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Read task submissions for an assignment from a user
+ """
+ return await read_assignment_task_submissions(
+ request, assignment_task_uuid, current_user, db_session
+ )
+
+
+@router.delete(
+ "/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/{assignment_task_submission_uuid}"
+)
+async def api_delete_assignment_task_submissions(
+ request: Request,
+ assignment_task_submission_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Delete task submissions for an assignment from a user
+ """
+ return await delete_assignment_task_submission(
+ request, assignment_task_submission_uuid, current_user, db_session
+ )
+
+
+## ASSIGNMENTS Submissions ##
+
+
+@router.post("/{assignment_uuid}/submissions")
+async def api_create_assignment_submissions(
+ request: Request,
+ assignment_uuid: str,
+ assignment_submission: AssignmentUserSubmissionCreate,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Create new submissions for an assignment
+ """
+ return await create_assignment_submission(
+ request, assignment_uuid, assignment_submission, current_user, db_session
+ )
+
+
+@router.get("/{assignment_uuid}/submissions")
+async def api_read_assignment_submissions(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Read submissions for an assignment
+ """
+ return await read_assignment_submissions(
+ request, assignment_uuid, current_user, db_session
+ )
+
+
+@router.get("/{assignment_uuid}/submissions/{user_id}")
+async def api_read_user_assignment_submissions(
+ request: Request,
+ assignment_uuid: str,
+ user_id: int,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Read submissions for an assignment from a user
+ """
+ return await read_user_assignment_submissions(
+ request, assignment_uuid, user_id, current_user, db_session
+ )
+
+
+@router.put("/{assignment_uuid}/submissions/{user_id}")
+async def api_update_user_assignment_submissions(
+ request: Request,
+ assignment_uuid: str,
+ user_id: str,
+ assignment_submission: AssignmentUserSubmissionCreate,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Update submissions for an assignment from a user
+ """
+ return await update_assignment_submission(
+ request, user_id, assignment_submission, current_user, db_session
+ )
+
+
+@router.delete("/{assignment_uuid}/submissions/{user_id}")
+async def api_delete_user_assignment_submissions(
+ request: Request,
+ assignment_id: str,
+ user_id: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Delete submissions for an assignment from a user
+ """
+ return await delete_assignment_submission(
+ request, assignment_id, user_id, current_user, db_session
+ )
diff --git a/apps/api/src/routers/courses/chapters.py b/apps/api/src/routers/courses/chapters.py
index f6cf42db..0d33e6ec 100644
--- a/apps/api/src/routers/courses/chapters.py
+++ b/apps/api/src/routers/courses/chapters.py
@@ -1,7 +1,7 @@
from typing import List
from fastapi import APIRouter, Depends, Request
from src.core.events.database import get_db_session
-from src.db.chapters import (
+from src.db.courses.chapters import (
ChapterCreate,
ChapterRead,
ChapterUpdate,
diff --git a/apps/api/src/routers/courses/courses.py b/apps/api/src/routers/courses/courses.py
index 38057069..e81bf9ae 100644
--- a/apps/api/src/routers/courses/courses.py
+++ b/apps/api/src/routers/courses/courses.py
@@ -2,13 +2,13 @@ from typing import List
from fastapi import APIRouter, Depends, UploadFile, Form, Request
from sqlmodel import Session
from src.core.events.database import get_db_session
-from src.db.course_updates import (
+from src.db.courses.course_updates import (
CourseUpdateCreate,
CourseUpdateRead,
CourseUpdateUpdate,
)
from src.db.users import PublicUser
-from src.db.courses import (
+from src.db.courses.courses import (
CourseCreate,
CourseRead,
CourseUpdate,
diff --git a/apps/api/src/security/rbac/rbac.py b/apps/api/src/security/rbac/rbac.py
index d7055a79..04b64ca1 100644
--- a/apps/api/src/security/rbac/rbac.py
+++ b/apps/api/src/security/rbac/rbac.py
@@ -3,7 +3,7 @@ from fastapi import HTTPException, status, Request
from sqlalchemy import null
from sqlmodel import Session, select
from src.db.collections import Collection
-from src.db.courses import Course
+from src.db.courses.courses import Course
from src.db.resource_authors import ResourceAuthor, ResourceAuthorshipEnum
from src.db.roles import Role
from src.db.user_organizations import UserOrganization
diff --git a/apps/api/src/services/ai/ai.py b/apps/api/src/services/ai/ai.py
index 8afc7f51..17516d76 100644
--- a/apps/api/src/services/ai/ai.py
+++ b/apps/api/src/services/ai/ai.py
@@ -3,10 +3,10 @@ from sqlmodel import Session, select
from src.db.organization_config import OrganizationConfig
from src.db.organizations import Organization
from src.services.ai.utils import check_limits_and_config, count_ai_ask
-from src.db.courses import Course, CourseRead
+from src.db.courses.courses import Course, CourseRead
from src.core.events.database import get_db_session
from src.db.users import PublicUser
-from src.db.activities import Activity, ActivityRead
+from src.db.courses.activities import Activity, ActivityRead
from src.security.auth import get_current_user
from src.services.ai.base import ask_ai, get_chat_session_history
diff --git a/apps/api/src/services/blocks/block_types/imageBlock/imageBlock.py b/apps/api/src/services/blocks/block_types/imageBlock/imageBlock.py
index 63fabcc7..3b4dc539 100644
--- a/apps/api/src/services/blocks/block_types/imageBlock/imageBlock.py
+++ b/apps/api/src/services/blocks/block_types/imageBlock/imageBlock.py
@@ -3,9 +3,9 @@ from uuid import uuid4
from src.db.organizations import Organization
from fastapi import HTTPException, status, UploadFile, Request
from sqlmodel import Session, select
-from src.db.activities import Activity
-from src.db.blocks import Block, BlockRead, BlockTypeEnum
-from src.db.courses import Course
+from src.db.courses.activities import Activity
+from src.db.courses.blocks import Block, BlockRead, BlockTypeEnum
+from src.db.courses.courses import Course
from src.services.blocks.utils.upload_files import upload_file_and_return_file_object
from src.services.users.users import PublicUser
diff --git a/apps/api/src/services/blocks/block_types/pdfBlock/pdfBlock.py b/apps/api/src/services/blocks/block_types/pdfBlock/pdfBlock.py
index 4d69cc89..46f4d004 100644
--- a/apps/api/src/services/blocks/block_types/pdfBlock/pdfBlock.py
+++ b/apps/api/src/services/blocks/block_types/pdfBlock/pdfBlock.py
@@ -3,9 +3,9 @@ from uuid import uuid4
from src.db.organizations import Organization
from fastapi import HTTPException, status, UploadFile, Request
from sqlmodel import Session, select
-from src.db.activities import Activity
-from src.db.blocks import Block, BlockRead, BlockTypeEnum
-from src.db.courses import Course
+from src.db.courses.activities import Activity
+from src.db.courses.blocks import Block, BlockRead, BlockTypeEnum
+from src.db.courses.courses import Course
from src.services.blocks.utils.upload_files import upload_file_and_return_file_object
from src.services.users.users import PublicUser
diff --git a/apps/api/src/services/blocks/block_types/videoBlock/videoBlock.py b/apps/api/src/services/blocks/block_types/videoBlock/videoBlock.py
index 2e05ec01..481b5162 100644
--- a/apps/api/src/services/blocks/block_types/videoBlock/videoBlock.py
+++ b/apps/api/src/services/blocks/block_types/videoBlock/videoBlock.py
@@ -3,9 +3,9 @@ from uuid import uuid4
from src.db.organizations import Organization
from fastapi import HTTPException, status, UploadFile, Request
from sqlmodel import Session, select
-from src.db.activities import Activity
-from src.db.blocks import Block, BlockRead, BlockTypeEnum
-from src.db.courses import Course
+from src.db.courses.activities import Activity
+from src.db.courses.blocks import Block, BlockRead, BlockTypeEnum
+from src.db.courses.courses import Course
from src.services.blocks.utils.upload_files import upload_file_and_return_file_object
from src.services.users.users import PublicUser
diff --git a/apps/api/src/services/courses/activities/activities.py b/apps/api/src/services/courses/activities/activities.py
index e976f8c3..f3a93d2c 100644
--- a/apps/api/src/services/courses/activities/activities.py
+++ b/apps/api/src/services/courses/activities/activities.py
@@ -1,14 +1,14 @@
from typing import Literal
from sqlmodel import Session, select
-from src.db.courses import Course
-from src.db.chapters import Chapter
+from src.db.courses.courses import Course
+from src.db.courses.chapters import Chapter
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship_and_usergroups,
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_anon,
)
-from src.db.activities import ActivityCreate, Activity, ActivityRead, ActivityUpdate
-from src.db.chapter_activities import ChapterActivity
+from src.db.courses.activities import ActivityCreate, Activity, ActivityRead, ActivityUpdate
+from src.db.courses.chapter_activities import ChapterActivity
from src.db.users import AnonymousUser, PublicUser
from fastapi import HTTPException, Request
from uuid import uuid4
@@ -58,7 +58,7 @@ async def create_activity(
statement = (
select(ChapterActivity)
.where(ChapterActivity.chapter_id == activity_object.chapter_id)
- .order_by(ChapterActivity.order)
+ .order_by(ChapterActivity.order) # type: ignore
)
chapter_activities = db_session.exec(statement).all()
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
new file mode 100644
index 00000000..9bbd5717
--- /dev/null
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -0,0 +1,997 @@
+####################################################
+# CRUD
+####################################################
+
+from datetime import datetime
+from typing import Literal
+from uuid import uuid4
+from fastapi import HTTPException, Request
+from sqlmodel import Session, select
+
+from src.db.courses.assignments import (
+ Assignment,
+ AssignmentCreate,
+ AssignmentRead,
+ AssignmentTask,
+ AssignmentTaskCreate,
+ AssignmentTaskRead,
+ AssignmentTaskSubmission,
+ AssignmentTaskSubmissionCreate,
+ AssignmentTaskSubmissionRead,
+ AssignmentTaskUpdate,
+ AssignmentUpdate,
+ AssignmentUserSubmission,
+ AssignmentUserSubmissionCreate,
+ AssignmentUserSubmissionRead,
+)
+from src.db.courses.courses import Course
+from src.db.users import AnonymousUser, PublicUser
+from src.security.rbac.rbac import (
+ authorization_verify_based_on_roles_and_authorship_and_usergroups,
+ authorization_verify_if_element_is_public,
+ authorization_verify_if_user_is_anon,
+)
+
+## > Assignments CRUD
+
+
+async def create_assignment(
+ request: Request,
+ assignment_object: AssignmentCreate,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if org exists
+ statement = select(Course).where(Course.id == assignment_object.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "create", db_session)
+
+ # Create Assignment
+ assignment = Assignment(**assignment_object.model_dump())
+
+ assignment.assignment_uuid = str(f"assignment_{uuid4()}")
+ assignment.creation_date = str(datetime.now())
+ assignment.update_date = str(datetime.now())
+ assignment.org_id = course.org_id
+
+ # Insert Assignment in DB
+ db_session.add(assignment)
+ db_session.commit()
+ db_session.refresh(assignment)
+
+ # return assignment read
+ return AssignmentRead.model_validate(assignment)
+
+
+async def read_assignment(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # return assignment read
+ return AssignmentRead.model_validate(assignment)
+
+
+async def update_assignment(
+ request: Request,
+ assignment_uuid: str,
+ assignment_object: AssignmentUpdate,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "update", db_session)
+
+ # Update only the fields that were passed in
+ for var, value in vars(assignment_object).items():
+ if value is not None:
+ setattr(assignment, var, value)
+ assignment.update_date = str(datetime.now())
+
+ # Insert Assignment in DB
+ db_session.add(assignment)
+ db_session.commit()
+ db_session.refresh(assignment)
+
+ # return assignment read
+ return AssignmentRead.model_validate(assignment)
+
+
+async def delete_assignment(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
+
+ # Delete Assignment
+ db_session.delete(assignment)
+ db_session.commit()
+
+ return {"message": "Assignment deleted"}
+
+
+## > Assignments Tasks CRUD
+
+
+async def create_assignment_task(
+ request: Request,
+ assignment_uuid: str,
+ assignment_task_object: AssignmentTaskCreate,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "create", db_session)
+
+ # Create Assignment Task
+ assignment_task = AssignmentTask(**assignment_task_object.model_dump())
+
+ assignment_task.assignment_task_uuid = str(f"assignmenttask_{uuid4()}")
+ assignment_task.creation_date = str(datetime.now())
+ assignment_task.update_date = str(datetime.now())
+ assignment_task.org_id = course.org_id
+
+ # Insert Assignment Task in DB
+ db_session.add(assignment_task)
+ db_session.commit()
+ db_session.refresh(assignment_task)
+
+ # return assignment task read
+ return AssignmentTaskRead.model_validate(assignment_task)
+
+
+async def read_assignment_tasks(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Find assignment
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # Find assignments tasks for an assignment
+ statement = select(AssignmentTask).where(
+ assignment.assignment_uuid == assignment_uuid
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # return assignment tasks read
+ return [
+ AssignmentTaskRead.model_validate(assignment_task)
+ for assignment_task in db_session.exec(statement).all()
+ ]
+
+
+async def update_assignment_task(
+ request: Request,
+ assignment_task_uuid: str,
+ assignment_task_object: AssignmentTaskUpdate,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment task exists
+ statement = select(AssignmentTask).where(
+ AssignmentTask.assignment_task_uuid == assignment_task_uuid
+ )
+ assignment_task = db_session.exec(statement).first()
+
+ if not assignment_task:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "update", db_session)
+
+ # Update only the fields that were passed in
+ for var, value in vars(assignment_task_object).items():
+ if value is not None:
+ setattr(assignment_task, var, value)
+ assignment_task.update_date = str(datetime.now())
+
+ # Insert Assignment Task in DB
+ db_session.add(assignment_task)
+ db_session.commit()
+ db_session.refresh(assignment_task)
+
+ # return assignment task read
+ return AssignmentTaskRead.model_validate(assignment_task)
+
+
+async def delete_assignment_task(
+ request: Request,
+ assignment_task_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment task exists
+ statement = select(AssignmentTask).where(
+ AssignmentTask.assignment_task_uuid == assignment_task_uuid
+ )
+ assignment_task = db_session.exec(statement).first()
+
+ if not assignment_task:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
+
+ # Delete Assignment Task
+ db_session.delete(assignment_task)
+ db_session.commit()
+
+ return {"message": "Assignment Task deleted"}
+
+
+## > Assignments Tasks Submissions CRUD
+
+
+async def create_assignment_task_submission(
+ request: Request,
+ assignment_task_uuid: str,
+ assignment_task_submission_object: AssignmentTaskSubmissionCreate,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment task exists
+ statement = select(AssignmentTask).where(
+ AssignmentTask.assignment_task_uuid == assignment_task_uuid
+ )
+ assignment_task = db_session.exec(statement).first()
+
+ if not assignment_task:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "create", db_session)
+
+ # Create Assignment Task Submission
+ assignment_task_submission = AssignmentTaskSubmission(
+ **assignment_task_submission_object.model_dump()
+ )
+
+ assignment_task_submission.assignment_task_submission_uuid = str(
+ f"assignmenttasksubmission_{uuid4()}"
+ )
+ assignment_task_submission.creation_date = str(datetime.now())
+ assignment_task_submission.update_date = str(datetime.now())
+ assignment_task_submission.org_id = course.org_id
+
+ # Insert Assignment Task Submission in DB
+ db_session.add(assignment_task_submission)
+ db_session.commit()
+ db_session.refresh(assignment_task_submission)
+
+ # return assignment task submission read
+ return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
+
+
+async def read_user_assignment_task_submissions(
+ request: Request,
+ assignment_task_submission_uuid: str,
+ user_id: int,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment task submission exists
+ statement = select(AssignmentTaskSubmission).where(
+ AssignmentTaskSubmission.assignment_task_submission_uuid
+ == assignment_task_submission_uuid,
+ AssignmentTaskSubmission.user_id == user_id,
+ )
+ assignment_task_submission = db_session.exec(statement).first()
+
+ if not assignment_task_submission:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task Submission not found",
+ )
+
+ # Check if assignment task exists
+ statement = select(AssignmentTask).where(
+ AssignmentTask.id == assignment_task_submission.assignment_task_id
+ )
+ assignment_task = db_session.exec(statement).first()
+
+ if not assignment_task:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # return assignment task submission read
+ return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
+
+
+async def read_assignment_task_submissions(
+ request: Request,
+ assignment_task_submission_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment task submission exists
+ statement = select(AssignmentTaskSubmission).where(
+ AssignmentTaskSubmission.assignment_task_submission_uuid
+ == assignment_task_submission_uuid,
+ )
+ assignment_task_submission = db_session.exec(statement).first()
+
+ if not assignment_task_submission:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task Submission not found",
+ )
+
+ # Check if assignment task exists
+ statement = select(AssignmentTask).where(
+ AssignmentTask.id == assignment_task_submission.assignment_task_id
+ )
+ assignment_task = db_session.exec(statement).first()
+
+ if not assignment_task:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # return assignment task submission read
+ return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
+
+
+async def update_assignment_task_submission(
+ request: Request,
+ assignment_task_submission_uuid: str,
+ assignment_task_submission_object: AssignmentTaskSubmissionCreate,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment task submission exists
+ statement = select(AssignmentTaskSubmission).where(
+ AssignmentTaskSubmission.assignment_task_submission_uuid
+ == assignment_task_submission_uuid
+ )
+ assignment_task_submission = db_session.exec(statement).first()
+
+ if not assignment_task_submission:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task Submission not found",
+ )
+
+ # Check if assignment task exists
+ statement = select(AssignmentTask).where(
+ AssignmentTask.id == assignment_task_submission.assignment_task_id
+ )
+ assignment_task = db_session.exec(statement).first()
+
+ if not assignment_task:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "update", db_session)
+
+ # Update only the fields that were passed in
+ for var, value in vars(assignment_task_submission_object).items():
+ if value is not None:
+ setattr(assignment_task_submission, var, value)
+ assignment_task_submission.update_date = str(datetime.now())
+
+ # Insert Assignment Task Submission in DB
+ db_session.add(assignment_task_submission)
+ db_session.commit()
+ db_session.refresh(assignment_task_submission)
+
+ # return assignment task submission read
+ return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
+
+
+async def delete_assignment_task_submission(
+ request: Request,
+ assignment_task_submission_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment task submission exists
+ statement = select(AssignmentTaskSubmission).where(
+ AssignmentTaskSubmission.assignment_task_submission_uuid
+ == assignment_task_submission_uuid
+ )
+ assignment_task_submission = db_session.exec(statement).first()
+
+ if not assignment_task_submission:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task Submission not found",
+ )
+
+ # Check if assignment task exists
+ statement = select(AssignmentTask).where(
+ AssignmentTask.id == assignment_task_submission.assignment_task_id
+ )
+ assignment_task = db_session.exec(statement).first()
+
+ if not assignment_task:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
+
+ # Delete Assignment Task Submission
+ db_session.delete(assignment_task_submission)
+ db_session.commit()
+
+ return {"message": "Assignment Task Submission deleted"}
+
+
+## > Assignments Submissions CRUD
+
+
+async def create_assignment_submission(
+ request: Request,
+ assignment_uuid: str,
+ assignment_user_submission_object: AssignmentUserSubmissionCreate,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if the submission has already been made
+ statement = select(AssignmentUserSubmission).where(
+ AssignmentUserSubmission.assignment_id == assignment.id,
+ AssignmentUserSubmission.user_id == assignment_user_submission_object.user_id,
+ )
+
+ assignment_user_submission = db_session.exec(statement).first()
+
+ if assignment_user_submission:
+ raise HTTPException(
+ status_code=400,
+ detail="Assignment User Submission already exists",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "create", db_session)
+
+ # Create Assignment User Submission
+ assignment_user_submission = AssignmentUserSubmission(
+ **assignment_user_submission_object.model_dump()
+ )
+
+ assignment_user_submission.assignment_user_submission_uuid = str(
+ f"assignmentusersubmission_{uuid4()}"
+ )
+ assignment_user_submission.creation_date = str(datetime.now())
+ assignment_user_submission.update_date = str(datetime.now())
+ assignment_user_submission.org_id = course.org_id
+
+ # Insert Assignment User Submission in DB
+ db_session.add(assignment_user_submission)
+ db_session.commit()
+
+ # return assignment user submission read
+ return AssignmentUserSubmissionRead.model_validate(assignment_user_submission)
+
+
+async def read_assignment_submissions(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Find assignment
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # Find assignments tasks for an assignment
+ statement = select(AssignmentUserSubmission).where(
+ assignment.assignment_uuid == assignment_uuid
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # return assignment tasks read
+ return [
+ AssignmentUserSubmissionRead.model_validate(assignment_user_submission)
+ for assignment_user_submission in db_session.exec(statement).all()
+ ]
+
+
+async def read_user_assignment_submissions(
+ request: Request,
+ assignment_uuid: str,
+ user_id: int,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Find assignment
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # Find assignments tasks for an assignment
+ statement = select(AssignmentUserSubmission).where(
+ assignment.assignment_uuid == assignment_uuid,
+ AssignmentUserSubmission.user_id == user_id,
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # return assignment tasks read
+ return [
+ AssignmentUserSubmissionRead.model_validate(assignment_user_submission)
+ for assignment_user_submission in db_session.exec(statement).all()
+ ]
+
+
+async def update_assignment_submission(
+ request: Request,
+ user_id: str,
+ assignment_user_submission_object: AssignmentUserSubmissionCreate,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment user submission exists
+ statement = select(AssignmentUserSubmission).where(
+ AssignmentUserSubmission.user_id == user_id
+ )
+ assignment_user_submission = db_session.exec(statement).first()
+
+ if not assignment_user_submission:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment User Submission not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(
+ Assignment.id == assignment_user_submission.assignment_id
+ )
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "update", db_session)
+
+ # Update only the fields that were passed in
+ for var, value in vars(assignment_user_submission_object).items():
+ if value is not None:
+ setattr(assignment_user_submission, var, value)
+ assignment_user_submission.update_date = str(datetime.now())
+
+ # Insert Assignment User Submission in DB
+ db_session.add(assignment_user_submission)
+ db_session.commit()
+ db_session.refresh(assignment_user_submission)
+
+ # return assignment user submission read
+ return AssignmentUserSubmissionRead.model_validate(assignment_user_submission)
+
+
+async def delete_assignment_submission(
+ request: Request,
+ user_id: str,
+ assignment_id: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if assignment user submission exists
+ statement = select(AssignmentUserSubmission).where(
+ AssignmentUserSubmission.user_id == user_id,
+ AssignmentUserSubmission.assignment_id == assignment_id,
+ )
+ assignment_user_submission = db_session.exec(statement).first()
+
+ if not assignment_user_submission:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment User Submission not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(
+ Assignment.id == assignment_user_submission.assignment_id
+ )
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
+
+ # Delete Assignment User Submission
+ db_session.delete(assignment_user_submission)
+ db_session.commit()
+
+ return {"message": "Assignment User Submission deleted"}
+
+
+## 🔒 RBAC Utils ##
+
+
+async def rbac_check(
+ request: Request,
+ course_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ action: Literal["create", "read", "update", "delete"],
+ db_session: Session,
+):
+
+ if action == "read":
+ if current_user.id == 0: # Anonymous user
+ res = await authorization_verify_if_element_is_public(
+ request, course_uuid, action, db_session
+ )
+ return res
+ else:
+ res = (
+ await authorization_verify_based_on_roles_and_authorship_and_usergroups(
+ request, current_user.id, action, course_uuid, db_session
+ )
+ )
+ return res
+ else:
+ await authorization_verify_if_user_is_anon(current_user.id)
+
+ await authorization_verify_based_on_roles_and_authorship_and_usergroups(
+ request,
+ current_user.id,
+ action,
+ course_uuid,
+ db_session,
+ )
+
+
+## 🔒 RBAC Utils ##
diff --git a/apps/api/src/services/courses/activities/pdf.py b/apps/api/src/services/courses/activities/pdf.py
index bb97da54..30b4db9d 100644
--- a/apps/api/src/services/courses/activities/pdf.py
+++ b/apps/api/src/services/courses/activities/pdf.py
@@ -1,20 +1,20 @@
from typing import Literal
-from src.db.courses import Course
+from src.db.courses.courses import Course
from src.db.organizations import Organization
from sqlmodel import Session, select
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship_and_usergroups,
authorization_verify_if_user_is_anon,
)
-from src.db.chapters import Chapter
-from src.db.activities import (
+from src.db.courses.chapters import Chapter
+from src.db.courses.activities import (
Activity,
ActivityRead,
ActivitySubTypeEnum,
ActivityTypeEnum,
)
-from src.db.chapter_activities import ChapterActivity
-from src.db.course_chapters import CourseChapter
+from src.db.courses.chapter_activities import ChapterActivity
+from src.db.courses.course_chapters import CourseChapter
from src.db.users import AnonymousUser, PublicUser
from src.services.courses.activities.uploads.pdfs import upload_pdf
from fastapi import HTTPException, status, UploadFile, Request
diff --git a/apps/api/src/services/courses/activities/utils.py b/apps/api/src/services/courses/activities/utils.py
index c2904d18..d3fee6d4 100644
--- a/apps/api/src/services/courses/activities/utils.py
+++ b/apps/api/src/services/courses/activities/utils.py
@@ -1,5 +1,5 @@
-from src.db.activities import ActivityRead
-from src.db.courses import CourseRead
+from src.db.courses.activities import ActivityRead
+from src.db.courses.courses import CourseRead
def structure_activity_content_by_type(activity):
diff --git a/apps/api/src/services/courses/activities/video.py b/apps/api/src/services/courses/activities/video.py
index 629a76c7..3396607c 100644
--- a/apps/api/src/services/courses/activities/video.py
+++ b/apps/api/src/services/courses/activities/video.py
@@ -1,5 +1,5 @@
from typing import Literal
-from src.db.courses import Course
+from src.db.courses.courses import Course
from src.db.organizations import Organization
from pydantic import BaseModel
@@ -8,15 +8,15 @@ from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship_and_usergroups,
authorization_verify_if_user_is_anon,
)
-from src.db.chapters import Chapter
-from src.db.activities import (
+from src.db.courses.chapters import Chapter
+from src.db.courses.activities import (
Activity,
ActivityRead,
ActivitySubTypeEnum,
ActivityTypeEnum,
)
-from src.db.chapter_activities import ChapterActivity
-from src.db.course_chapters import CourseChapter
+from src.db.courses.chapter_activities import ChapterActivity
+from src.db.courses.course_chapters import CourseChapter
from src.db.users import AnonymousUser, PublicUser
from src.services.courses.activities.uploads.videos import upload_video
from fastapi import HTTPException, status, UploadFile, Request
diff --git a/apps/api/src/services/courses/chapters.py b/apps/api/src/services/courses/chapters.py
index ee8ce1b5..b960e2c1 100644
--- a/apps/api/src/services/courses/chapters.py
+++ b/apps/api/src/services/courses/chapters.py
@@ -8,10 +8,10 @@ from src.security.rbac.rbac import (
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_anon,
)
-from src.db.course_chapters import CourseChapter
-from src.db.activities import Activity, ActivityRead
-from src.db.chapter_activities import ChapterActivity
-from src.db.chapters import (
+from src.db.courses.course_chapters import CourseChapter
+from src.db.courses.activities import Activity, ActivityRead
+from src.db.courses.chapter_activities import ChapterActivity
+from src.db.courses.chapters import (
Chapter,
ChapterCreate,
ChapterRead,
diff --git a/apps/api/src/services/courses/collections.py b/apps/api/src/services/courses/collections.py
index ac9627b6..9c5f8412 100644
--- a/apps/api/src/services/courses/collections.py
+++ b/apps/api/src/services/courses/collections.py
@@ -15,7 +15,7 @@ from src.db.collections import (
CollectionUpdate,
)
from src.db.collections_courses import CollectionCourse
-from src.db.courses import Course
+from src.db.courses.courses import Course
from src.services.users.users import PublicUser
from fastapi import HTTPException, status, Request
diff --git a/apps/api/src/services/courses/courses.py b/apps/api/src/services/courses/courses.py
index 6c09ea9c..b3d2ed33 100644
--- a/apps/api/src/services/courses/courses.py
+++ b/apps/api/src/services/courses/courses.py
@@ -8,7 +8,7 @@ from src.db.organizations import Organization
from src.services.trail.trail import get_user_trail_with_orgid
from src.db.resource_authors import ResourceAuthor, ResourceAuthorshipEnum
from src.db.users import PublicUser, AnonymousUser, User, UserRead
-from src.db.courses import (
+from src.db.courses.courses import (
Course,
CourseCreate,
CourseRead,
diff --git a/apps/api/src/services/courses/updates.py b/apps/api/src/services/courses/updates.py
index b4460664..f3fea858 100644
--- a/apps/api/src/services/courses/updates.py
+++ b/apps/api/src/services/courses/updates.py
@@ -3,13 +3,13 @@ from typing import List
from uuid import uuid4
from fastapi import HTTPException, Request, status
from sqlmodel import Session, col, select
-from src.db.course_updates import (
+from src.db.courses.course_updates import (
CourseUpdate,
CourseUpdateCreate,
CourseUpdateRead,
CourseUpdateUpdate,
)
-from src.db.courses import Course
+from src.db.courses.courses import Course
from src.db.organizations import Organization
from src.db.users import AnonymousUser, PublicUser
from src.services.courses.courses import rbac_check
diff --git a/apps/api/src/services/trail/trail.py b/apps/api/src/services/trail/trail.py
index 6dd5c15b..3101ceca 100644
--- a/apps/api/src/services/trail/trail.py
+++ b/apps/api/src/services/trail/trail.py
@@ -1,10 +1,10 @@
from datetime import datetime
from uuid import uuid4
-from src.db.chapter_activities import ChapterActivity
+from src.db.courses.chapter_activities import ChapterActivity
from fastapi import HTTPException, Request, status
from sqlmodel import Session, select
-from src.db.activities import Activity
-from src.db.courses import Course
+from src.db.courses.activities import Activity
+from src.db.courses.courses import Course
from src.db.trail_runs import TrailRun, TrailRunRead
from src.db.trail_steps import TrailStep
from src.db.trails import Trail, TrailCreate, TrailRead
From 9cf84b959d4df7c7d6f29146f44f6ff00469cf32 Mon Sep 17 00:00:00 2001
From: swve
Date: Thu, 11 Jul 2024 18:37:24 +0200
Subject: [PATCH 03/25] feat: add assignment activity to new activity modal
---
.../Buttons/NewActivityButton.tsx | 1 +
.../Modals/Activities/Create/NewActivity.tsx | 127 ++++++++----------
.../Create/NewActivityModal/Assignment.tsx | 9 ++
.../assignment-page-activity.png | Bin 0 -> 941 bytes
4 files changed, 63 insertions(+), 74 deletions(-)
create mode 100644 apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx
create mode 100644 apps/web/public/activities_types/assignment-page-activity.png
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/Buttons/NewActivityButton.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/Buttons/NewActivityButton.tsx
index afa30d9a..77d02ff0 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/Buttons/NewActivityButton.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/Buttons/NewActivityButton.tsx
@@ -87,6 +87,7 @@ function NewActivityButton(props: NewActivityButtonProps) {
isDialogOpen={newActivityModal}
onOpenChange={setNewActivityModal}
minHeight="no-min"
+ minWidth='md'
addDefCloseButton={false}
dialogContent={
+ <>
{selectedView === 'home' && (
-
+
{
setSelectedView('dynamic')
}}
>
-
-
-
- Dynamic Page
+
+
+
+
+ Dynamic Page
+
{
setSelectedView('video')
}}
>
-
-
-
- Video Page
+
+
+
+
+ Video
+
{
setSelectedView('documentpdf')
}}
>
-
-
-
- PDF Document Page
+
+
+
+
+ Document
+
-
+
{
+ setSelectedView('assignments')
+ }}
+ >
+
+
+
+
+ Assignments
+
+
+
)}
{selectedView === 'dynamic' && (
@@ -82,63 +99,25 @@ function NewActivityModal({
course={course}
/>
)}
-
+
+ {selectedView === 'assignments' && (
+ )
+ }
+ >
)
}
-const ActivityChooserWrapper = styled('div', {
- display: 'flex',
- flexDirection: 'row',
- justifyContent: 'start',
- marginTop: 10,
-})
-
-const ActivityOption = styled('div', {
- width: '180px',
- textAlign: 'center',
- borderRadius: 10,
- background: '#F6F6F6',
- border: '4px solid #F5F5F5',
- margin: 'auto',
-
- // hover
- '&:hover': {
- cursor: 'pointer',
- background: '#ededed',
- border: '4px solid #ededed',
-
- transition: 'background 0.2s ease-in-out, border 0.2s ease-in-out',
- },
-})
-
-const ActivityTypeImage = styled('div', {
- height: 80,
- borderRadius: 8,
- margin: 2,
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'center',
- justifyContent: 'end',
- textAlign: 'center',
- background: '#ffffff',
-
- // hover
- '&:hover': {
- cursor: 'pointer',
- },
-})
-
-const ActivityTypeTitle = styled('div', {
- display: 'flex',
- fontSize: 12,
- height: '20px',
- fontWeight: 500,
- color: 'rgba(0, 0, 0, 0.38);',
-
- // center text vertically
- alignItems: 'center',
- justifyContent: 'center',
- textAlign: 'center',
-})
+const ActivityOption = ({ onClick, children }: any) => (
+
+ {children}
+
+)
export default NewActivityModal
diff --git a/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx b/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx
new file mode 100644
index 00000000..a8eccc51
--- /dev/null
+++ b/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+function Assignment() {
+ return (
+ Assignment
+ )
+}
+
+export default Assignment
\ No newline at end of file
diff --git a/apps/web/public/activities_types/assignment-page-activity.png b/apps/web/public/activities_types/assignment-page-activity.png
new file mode 100644
index 0000000000000000000000000000000000000000..46de7b825d62f20856c91d66c1119fd1116c769d
GIT binary patch
literal 941
zcmeAS@N?(olHy`uVBq!ia0vp^=|F7H!3HG%&bgKhq&N#aB8wRqxP?KOkzv*x37{Zj
zage(c!@6@aFM%AEbVpxD28NCO+
zDsRem`#TEMc$?X)uTNiWGwHfT-~P75AJ#v#pDhp6G*Pj8_Wbit)s96ks*_%I2i~aQ
z{`R{zN5o3NR&{Z}q?FC+Q=NNGDY`usSX|T*XnACXOi~D+p;o&Ds_>Mv><`6Kkvs^84k(*<10m`2dzx0+B`aHho
z8J1r@x#s%ooZFMuyG|0gDWD(~;6GtkO@@iovb%ZR-uaK7IPheh+WV3#>B3%5Ar-x~
zx?6r
ztIYjJ{D#w&4xK7&OxUyScJ8m@Grml@QO>;|-kuU*t<>v0nf!F~J?@Kcd|dmjO`9Xr
zZWlhy+#2=rG`n?l@8=tOd@K1fC-B}n;mDoi`08UPOMHRe_NCio6{NRJOzyT{_GkT7
zmg=wZOy3<{z1b|(?TXd?Z!UO$&EUXvhm^#|w_$r5S{4;}5IET^woo{^qj%>RXDe=K4+RTetP}_euFG0tsSJ
z?7!^hv6y+h@K4a8?Y;@hH$P@gac>s-%qIWg6MJmS#>t)9>U)8?i^0>?&t;ucLK6Vv
C#iU{Y
literal 0
HcmV?d00001
From 04c05e4f9aae1395ef6b7d33cbe1581efe5c42cc Mon Sep 17 00:00:00 2001
From: swve
Date: Thu, 11 Jul 2024 19:57:12 +0200
Subject: [PATCH 04/25] feat: init alembic + add init revision
---
apps/api/alembic.ini | 116 ++++++++++++++++++
apps/api/migrations/env.py | 110 +++++++++++++++++
apps/api/migrations/script.py.mako | 27 ++++
.../df2981bf24dd_initial_migration.py | 51 ++++++++
apps/api/poetry.lock | 40 +++++-
apps/api/pyproject.toml | 1 +
apps/api/src/db/courses/activities.py | 11 +-
7 files changed, 348 insertions(+), 8 deletions(-)
create mode 100644 apps/api/alembic.ini
create mode 100644 apps/api/migrations/env.py
create mode 100644 apps/api/migrations/script.py.mako
create mode 100644 apps/api/migrations/versions/df2981bf24dd_initial_migration.py
diff --git a/apps/api/alembic.ini b/apps/api/alembic.ini
new file mode 100644
index 00000000..58e115a0
--- /dev/null
+++ b/apps/api/alembic.ini
@@ -0,0 +1,116 @@
+# A generic, single database configuration.
+
+[alembic]
+# path to migration scripts
+# Use forward slashes (/) also on windows to provide an os agnostic path
+script_location = migrations
+
+# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
+# Uncomment the line below if you want the files to be prepended with date and time
+# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
+# for all available tokens
+# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
+
+# sys.path path, will be prepended to sys.path if present.
+# defaults to the current working directory.
+prepend_sys_path = .
+
+# timezone to use when rendering the date within the migration file
+# as well as the filename.
+# If specified, requires the python>=3.9 or backports.zoneinfo library.
+# Any required deps can installed by adding `alembic[tz]` to the pip requirements
+# string value is passed to ZoneInfo()
+# leave blank for localtime
+# timezone =
+
+# max length of characters to apply to the "slug" field
+# truncate_slug_length = 40
+
+# set to 'true' to run the environment during
+# the 'revision' command, regardless of autogenerate
+# revision_environment = false
+
+# set to 'true' to allow .pyc and .pyo files without
+# a source .py file to be detected as revisions in the
+# versions/ directory
+# sourceless = false
+
+# version location specification; This defaults
+# to migrations/versions. When using multiple version
+# directories, initial revisions must be specified with --version-path.
+# The path separator used here should be the separator specified by "version_path_separator" below.
+# version_locations = %(here)s/bar:%(here)s/bat:migrations/versions
+
+# version path separator; As mentioned above, this is the character used to split
+# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
+# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
+# Valid values for version_path_separator are:
+#
+# version_path_separator = :
+# version_path_separator = ;
+# version_path_separator = space
+version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
+
+# set to 'true' to search source files recursively
+# in each "version_locations" directory
+# new in Alembic version 1.10
+# recursive_version_locations = false
+
+# the output encoding used when revision files
+# are written from script.py.mako
+# output_encoding = utf-8
+
+sqlalchemy.url = postgresql://learnhouse:learnhouse@localhost:5432/learnhouse
+
+
+[post_write_hooks]
+# post_write_hooks defines scripts or Python functions that are run
+# on newly generated revision scripts. See the documentation for further
+# detail and examples
+
+# format using "black" - use the console_scripts runner, against the "black" entrypoint
+# hooks = black
+# black.type = console_scripts
+# black.entrypoint = black
+# black.options = -l 79 REVISION_SCRIPT_FILENAME
+
+# lint with attempts to fix using "ruff" - use the exec runner, execute a binary
+# hooks = ruff
+# ruff.type = exec
+# ruff.executable = %(here)s/.venv/bin/ruff
+# ruff.options = --fix REVISION_SCRIPT_FILENAME
+
+# Logging configuration
+[loggers]
+keys = root,sqlalchemy,alembic
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = WARN
+handlers = console
+qualname =
+
+[logger_sqlalchemy]
+level = WARN
+handlers =
+qualname = sqlalchemy.engine
+
+[logger_alembic]
+level = INFO
+handlers =
+qualname = alembic
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
diff --git a/apps/api/migrations/env.py b/apps/api/migrations/env.py
new file mode 100644
index 00000000..41302d3d
--- /dev/null
+++ b/apps/api/migrations/env.py
@@ -0,0 +1,110 @@
+import importlib
+from logging.config import fileConfig
+import os
+
+from sqlalchemy import engine_from_config
+from sqlalchemy import pool
+from sqlmodel import SQLModel
+from alembic import context
+
+from config.config import get_learnhouse_config
+
+# LearnHouse config
+
+lh_config = get_learnhouse_config()
+
+# this is the Alembic Config object, which provides
+# access to the values within the .ini file in use.
+config = context.config
+
+# Interpret the config file for Python logging.
+# This line sets up loggers basically.
+if config.config_file_name is not None:
+ fileConfig(config.config_file_name)
+
+# add your model's MetaData object here
+# for 'autogenerate' support
+# from myapp import mymodel
+# target_metadata = mymodel.Base.metadata
+
+# IMPORTING ALL SCHEMAS
+base_dir = 'src/db'
+base_module_path = 'src.db'
+
+# Recursively walk through the base directory
+for root, dirs, files in os.walk(base_dir):
+ # Filter out __init__.py and non-Python files
+ module_files = [f for f in files if f.endswith('.py') and f != '__init__.py']
+ # Calculate the module's base path from its directory structure
+ path_diff = os.path.relpath(root, base_dir)
+ if path_diff == '.':
+ # Root of the base_dir, no additional path to add
+ current_module_base = base_module_path
+ else:
+ # Convert directory path to a module path
+ current_module_base = f"{base_module_path}.{path_diff.replace(os.sep, '.')}"
+
+ # Dynamically import each module
+ for file_name in module_files:
+ module_name = file_name[:-3] # Remove the '.py' extension
+ full_module_path = f"{current_module_base}.{module_name}"
+ importlib.import_module(full_module_path)
+
+# IMPORTING ALL SCHEMAS
+
+target_metadata = SQLModel.metadata
+
+# other values from the config, defined by the needs of env.py,
+# can be acquired:
+# my_important_option = config.get_main_option("my_important_option")
+# ... etc.
+
+
+def run_migrations_offline() -> None:
+ """Run migrations in 'offline' mode.
+
+ This configures the context with just a URL
+ and not an Engine, though an Engine is acceptable
+ here as well. By skipping the Engine creation
+ we don't even need a DBAPI to be available.
+
+ Calls to context.execute() here emit the given string to the
+ script output.
+
+ """
+ url = config.get_main_option("sqlalchemy.url")
+ context.configure(
+ url=url,
+ target_metadata=target_metadata,
+ literal_binds=True,
+ dialect_opts={"paramstyle": "named"},
+ )
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+
+def run_migrations_online() -> None:
+ """Run migrations in 'online' mode.
+
+ In this scenario we need to create an Engine
+ and associate a connection with the context.
+
+ """
+ connectable = engine_from_config(
+ config.get_section(config.config_ini_section, {}),
+ prefix="sqlalchemy.",
+ poolclass=pool.NullPool,
+ )
+
+ with connectable.connect() as connection:
+ context.configure(connection=connection, target_metadata=target_metadata)
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+
+if context.is_offline_mode():
+ run_migrations_offline()
+else:
+ run_migrations_online()
diff --git a/apps/api/migrations/script.py.mako b/apps/api/migrations/script.py.mako
new file mode 100644
index 00000000..6ce33510
--- /dev/null
+++ b/apps/api/migrations/script.py.mako
@@ -0,0 +1,27 @@
+"""${message}
+
+Revision ID: ${up_revision}
+Revises: ${down_revision | comma,n}
+Create Date: ${create_date}
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel
+${imports if imports else ""}
+
+# revision identifiers, used by Alembic.
+revision: str = ${repr(up_revision)}
+down_revision: Union[str, None] = ${repr(down_revision)}
+branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
+depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
+
+
+def upgrade() -> None:
+ ${upgrades if upgrades else "pass"}
+
+
+def downgrade() -> None:
+ ${downgrades if downgrades else "pass"}
diff --git a/apps/api/migrations/versions/df2981bf24dd_initial_migration.py b/apps/api/migrations/versions/df2981bf24dd_initial_migration.py
new file mode 100644
index 00000000..e27b5c33
--- /dev/null
+++ b/apps/api/migrations/versions/df2981bf24dd_initial_migration.py
@@ -0,0 +1,51 @@
+"""Initial Migration
+
+Revision ID: df2981bf24dd
+Revises:
+Create Date: 2024-07-11 19:33:37.993767
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+from grpc import server
+import sqlalchemy as sa
+import sqlmodel
+
+
+# revision identifiers, used by Alembic.
+revision: str = 'df2981bf24dd'
+down_revision: Union[str, None] = None
+branch_labels: Union[str, Sequence[str], None] = None
+depends_on: Union[str, Sequence[str], None] = None
+
+
+def upgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('activity', sa.Column('published', sa.Boolean(), nullable=False, server_default=sa.true()))
+ op.drop_column('activity', 'published_version')
+ op.drop_column('activity', 'version')
+
+ op.drop_column('assignmentusersubmission', 'assignment_user_uuid')
+
+ op.drop_constraint('trail_org_id_fkey', 'trail', type_='foreignkey')
+ op.create_foreign_key('trail_org_id_fkey', 'trail', 'organization', ['org_id'], ['id'], ondelete='CASCADE')
+ op.drop_constraint('trail_user_id_fkey', 'trail', type_='foreignkey')
+ op.create_foreign_key('trail_user_id_fkey', 'trail', 'user', ['user_id'], ['id'], ondelete='CASCADE')
+
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_constraint('trail_org_id_fkey', 'trail', type_='foreignkey')
+ op.create_foreign_key('trail_org_id_fkey', 'trail', 'organization', ['org_id'], ['id'])
+ op.drop_constraint('trail_user_id_fkey', 'trail', type_='foreignkey')
+ op.create_foreign_key('trail_user_id_fkey', 'trail', 'user', ['user_id'], ['id'])
+
+ op.add_column('assignmentusersubmission', sa.Column('assignment_user_uuid', sa.VARCHAR(), autoincrement=False, nullable=False))
+
+ op.add_column('activity', sa.Column('version', sa.INTEGER(), autoincrement=False, nullable=False , server_default=sa.text('1')))
+ op.add_column('activity', sa.Column('published_version', sa.INTEGER(), autoincrement=False, nullable=False , server_default=sa.text('1')) )
+ op.drop_column('activity', 'published')
+ # ### end Alembic commands ###
diff --git a/apps/api/poetry.lock b/apps/api/poetry.lock
index deb41715..5aae9088 100644
--- a/apps/api/poetry.lock
+++ b/apps/api/poetry.lock
@@ -109,6 +109,25 @@ files = [
[package.dependencies]
frozenlist = ">=1.1.0"
+[[package]]
+name = "alembic"
+version = "1.13.2"
+description = "A database migration tool for SQLAlchemy."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"},
+ {file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"},
+]
+
+[package.dependencies]
+Mako = "*"
+SQLAlchemy = ">=1.3.0"
+typing-extensions = ">=4"
+
+[package.extras]
+tz = ["backports.zoneinfo"]
+
[[package]]
name = "anyio"
version = "4.4.0"
@@ -1419,6 +1438,25 @@ files = [
pydantic = ">=1,<3"
requests = ">=2,<3"
+[[package]]
+name = "mako"
+version = "1.3.5"
+description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"},
+ {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"},
+]
+
+[package.dependencies]
+MarkupSafe = ">=0.9.2"
+
+[package.extras]
+babel = ["Babel"]
+lingua = ["lingua"]
+testing = ["pytest"]
+
[[package]]
name = "markdown-it-py"
version = "3.0.0"
@@ -3833,4 +3871,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools",
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
-content-hash = "2ede6d1fb6efc6ff9e32b19be61139c9bb9fca4a9c84ac290a8278ea7812aed8"
+content-hash = "76c4defc807fe83375766ac085982a2edf16e57b2d092a4494021f00a0424a4c"
diff --git a/apps/api/pyproject.toml b/apps/api/pyproject.toml
index 1ea47def..0632d60b 100644
--- a/apps/api/pyproject.toml
+++ b/apps/api/pyproject.toml
@@ -38,6 +38,7 @@ tiktoken = "^0.7.0"
uvicorn = "0.30.1"
typer = "^0.12.3"
chromadb = "^0.5.3"
+alembic = "^1.13.2"
[build-system]
build-backend = "poetry.core.masonry.api"
diff --git a/apps/api/src/db/courses/activities.py b/apps/api/src/db/courses/activities.py
index 3db42b2a..8e40e21a 100644
--- a/apps/api/src/db/courses/activities.py
+++ b/apps/api/src/db/courses/activities.py
@@ -8,7 +8,7 @@ class ActivityTypeEnum(str, Enum):
TYPE_VIDEO = "TYPE_VIDEO"
TYPE_DOCUMENT = "TYPE_DOCUMENT"
TYPE_DYNAMIC = "TYPE_DYNAMIC"
- TYPE_ASSESSMENT = "TYPE_ASSESSMENT"
+ TYPE_ASSIGNMENT = "TYPE_ASSIGNMENT"
TYPE_CUSTOM = "TYPE_CUSTOM"
@@ -21,8 +21,8 @@ class ActivitySubTypeEnum(str, Enum):
# Document
SUBTYPE_DOCUMENT_PDF = "SUBTYPE_DOCUMENT_PDF"
SUBTYPE_DOCUMENT_DOC = "SUBTYPE_DOCUMENT_DOC"
- # Assessment
- SUBTYPE_ASSESSMENT_QUIZ = "SUBTYPE_ASSESSMENT_QUIZ"
+ # Assignment
+ SUBTYPE_ASSIGNMENT_ANY = "SUBTYPE_ASSIGNMENT_ANY"
# Custom
SUBTYPE_CUSTOM = "SUBTYPE_CUSTOM"
@@ -32,8 +32,7 @@ class ActivityBase(SQLModel):
activity_type: ActivityTypeEnum = ActivityTypeEnum.TYPE_CUSTOM
activity_sub_type: ActivitySubTypeEnum = ActivitySubTypeEnum.SUBTYPE_CUSTOM
content: dict = Field(default={}, sa_column=Column(JSON))
- published_version: int
- version: int
+ published: bool = False
class Activity(ActivityBase, table=True):
@@ -57,8 +56,6 @@ class ActivityCreate(ActivityBase):
class ActivityUpdate(ActivityBase):
name: Optional[str]
- activity_type: Optional[ActivityTypeEnum]
- activity_sub_type: Optional[ActivitySubTypeEnum]
content: dict = Field(default={}, sa_column=Column(JSON))
published_version: Optional[int]
version: Optional[int]
From 10e9be1d3377064a34f6e5bdf2df98458327bb33 Mon Sep 17 00:00:00 2001
From: swve
Date: Fri, 12 Jul 2024 11:54:33 +0200
Subject: [PATCH 05/25] feat: create and delete assignment activities from UI
---
apps/api/migrations/env.py | 2 +-
.../versions/6295e05ff7d0_enum_updates.py | 41 +++++
.../df2981bf24dd_initial_migration.py | 9 +-
apps/api/poetry.lock | 45 ++++-
apps/api/pyproject.toml | 2 +
apps/api/src/db/collections_courses.py | 8 +-
apps/api/src/db/courses/assignments.py | 2 +-
apps/api/src/db/trails.py | 6 +
apps/api/src/routers/courses/assignments.py | 13 ++
.../courses/activities/assignments.py | 48 ++++++
.../DraggableElements/ActivityElement.tsx | 6 +
.../Modals/Activities/Create/NewActivity.tsx | 3 +-
.../Create/NewActivityModal/Assignment.tsx | 154 +++++++++++++++++-
apps/web/services/courses/assignments.ts | 33 ++++
14 files changed, 358 insertions(+), 14 deletions(-)
create mode 100644 apps/api/migrations/versions/6295e05ff7d0_enum_updates.py
create mode 100644 apps/web/services/courses/assignments.ts
diff --git a/apps/api/migrations/env.py b/apps/api/migrations/env.py
index 41302d3d..08a2dd30 100644
--- a/apps/api/migrations/env.py
+++ b/apps/api/migrations/env.py
@@ -1,7 +1,7 @@
import importlib
from logging.config import fileConfig
import os
-
+import alembic_postgresql_enum
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from sqlmodel import SQLModel
diff --git a/apps/api/migrations/versions/6295e05ff7d0_enum_updates.py b/apps/api/migrations/versions/6295e05ff7d0_enum_updates.py
new file mode 100644
index 00000000..4ff2406e
--- /dev/null
+++ b/apps/api/migrations/versions/6295e05ff7d0_enum_updates.py
@@ -0,0 +1,41 @@
+"""Enum updates
+
+Revision ID: 6295e05ff7d0
+Revises: df2981bf24dd
+Create Date: 2024-07-11 20:46:26.582170
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel
+from alembic_postgresql_enum import TableReference # type: ignore
+
+# revision identifiers, used by Alembic.
+revision: str = '6295e05ff7d0'
+down_revision: Union[str, None] = 'df2981bf24dd'
+branch_labels: Union[str, Sequence[str], None] = None
+depends_on: Union[str, Sequence[str], None] = None
+
+
+def upgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.sync_enum_values('public', 'activitytypeenum', ['TYPE_VIDEO', 'TYPE_DOCUMENT', 'TYPE_DYNAMIC', 'TYPE_ASSIGNMENT', 'TYPE_CUSTOM'],
+ [TableReference(table_schema='public', table_name='activity', column_name='activity_type')],
+ enum_values_to_rename=[])
+ op.sync_enum_values('public', 'activitysubtypeenum', ['SUBTYPE_DYNAMIC_PAGE', 'SUBTYPE_VIDEO_YOUTUBE', 'SUBTYPE_VIDEO_HOSTED', 'SUBTYPE_DOCUMENT_PDF', 'SUBTYPE_DOCUMENT_DOC', 'SUBTYPE_ASSIGNMENT_ANY', 'SUBTYPE_CUSTOM'],
+ [TableReference(table_schema='public', table_name='activity', column_name='activity_sub_type')],
+ enum_values_to_rename=[])
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.sync_enum_values('public', 'activitysubtypeenum', ['SUBTYPE_DYNAMIC_PAGE', 'SUBTYPE_VIDEO_YOUTUBE', 'SUBTYPE_VIDEO_HOSTED', 'SUBTYPE_DOCUMENT_PDF', 'SUBTYPE_DOCUMENT_DOC', 'SUBTYPE_ASSESSMENT_QUIZ', 'SUBTYPE_CUSTOM'],
+ [TableReference(table_schema='public', table_name='activity', column_name='activity_sub_type')],
+ enum_values_to_rename=[])
+ op.sync_enum_values('public', 'activitytypeenum', ['TYPE_VIDEO', 'TYPE_DOCUMENT', 'TYPE_DYNAMIC', 'TYPE_ASSESSMENT', 'TYPE_CUSTOM'],
+ [TableReference(table_schema='public', table_name='activity', column_name='activity_type')],
+ enum_values_to_rename=[])
+ # ### end Alembic commands ###
diff --git a/apps/api/migrations/versions/df2981bf24dd_initial_migration.py b/apps/api/migrations/versions/df2981bf24dd_initial_migration.py
index e27b5c33..a6a5be8a 100644
--- a/apps/api/migrations/versions/df2981bf24dd_initial_migration.py
+++ b/apps/api/migrations/versions/df2981bf24dd_initial_migration.py
@@ -23,6 +23,9 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('activity', sa.Column('published', sa.Boolean(), nullable=False, server_default=sa.true()))
+ # If you need to rename columns instead of dropping them, use the rename_column command
+ # For example, if we are changing the name 'published_version' to 'published', we would use:
+ # op.alter_column('activity', 'published_version', new_column_name='published', existing_type=sa.Boolean())
op.drop_column('activity', 'published_version')
op.drop_column('activity', 'version')
@@ -32,7 +35,6 @@ def upgrade() -> None:
op.create_foreign_key('trail_org_id_fkey', 'trail', 'organization', ['org_id'], ['id'], ondelete='CASCADE')
op.drop_constraint('trail_user_id_fkey', 'trail', type_='foreignkey')
op.create_foreign_key('trail_user_id_fkey', 'trail', 'user', ['user_id'], ['id'], ondelete='CASCADE')
-
# ### end Alembic commands ###
@@ -45,7 +47,8 @@ def downgrade() -> None:
op.add_column('assignmentusersubmission', sa.Column('assignment_user_uuid', sa.VARCHAR(), autoincrement=False, nullable=False))
- op.add_column('activity', sa.Column('version', sa.INTEGER(), autoincrement=False, nullable=False , server_default=sa.text('1')))
- op.add_column('activity', sa.Column('published_version', sa.INTEGER(), autoincrement=False, nullable=False , server_default=sa.text('1')) )
+ op.add_column('activity', sa.Column('version', sa.INTEGER(), autoincrement=False, nullable=False, server_default=sa.text('1')))
+ op.add_column('activity', sa.Column('published_version', sa.INTEGER(), autoincrement=False, nullable=False, server_default=sa.text('1')))
op.drop_column('activity', 'published')
# ### end Alembic commands ###
+
diff --git a/apps/api/poetry.lock b/apps/api/poetry.lock
index 5aae9088..2b49d1cf 100644
--- a/apps/api/poetry.lock
+++ b/apps/api/poetry.lock
@@ -128,6 +128,21 @@ typing-extensions = ">=4"
[package.extras]
tz = ["backports.zoneinfo"]
+[[package]]
+name = "alembic-postgresql-enum"
+version = "1.2.0"
+description = "Alembic autogenerate support for creation, alteration and deletion of enums"
+optional = false
+python-versions = "<4.0,>=3.7"
+files = [
+ {file = "alembic_postgresql_enum-1.2.0-py3-none-any.whl", hash = "sha256:bd156e882a10c680fc88ebad25cfe78ccf9f826dec89670f8aeb28e5359e502b"},
+ {file = "alembic_postgresql_enum-1.2.0.tar.gz", hash = "sha256:971bd3a4c35ea38869bb5e263ea79e5b4a9c4a02f174a3dd7ddcb29d41260cba"},
+]
+
+[package.dependencies]
+alembic = ">=1.7"
+SQLAlchemy = ">=1.4"
+
[[package]]
name = "anyio"
version = "4.4.0"
@@ -3018,6 +3033,34 @@ postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"]
pymysql = ["pymysql"]
sqlcipher = ["sqlcipher3_binary"]
+[[package]]
+name = "sqlalchemy-utils"
+version = "0.41.2"
+description = "Various utility functions for SQLAlchemy."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "SQLAlchemy-Utils-0.41.2.tar.gz", hash = "sha256:bc599c8c3b3319e53ce6c5c3c471120bd325d0071fb6f38a10e924e3d07b9990"},
+ {file = "SQLAlchemy_Utils-0.41.2-py3-none-any.whl", hash = "sha256:85cf3842da2bf060760f955f8467b87983fb2e30f1764fd0e24a48307dc8ec6e"},
+]
+
+[package.dependencies]
+SQLAlchemy = ">=1.3"
+
+[package.extras]
+arrow = ["arrow (>=0.3.4)"]
+babel = ["Babel (>=1.3)"]
+color = ["colour (>=0.0.4)"]
+encrypted = ["cryptography (>=0.6)"]
+intervals = ["intervals (>=0.7.1)"]
+password = ["passlib (>=1.6,<2.0)"]
+pendulum = ["pendulum (>=2.0.5)"]
+phone = ["phonenumbers (>=5.9.2)"]
+test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"]
+test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"]
+timezone = ["python-dateutil"]
+url = ["furl (>=0.4.1)"]
+
[[package]]
name = "sqlmodel"
version = "0.0.19"
@@ -3871,4 +3914,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools",
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
-content-hash = "76c4defc807fe83375766ac085982a2edf16e57b2d092a4494021f00a0424a4c"
+content-hash = "49d72c6871e3ecffae3b55ccad3a6b140f9a1ebbca84d7632dafd54e1d2b7f9d"
diff --git a/apps/api/pyproject.toml b/apps/api/pyproject.toml
index 0632d60b..a742eca1 100644
--- a/apps/api/pyproject.toml
+++ b/apps/api/pyproject.toml
@@ -39,6 +39,8 @@ uvicorn = "0.30.1"
typer = "^0.12.3"
chromadb = "^0.5.3"
alembic = "^1.13.2"
+alembic-postgresql-enum = "^1.2.0"
+sqlalchemy-utils = "^0.41.2"
[build-system]
build-backend = "poetry.core.masonry.api"
diff --git a/apps/api/src/db/collections_courses.py b/apps/api/src/db/collections_courses.py
index 4e0fc270..9ea829d8 100644
--- a/apps/api/src/db/collections_courses.py
+++ b/apps/api/src/db/collections_courses.py
@@ -5,8 +5,12 @@ from sqlmodel import Field, SQLModel
class CollectionCourse(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
- collection_id: int = Field(sa_column=Column(Integer, ForeignKey("collection.id", ondelete="CASCADE")))
- course_id: int = Field(sa_column=Column(Integer, ForeignKey("course.id", ondelete="CASCADE")))
+ collection_id: int = Field(
+ sa_column=Column(Integer, ForeignKey("collection.id", ondelete="CASCADE"))
+ )
+ course_id: int = Field(
+ sa_column=Column(Integer, ForeignKey("course.id", ondelete="CASCADE"))
+ )
org_id: int = Field(default=None, foreign_key="organization.id")
creation_date: str
update_date: str
diff --git a/apps/api/src/db/courses/assignments.py b/apps/api/src/db/courses/assignments.py
index 78632aa2..67b1f872 100644
--- a/apps/api/src/db/courses/assignments.py
+++ b/apps/api/src/db/courses/assignments.py
@@ -87,7 +87,7 @@ class Assignment(AssignmentBase, table=True):
class AssignmentTaskTypeEnum(str, Enum):
FILE_SUBMISSION = "FILE_SUBMISSION"
QUIZ = "QUIZ"
- FORM = "FORM" # soon to be implemented
+ FORM = "FORM" # soon to be implemented
OTHER = "OTHER"
diff --git a/apps/api/src/db/trails.py b/apps/api/src/db/trails.py
index afce3b7d..9b0430ba 100644
--- a/apps/api/src/db/trails.py
+++ b/apps/api/src/db/trails.py
@@ -16,6 +16,12 @@ class TrailBase(SQLModel):
class Trail(TrailBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
+ org_id: int = Field(
+ sa_column=Column(Integer, ForeignKey("organization.id", ondelete="CASCADE"))
+ )
+ user_id: int = Field(
+ sa_column=Column(Integer, ForeignKey("user.id", ondelete="CASCADE"))
+ )
trail_uuid: str = ""
creation_date: str = ""
update_date: str = ""
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index 6bcd334e..1dba87ce 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -17,6 +17,7 @@ from src.services.courses.activities.assignments import (
create_assignment_task,
create_assignment_task_submission,
delete_assignment,
+ delete_assignment_from_activity_uuid,
delete_assignment_submission,
delete_assignment_task,
delete_assignment_task_submission,
@@ -90,6 +91,18 @@ async def api_delete_assignment(
"""
return await delete_assignment(request, assignment_uuid, current_user, db_session)
+@router.delete("/activity/{activity_uuid}")
+async def api_delete_assignment_from_activity(
+ request: Request,
+ activity_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Delete an assignment
+ """
+ return await delete_assignment_from_activity_uuid(request, activity_uuid, current_user, db_session)
+
## ASSIGNMENTS Tasks ##
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index 9bbd5717..cb133190 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -8,6 +8,7 @@ from uuid import uuid4
from fastapi import HTTPException, Request
from sqlmodel import Session, select
+from src.db.courses.activities import Activity
from src.db.courses.assignments import (
Assignment,
AssignmentCreate,
@@ -184,6 +185,53 @@ async def delete_assignment(
return {"message": "Assignment deleted"}
+async def delete_assignment_from_activity_uuid(
+ request: Request,
+ activity_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if activity exists
+ statement = select(Activity).where(Activity.activity_uuid == activity_uuid)
+
+ activity = db_session.exec(statement).first()
+
+ if not activity:
+ raise HTTPException(
+ status_code=404,
+ detail="Activity not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == activity.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.activity_id == activity.id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
+
+ # Delete Assignment
+ db_session.delete(assignment)
+
+ db_session.commit()
+
+ return {"message": "Assignment deleted"}
+
## > Assignments Tasks CRUD
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
index a76c72e7..a631adcc 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
@@ -19,6 +19,7 @@ import { useRouter } from 'next/navigation'
import React from 'react'
import { Draggable } from 'react-beautiful-dnd'
import { mutate } from 'swr'
+import { deleteAssignment, deleteAssignmentUsingActivityUUID } from '@services/courses/assignments'
type ActivitiyElementProps = {
orgslug: string
@@ -45,6 +46,11 @@ function ActivityElement(props: ActivitiyElementProps) {
const activityUUID = props.activity.activity_uuid
async function deleteActivityUI() {
+ // Assignments
+ if(props.activity.activity_type === 'TYPE_ASSIGNMENT') {
+ await deleteAssignmentUsingActivityUUID(props.activity.activity_uuid, access_token)
+ }
+
await deleteActivity(props.activity.activity_uuid, access_token)
mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`)
await revalidateTags(['courses'], props.orgslug)
diff --git a/apps/web/components/Objects/Modals/Activities/Create/NewActivity.tsx b/apps/web/components/Objects/Modals/Activities/Create/NewActivity.tsx
index 797a2c8f..16201245 100644
--- a/apps/web/components/Objects/Modals/Activities/Create/NewActivity.tsx
+++ b/apps/web/components/Objects/Modals/Activities/Create/NewActivity.tsx
@@ -102,9 +102,10 @@ function NewActivityModal({
{selectedView === 'assignments' && (
)
}
>
diff --git a/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx b/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx
index a8eccc51..95abf80b 100644
--- a/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx
+++ b/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx
@@ -1,9 +1,153 @@
import React from 'react'
+import FormLayout, {
+ ButtonBlack,
+ Flex,
+ FormField,
+ FormLabel,
+ FormMessage,
+ Input,
-function Assignment() {
- return (
- Assignment
- )
+} from '@components/StyledElements/Form/Form'
+import * as Form from '@radix-ui/react-form'
+import { BarLoader } from 'react-spinners'
+import { useOrg } from '@components/Contexts/OrgContext'
+import { getAPIUrl } from '@services/config/config'
+import { mutate } from 'swr'
+import { createAssignment } from '@services/courses/assignments'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
+import { createActivity } from '@services/courses/activities'
+
+function NewAssignment({ submitActivity, chapterId, course, closeModal }: any) {
+ const org = useOrg() as any;
+ const session = useLHSession() as any
+ const [activityName, setActivityName] = React.useState('')
+ const [isSubmitting, setIsSubmitting] = React.useState(false)
+ const [activityDescription, setActivityDescription] = React.useState('')
+ const [dueDate, setDueDate] = React.useState('')
+ const [gradingType, setGradingType] = React.useState('ALPHABET')
+
+ const handleNameChange = (e: any) => {
+ setActivityName(e.target.value)
+ }
+
+ const handleDescriptionChange = (e: any) => {
+ setActivityDescription(e.target.value)
+ }
+
+ const handleDueDateChange = (e: any) => {
+ setDueDate(e.target.value)
+ }
+
+ const handleGradingTypeChange = (e: any) => {
+ setGradingType(e.target.value)
+ }
+
+ const handleSubmit = async (e: any) => {
+ e.preventDefault()
+ setIsSubmitting(true)
+ const activity = {
+ name: activityName,
+ chapter_id: chapterId,
+ activity_type: 'TYPE_ASSIGNMENT',
+ activity_sub_type: 'SUBTYPE_ASSIGNMENT_ANY',
+ published: false,
+ course_id: course?.courseStructure.id,
+ }
+
+ const activity_res = await createActivity(activity, chapterId, org?.id, session.data?.tokens?.access_token)
+ console.log(course)
+ console.log(activity_res)
+ await createAssignment({
+ title: activityName,
+ description: activityDescription,
+ due_date: dueDate,
+ grading_type: gradingType,
+ course_id: course?.courseStructure.id,
+ org_id: org?.id,
+ chapter_id: chapterId,
+ activity_id: activity_res?.id,
+ }, session.data?.tokens?.access_token)
+
+ mutate(`${getAPIUrl()}courses/${course.courseStructure.course_uuid}/meta`)
+ setIsSubmitting(false)
+ closeModal()
+ }
+
+
+ return (
+
+
+
+ Assignment Title
+
+ Please provide a name for your assignment
+
+
+
+
+
+
+
+ {/* Description */}
+
+
+ Assignment Description
+
+ Please provide a description for your assignment
+
+
+
+
+
+
+
+ {/* Due date */}
+
+
+ Due Date
+
+ Please provide a due date for your assignment
+
+
+
+
+
+
+
+ {/* Grading type */}
+
+
+ Grading Type
+
+ Please provide a grading type for your assignment
+
+
+
+
+
+
+
+
+
+
+ {isSubmitting ? (
+
+ ) : (
+ 'Create activity'
+ )}
+
+
+
+
+ )
}
-export default Assignment
\ No newline at end of file
+export default NewAssignment
\ No newline at end of file
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
new file mode 100644
index 00000000..33239fa3
--- /dev/null
+++ b/apps/web/services/courses/assignments.ts
@@ -0,0 +1,33 @@
+import { getAPIUrl } from '@services/config/config'
+import {
+ RequestBodyWithAuthHeader,
+ getResponseMetadata,
+} from '@services/utils/ts/requests'
+
+export async function createAssignment(body: any, access_token: string) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments`,
+ RequestBodyWithAuthHeader('POST', body, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
+
+// Delete an assignment
+export async function deleteAssignment(assignmentUUID: string, access_token: string) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}`,
+ RequestBodyWithAuthHeader('DELETE', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
+
+export async function deleteAssignmentUsingActivityUUID(activityUUID: string, access_token: string) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/activity/${activityUUID}`,
+ RequestBodyWithAuthHeader('DELETE', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+ }
From 6a4e16ec2956c60ebf73e3cbc97ff8d44e20a589 Mon Sep 17 00:00:00 2001
From: swve
Date: Fri, 12 Jul 2024 21:28:50 +0200
Subject: [PATCH 06/25] feat: init assignments UI and fix bugs
---
...95932_add_reference_for_assignmenttasks.py | 31 +++++
apps/api/src/db/courses/activities.py | 8 +-
apps/api/src/db/courses/assignments.py | 3 +-
apps/api/src/routers/courses/assignments.py | 13 ++
.../courses/activities/assignments.py | 42 ++++++
.../_components/TaskEditor.tsx | 32 +++++
.../[assignmentuuid]/_components/Tasks.tsx | 35 +++++
.../assignments/[assignmentuuid]/page.tsx | 59 +++++++++
.../orgs/[orgslug]/dash/assignments/page.tsx | 9 ++
.../course/[courseuuid]/[subpage]/page.tsx | 1 -
.../Assignments/AssignmentContext.tsx | 40 ++++++
.../DraggableElements/ActivityElement.tsx | 121 ++++++++++++++----
.../components/Dashboard/UI/BreadCrumbs.tsx | 19 ++-
apps/web/components/Dashboard/UI/LeftMenu.tsx | 10 +-
apps/web/services/courses/assignments.ts | 51 ++++++--
apps/web/styles/globals.css | 9 ++
16 files changed, 436 insertions(+), 47 deletions(-)
create mode 100644 apps/api/migrations/versions/d8bc71595932_add_reference_for_assignmenttasks.py
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
create mode 100644 apps/web/components/Contexts/Assignments/AssignmentContext.tsx
diff --git a/apps/api/migrations/versions/d8bc71595932_add_reference_for_assignmenttasks.py b/apps/api/migrations/versions/d8bc71595932_add_reference_for_assignmenttasks.py
new file mode 100644
index 00000000..10634418
--- /dev/null
+++ b/apps/api/migrations/versions/d8bc71595932_add_reference_for_assignmenttasks.py
@@ -0,0 +1,31 @@
+"""Add reference for AssignmentTasks
+
+Revision ID: d8bc71595932
+Revises: 6295e05ff7d0
+Create Date: 2024-07-12 18:59:50.242716
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel
+
+
+# revision identifiers, used by Alembic.
+revision: str = 'd8bc71595932'
+down_revision: Union[str, None] = '6295e05ff7d0'
+branch_labels: Union[str, Sequence[str], None] = None
+depends_on: Union[str, Sequence[str], None] = None
+
+
+def upgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('assignmenttask', sa.Column('reference_file', sa.VARCHAR(), nullable=True))
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_column('assignmenttask', 'reference_file')
+ # ### end Alembic commands ###
diff --git a/apps/api/src/db/courses/activities.py b/apps/api/src/db/courses/activities.py
index 8e40e21a..d6d8f0d8 100644
--- a/apps/api/src/db/courses/activities.py
+++ b/apps/api/src/db/courses/activities.py
@@ -29,8 +29,8 @@ class ActivitySubTypeEnum(str, Enum):
class ActivityBase(SQLModel):
name: str
- activity_type: ActivityTypeEnum = ActivityTypeEnum.TYPE_CUSTOM
- activity_sub_type: ActivitySubTypeEnum = ActivitySubTypeEnum.SUBTYPE_CUSTOM
+ activity_type: ActivityTypeEnum
+ activity_sub_type: ActivitySubTypeEnum
content: dict = Field(default={}, sa_column=Column(JSON))
published: bool = False
@@ -51,12 +51,16 @@ class Activity(ActivityBase, table=True):
class ActivityCreate(ActivityBase):
chapter_id: int
+ activity_type: ActivityTypeEnum = ActivityTypeEnum.TYPE_CUSTOM
+ activity_sub_type: ActivitySubTypeEnum = ActivitySubTypeEnum.SUBTYPE_CUSTOM
pass
class ActivityUpdate(ActivityBase):
name: Optional[str]
content: dict = Field(default={}, sa_column=Column(JSON))
+ activity_type: Optional[ActivityTypeEnum]
+ activity_sub_type: Optional[ActivitySubTypeEnum]
published_version: Optional[int]
version: Optional[int]
diff --git a/apps/api/src/db/courses/assignments.py b/apps/api/src/db/courses/assignments.py
index 67b1f872..fc288e36 100644
--- a/apps/api/src/db/courses/assignments.py
+++ b/apps/api/src/db/courses/assignments.py
@@ -97,6 +97,7 @@ class AssignmentTaskBase(SQLModel):
title: str
description: str
hint: str
+ reference_file: Optional[str]
assignment_type: AssignmentTaskTypeEnum
contents: Dict = Field(default={}, sa_column=Column(JSON))
max_grade_value: int = 0 # Value is always between 0-100
@@ -108,7 +109,7 @@ class AssignmentTaskBase(SQLModel):
activity_id: int
-class AssignmentTaskCreate(AssignmentTaskBase ):
+class AssignmentTaskCreate(AssignmentTaskBase):
"""Model for creating a new assignment task."""
pass # Inherits all fields from AssignmentTaskBase
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index 1dba87ce..f627d099 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -22,6 +22,7 @@ from src.services.courses.activities.assignments import (
delete_assignment_task,
delete_assignment_task_submission,
read_assignment,
+ read_assignment_from_activity_uuid,
read_assignment_submissions,
read_assignment_task_submissions,
read_assignment_tasks,
@@ -62,6 +63,18 @@ async def api_read_assignment(
"""
return await read_assignment(request, assignment_uuid, current_user, db_session)
+@router.get("/activity/{activity_uuid}")
+async def api_read_assignment_from_activity(
+ request: Request,
+ activity_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+) -> AssignmentRead:
+ """
+ Read an assignment
+ """
+ return await read_assignment_from_activity_uuid(request, activity_uuid, current_user, db_session)
+
@router.put("/{assignment_uuid}")
async def api_update_assignment(
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index cb133190..46102cf7 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -104,6 +104,48 @@ async def read_assignment(
# return assignment read
return AssignmentRead.model_validate(assignment)
+async def read_assignment_from_activity_uuid(
+ request: Request,
+ activity_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Check if activity exists
+ statement = select(Activity).where(Activity.activity_uuid == activity_uuid)
+ activity = db_session.exec(statement).first()
+
+ if not activity:
+ raise HTTPException(
+ status_code=404,
+ detail="Activity not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == activity.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.activity_id == activity.id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # return assignment read
+ return AssignmentRead.model_validate(assignment)
+
async def update_assignment(
request: Request,
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
new file mode 100644
index 00000000..c76be5e6
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
@@ -0,0 +1,32 @@
+'use client';
+import { Info, Link } from 'lucide-react'
+import React from 'react'
+
+function AssignmentTaskEditor({ task_uuid, page }: any) {
+ const [selectedSubPage, setSelectedSubPage] = React.useState(page)
+ return (
+
+
+
+
+ Assignment Test #1
+
+
+
+
+ )
+}
+
+export default AssignmentTaskEditor
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx
new file mode 100644
index 00000000..f2933817
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx
@@ -0,0 +1,35 @@
+import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext'
+import { Plus } from 'lucide-react';
+import React, { useEffect } from 'react'
+
+function AssignmentTasks() {
+ const assignments = useAssignments() as any;
+
+ useEffect(() => {
+ console.log(assignments)
+ }, [assignments])
+
+
+ return (
+
+
+ {assignments && assignments?.assignment_tasks?.map((task: any) => {
+ return (
+
+ )
+ })}
+
+
+
+
+ )
+}
+
+export default AssignmentTasks
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
new file mode 100644
index 00000000..cf7f609a
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
@@ -0,0 +1,59 @@
+'use client';
+import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'
+import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement'
+import { BookOpen, BookOpenCheck, BookX, Check, Ellipsis, EllipsisVertical, GalleryVerticalEnd, Info, LayoutList, UserRoundCog } from 'lucide-react'
+import React from 'react'
+import AssignmentTaskEditor from './_components/TaskEditor';
+import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext';
+import AssignmentTasks from './_components/Tasks';
+import { useParams } from 'next/navigation';
+
+function AssignmentEdit() {
+ const params = useParams<{ assignmentuuid: string; }>()
+ return (
+
+ )
+}
+
+export default AssignmentEdit
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
new file mode 100644
index 00000000..c54c9cc9
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+function AssignmentsHome() {
+ return (
+ AssignmentsHome
+ )
+}
+
+export default AssignmentsHome
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx
index 9de28441..9b44a988 100644
--- a/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx
@@ -82,7 +82,6 @@ function CourseOverviewPage({ params }: { params: CourseOverviewParams }) {
-
diff --git a/apps/web/components/Contexts/Assignments/AssignmentContext.tsx b/apps/web/components/Contexts/Assignments/AssignmentContext.tsx
new file mode 100644
index 00000000..f54844ee
--- /dev/null
+++ b/apps/web/components/Contexts/Assignments/AssignmentContext.tsx
@@ -0,0 +1,40 @@
+'use client'
+import { getAPIUrl } from '@services/config/config'
+import { swrFetcher } from '@services/utils/ts/requests'
+import React, { createContext, useContext, useEffect } from 'react'
+import useSWR from 'swr'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
+
+export const AssignmentContext = createContext({})
+
+export function AssignmentProvider({ children, assignment_uuid }: { children: React.ReactNode, assignment_uuid: string }) {
+ const session = useLHSession() as any
+ const accessToken = session?.data?.tokens?.access_token
+ const [assignmentsFull, setAssignmentsFull] = React.useState({ assignment_object: null, assignment_tasks: null })
+
+ const { data: assignment, error: assignmentError } = useSWR(
+ `${getAPIUrl()}assignments/${assignment_uuid}`,
+ (url) => swrFetcher(url, accessToken)
+ )
+
+ const { data: assignment_tasks, error: assignmentTasksError } = useSWR(
+ `${getAPIUrl()}assignments/${assignment_uuid}/tasks`,
+ (url) => swrFetcher(url, accessToken)
+ )
+
+ useEffect(() => {
+ setAssignmentsFull({ assignment_object: assignment, assignment_tasks: assignment_tasks })
+ }
+ , [assignment, assignment_tasks])
+
+ if (assignmentError || assignmentTasksError) return
+
+ if (!assignment || !assignment_tasks) return
+
+
+ return {children}
+}
+
+export function useAssignments() {
+ return useContext(AssignmentContext)
+}
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
index a631adcc..daeea79a 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
@@ -3,6 +3,7 @@ import { getAPIUrl, getUriWithOrg } from '@services/config/config'
import { deleteActivity, updateActivity } from '@services/courses/activities'
import { revalidateTags } from '@services/utils/ts/requests'
import {
+ Backpack,
Eye,
File,
FilePenLine,
@@ -16,10 +17,12 @@ import {
import { useLHSession } from '@components/Contexts/LHSessionContext'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
-import React from 'react'
+import React, { useEffect, useState } from 'react'
import { Draggable } from 'react-beautiful-dnd'
import { mutate } from 'swr'
-import { deleteAssignment, deleteAssignmentUsingActivityUUID } from '@services/courses/assignments'
+import { deleteAssignment, deleteAssignmentUsingActivityUUID, getAssignmentFromActivityUUID } from '@services/courses/assignments'
+import { useOrg } from '@components/Contexts/OrgContext'
+import { useCourse } from '@components/Contexts/CourseContext'
type ActivitiyElementProps = {
orgslug: string
@@ -47,7 +50,7 @@ function ActivityElement(props: ActivitiyElementProps) {
async function deleteActivityUI() {
// Assignments
- if(props.activity.activity_type === 'TYPE_ASSIGNMENT') {
+ if (props.activity.activity_type === 'TYPE_ASSIGNMENT') {
await deleteAssignmentUsingActivityUUID(props.activity.activity_uuid, access_token)
}
@@ -66,8 +69,6 @@ function ActivityElement(props: ActivitiyElementProps) {
let modifiedActivityCopy = {
name: modifiedActivity.activityName,
description: '',
- type: props.activity.type,
- content: props.activity.content,
}
await updateActivity(modifiedActivityCopy, activityUUID, access_token)
@@ -135,29 +136,7 @@ function ActivityElement(props: ActivitiyElementProps) {
{/* Edit and View Button */}
- {props.activity.activity_type === 'TYPE_DYNAMIC' && (
- <>
-
-
- Edit Page
-
-
- >
- )}
+
{
>
)}
+ {props.activityType === 'TYPE_ASSIGNMENT' && (
+ <>
+
+
+ {' '}
+
+
+ Assignment
+
{' '}
+
+ >
+ )}
{props.activityType === 'TYPE_DYNAMIC' && (
<>
@@ -240,4 +231,78 @@ const ActivityTypeIndicator = (props: { activityType: string }) => {
)
}
+
+const ActivityElementOptions = ({ activity }: any) => {
+ const [assignmentUUID, setAssignmentUUID] = useState('');
+ const org = useOrg() as any;
+ const course = useCourse() as any;
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+
+ async function getAssignmentUUIDFromActivityUUID(activityUUID: string) {
+ const activity = await getAssignmentFromActivityUUID(activityUUID, access_token);
+ if (activity) {
+ return activity.data.assignment_uuid;
+ }
+ }
+
+ const fetchAssignmentUUID = async () => {
+ if (activity.activity_type === 'TYPE_ASSIGNMENT') {
+ const assignment_uuid = await getAssignmentUUIDFromActivityUUID(activity.activity_uuid);
+ setAssignmentUUID(assignment_uuid.replace('assignment_', ''));
+ }
+ };
+
+ useEffect(() => {
+
+ console.log(activity)
+
+ fetchAssignmentUUID();
+ }, [activity, course]);
+
+ return (
+ <>
+ {activity.activity_type === 'TYPE_DYNAMIC' && (
+ <>
+
+
+ Edit Page
+
+
+ >
+ )}
+ {activity.activity_type === 'TYPE_ASSIGNMENT' && assignmentUUID && (
+ <>
+
+
+ Edit Assignment
+
+
+ >
+ )}
+ >
+ );
+};
+
export default ActivityElement
diff --git a/apps/web/components/Dashboard/UI/BreadCrumbs.tsx b/apps/web/components/Dashboard/UI/BreadCrumbs.tsx
index 05396e2b..f242f315 100644
--- a/apps/web/components/Dashboard/UI/BreadCrumbs.tsx
+++ b/apps/web/components/Dashboard/UI/BreadCrumbs.tsx
@@ -1,15 +1,16 @@
-import { useCourse } from '@components/Contexts/CourseContext'
-import { Book, ChevronRight, School, User, Users } from 'lucide-react'
+'use client';
+import { useOrg } from '@components/Contexts/OrgContext';
+import { Backpack, Book, ChevronRight, School, User, Users } from 'lucide-react'
import Link from 'next/link'
import React from 'react'
type BreadCrumbsProps = {
- type: 'courses' | 'user' | 'users' | 'org' | 'orgusers'
+ type: 'courses' | 'user' | 'users' | 'org' | 'orgusers' | 'assignments'
last_breadcrumb?: string
}
function BreadCrumbs(props: BreadCrumbsProps) {
- const course = useCourse() as any
+ const org = useOrg() as any
return (
@@ -25,6 +26,15 @@ function BreadCrumbs(props: BreadCrumbsProps) {
) : (
''
)}
+ {props.type == 'assignments' ? (
+
+ {' '}
+
+ Assignments
+
+ ) : (
+ ''
+ )}
{props.type == 'user' ? (
{' '}
@@ -64,7 +74,6 @@ function BreadCrumbs(props: BreadCrumbsProps) {
-
)
}
diff --git a/apps/web/components/Dashboard/UI/LeftMenu.tsx b/apps/web/components/Dashboard/UI/LeftMenu.tsx
index 9f695bbc..bc2eff28 100644
--- a/apps/web/components/Dashboard/UI/LeftMenu.tsx
+++ b/apps/web/components/Dashboard/UI/LeftMenu.tsx
@@ -3,7 +3,7 @@ import { useOrg } from '@components/Contexts/OrgContext'
import { signOut } from 'next-auth/react'
import ToolTip from '@components/StyledElements/Tooltip/Tooltip'
import LearnHouseDashboardLogo from '@public/dashLogo.png'
-import { BookCopy, Home, LogOut, School, Settings, Users } from 'lucide-react'
+import { Backpack, BookCopy, Home, LogOut, School, Settings, Users } from 'lucide-react'
import Image from 'next/image'
import Link from 'next/link'
import React, { useEffect } from 'react'
@@ -96,6 +96,14 @@ function LeftMenu() {
+
+
+
+
+
Date: Sat, 13 Jul 2024 20:03:08 +0200
Subject: [PATCH 07/25] feat: assignmentTask creation and switching
---
apps/api/src/db/courses/assignments.py | 6 +-
apps/api/src/routers/courses/assignments.py | 15 ++++
.../courses/activities/assignments.py | 46 +++++++++++
.../_components/Modals/NewTaskModal.tsx | 77 ++++++++++++++++++
.../_components/TaskEditor.tsx | 60 +++++++++-----
.../[assignmentuuid]/_components/Tasks.tsx | 58 +++++++++++---
.../assignments/[assignmentuuid]/page.tsx | 55 ++++++++-----
.../Assignments/AssignmentsTaskContext.tsx | 80 +++++++++++++++++++
apps/web/services/courses/assignments.ts | 12 +++
9 files changed, 354 insertions(+), 55 deletions(-)
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx
create mode 100644 apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
diff --git a/apps/api/src/db/courses/assignments.py b/apps/api/src/db/courses/assignments.py
index fc288e36..a7dbc221 100644
--- a/apps/api/src/db/courses/assignments.py
+++ b/apps/api/src/db/courses/assignments.py
@@ -102,11 +102,7 @@ class AssignmentTaskBase(SQLModel):
contents: Dict = Field(default={}, sa_column=Column(JSON))
max_grade_value: int = 0 # Value is always between 0-100
- assignment_id: int
- org_id: int
- course_id: int
- chapter_id: int
- activity_id: int
+
class AssignmentTaskCreate(AssignmentTaskBase):
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index f627d099..e238449c 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -24,6 +24,7 @@ from src.services.courses.activities.assignments import (
read_assignment,
read_assignment_from_activity_uuid,
read_assignment_submissions,
+ read_assignment_task,
read_assignment_task_submissions,
read_assignment_tasks,
read_user_assignment_submissions,
@@ -151,6 +152,20 @@ async def api_read_assignment_tasks(
)
+@router.get("/task/{assignment_task_uuid}")
+async def api_read_assignment_task(
+ request: Request,
+ assignment_task_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Read task for an assignment
+ """
+ return await read_assignment_task(
+ request, assignment_task_uuid, current_user, db_session
+ )
+
@router.put("/{assignment_uuid}/tasks/{task_uuid}")
async def api_update_assignment_tasks(
request: Request,
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index 46102cf7..6414a222 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -315,6 +315,10 @@ async def create_assignment_task(
assignment_task.creation_date = str(datetime.now())
assignment_task.update_date = str(datetime.now())
assignment_task.org_id = course.org_id
+ assignment_task.chapter_id = assignment.chapter_id
+ assignment_task.activity_id = assignment.activity_id
+ assignment_task.assignment_id = assignment.id # type: ignore
+ assignment_task.course_id = assignment.course_id
# Insert Assignment Task in DB
db_session.add(assignment_task)
@@ -365,6 +369,48 @@ async def read_assignment_tasks(
for assignment_task in db_session.exec(statement).all()
]
+async def read_assignment_task(
+ request: Request,
+ assignment_task_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Find assignment
+ statement = select(AssignmentTask).where(AssignmentTask.assignment_task_uuid == assignment_task_uuid)
+ assignmenttask = db_session.exec(statement).first()
+
+ if not assignmenttask:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.id == assignmenttask.assignment_id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # return assignment task read
+ return AssignmentTaskRead.model_validate(assignmenttask)
+
async def update_assignment_task(
request: Request,
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx
new file mode 100644
index 00000000..84a7e66f
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx
@@ -0,0 +1,77 @@
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import { getAPIUrl } from '@services/config/config';
+import { createAssignmentTask } from '@services/courses/assignments'
+import { AArrowUp, FileUp, ListTodo } from 'lucide-react'
+import React from 'react'
+import toast from 'react-hot-toast';
+import { mutate } from 'swr';
+
+function NewTaskModal({ closeModal, assignment_uuid }: any) {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const reminderShownRef = React.useRef(false);
+
+ function showReminderToast() {
+ // Check if the reminder has already been shown using sessionStorage
+ if (sessionStorage.getItem("TasksReminderShown") !== "true") {
+ setTimeout(() => {
+ toast('When editing/adding your tasks, make sure to Unpublish your Assignment to avoid any issues with students, you can Publish it again when you are ready.',
+ { icon: '✋', duration: 10000, style: { minWidth: 600 } });
+ // Mark the reminder as shown in sessionStorage
+ sessionStorage.setItem("TasksReminderShown", "true");
+ }, 3000);
+ }
+ }
+
+ async function createTask(type: string) {
+ const task_object = {
+ title: "Untitled Task",
+ description: "",
+ hint: "",
+ reference_file: "",
+ assignment_type: type,
+ contents: {},
+ max_grade_value: 100,
+ }
+ await createAssignmentTask(task_object, assignment_uuid, access_token)
+ toast.success('Task created successfully')
+ showReminderToast()
+ mutate(`${getAPIUrl()}assignments/${assignment_uuid}/tasks`)
+ closeModal(false)
+ }
+
+
+ return (
+
+
createTask('QUIZ')}
+ className='flex flex-col space-y-2 justify-center text-center pt-10'>
+
+
+
+
Quiz
+
Questions with multiple choice answers
+
+
createTask('FILE_SUBMISSION')}
+ className='flex flex-col space-y-2 justify-center text-center pt-10'>
+
+
+
+
File submissions
+
Students can submit files for this task
+
+
toast.error('Forms are not yet supported')}
+ className='flex flex-col space-y-2 justify-center text-center pt-10 opacity-25'>
+
+
Forms
+
Forms for students to fill out
+
+
+ )
+}
+
+export default NewTaskModal
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
index c76be5e6..c9e917b5 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
@@ -1,30 +1,52 @@
'use client';
-import { Info, Link } from 'lucide-react'
-import React from 'react'
+import { useAssignmentsTask } from '@components/Contexts/Assignments/AssignmentsTaskContext';
+import { Info, TentTree } from 'lucide-react'
+import React, { useEffect } from 'react'
-function AssignmentTaskEditor({ task_uuid, page }: any) {
+function AssignmentTaskEditor({ page }: any) {
const [selectedSubPage, setSelectedSubPage] = React.useState(page)
+ const assignmentTaskState = useAssignmentsTask() as any
+
+ useEffect(() => {
+ console.log(assignmentTaskState)
+ }
+ , [assignmentTaskState])
+
return (
-
-
-
- Assignment Test #1
-
-
-
-
-
-
Overview
+ {assignmentTaskState.assignmentTask && Object.keys(assignmentTaskState.assignmentTask).length > 0 && (
+
+
+ Assignment Test #1
+
+
-
+ )}
+ {Object.keys(assignmentTaskState.assignmentTask).length == 0 && (
+
+
+
+
+
+ No Task Selected
+
+
+
+
+ )}
+
)
}
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx
index f2933817..1236cd45 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx
@@ -1,12 +1,20 @@
import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext'
-import { Plus } from 'lucide-react';
+import Modal from '@components/StyledElements/Modal/Modal';
+import { FileUp, ListTodo, PanelLeftOpen, Plus } from 'lucide-react';
import React, { useEffect } from 'react'
+import NewTaskModal from './Modals/NewTaskModal';
+import { useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
-function AssignmentTasks() {
+function AssignmentTasks({ assignment_uuid }: any) {
const assignments = useAssignments() as any;
+ const assignmentTaskHook = useAssignmentsTaskDispatch() as any;
+ const [isNewTaskModalOpen, setIsNewTaskModalOpen] = React.useState(false)
+
+ async function setSelectTask(task_uuid: string) {
+ assignmentTaskHook({ type: 'setSelectedAssignmentTaskUUID', payload: task_uuid })
+ }
useEffect(() => {
- console.log(assignments)
}, [assignments])
@@ -15,19 +23,47 @@ function AssignmentTasks() {
{assignments && assignments?.assignment_tasks?.map((task: any) => {
return (
-
-
-
{task.title}
+
setSelectTask(task.assignment_task_uuid)}
+ >
+
+
+
+ {task.assignment_type === 'QUIZ' && }
+ {task.assignment_type === 'FILE_SUBMISSION' && }
+
+
{task.title}
+
+
)
})}
-
+
+
+ }
+ dialogTitle="Add an Assignment Task"
+ dialogDescription="Create a new task for this assignment"
+ dialogTrigger={
+
+ }
+ />
+
-
+
)
}
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
index cf7f609a..47f9793e 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
@@ -1,12 +1,13 @@
'use client';
import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'
-import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement'
-import { BookOpen, BookOpenCheck, BookX, Check, Ellipsis, EllipsisVertical, GalleryVerticalEnd, Info, LayoutList, UserRoundCog } from 'lucide-react'
+import { BookOpen, BookX, EllipsisVertical, LayoutList } from 'lucide-react'
import React from 'react'
import AssignmentTaskEditor from './_components/TaskEditor';
import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext';
import AssignmentTasks from './_components/Tasks';
import { useParams } from 'next/navigation';
+import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext';
+import ToolTip from '@components/StyledElements/Tooltip/Tooltip';
function AssignmentEdit() {
const params = useParams<{ assignmentuuid: string; }>()
@@ -24,33 +25,47 @@ function AssignmentEdit() {
-
-
)
diff --git a/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx b/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
new file mode 100644
index 00000000..64910a86
--- /dev/null
+++ b/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
@@ -0,0 +1,80 @@
+'use client'
+import React, { createContext, useContext, useEffect, useReducer } from 'react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
+import { getAssignmentTask } from '@services/courses/assignments'
+
+interface State {
+ selectedAssignmentTaskUUID: string | null;
+ assignmentTask: Record
;
+}
+
+interface Action {
+ type: string;
+ payload?: any;
+}
+
+const initialState: State = {
+ selectedAssignmentTaskUUID: null,
+ assignmentTask: {}
+};
+
+export const AssignmentsTaskContext = createContext(undefined);
+export const AssignmentsTaskDispatchContext = createContext | undefined>(undefined);
+
+export function AssignmentsTaskProvider({ children }: { children: React.ReactNode }) {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+
+ const [state, dispatch] = useReducer(assignmentstaskReducer, initialState);
+
+ async function fetchAssignmentTask(assignmentTaskUUID: string) {
+ const res = await getAssignmentTask(assignmentTaskUUID, access_token);
+ if (res.success) {
+ dispatch({ type: 'setAssignmentTask', payload: res });
+ }
+ }
+
+ useEffect(() => {
+ if (state.selectedAssignmentTaskUUID) {
+ fetchAssignmentTask(state.selectedAssignmentTaskUUID);
+ }
+ }, [state.selectedAssignmentTaskUUID]);
+
+ return (
+
+
+ {children}
+
+
+ );
+}
+
+export function useAssignmentsTask() {
+ const context = useContext(AssignmentsTaskContext);
+ if (context === undefined) {
+ throw new Error('useAssignmentsTask must be used within an AssignmentsTaskProvider');
+ }
+ return context;
+}
+
+export function useAssignmentsTaskDispatch() {
+ const context = useContext(AssignmentsTaskDispatchContext);
+ if (context === undefined) {
+ throw new Error('useAssignmentsTaskDispatch must be used within an AssignmentsTaskProvider');
+ }
+ return context;
+}
+
+function assignmentstaskReducer(state: State, action: Action): State {
+ switch (action.type) {
+ case 'setSelectedAssignmentTaskUUID':
+ return { ...state, selectedAssignmentTaskUUID: action.payload };
+ case 'setAssignmentTask':
+ return { ...state, assignmentTask: action.payload };
+ case 'reload':
+ return { ...state };
+ default:
+ return state;
+ }
+}
+
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
index f73f57ab..db88b95d 100644
--- a/apps/web/services/courses/assignments.ts
+++ b/apps/web/services/courses/assignments.ts
@@ -64,3 +64,15 @@ export async function createAssignmentTask(
const res = await getResponseMetadata(result)
return res
}
+
+export async function getAssignmentTask(
+ assignmentTaskUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/task/${assignmentTaskUUID}`,
+ RequestBodyWithAuthHeader('GET', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
From 3c41e0ee730b6db109c5525e907095f5e0fe88e1 Mon Sep 17 00:00:00 2001
From: swve
Date: Sun, 14 Jul 2024 14:06:25 +0200
Subject: [PATCH 08/25] feat: edit tasks and general improvements
---
apps/api/src/db/courses/assignments.py | 5 -
apps/api/src/routers/courses/assignments.py | 32 +-
.../courses/activities/assignments.py | 106 +++++-
.../activities/uploads/tasks_ref_files.py | 24 ++
apps/api/src/services/utils/upload_content.py | 17 +-
.../_components/Modals/NewTaskModal.tsx | 4 +-
.../_components/TaskEditor.tsx | 313 +++++++++++++++++-
.../[assignmentuuid]/_components/Tasks.tsx | 54 +--
.../assignments/[assignmentuuid]/page.tsx | 38 +--
.../Assignments/AssignmentsTaskContext.tsx | 19 +-
.../components/StyledElements/Form/Form.tsx | 2 +-
apps/web/services/courses/assignments.ts | 36 ++
apps/web/services/media/media.ts | 13 +
13 files changed, 570 insertions(+), 93 deletions(-)
create mode 100644 apps/api/src/services/courses/activities/uploads/tasks_ref_files.py
diff --git a/apps/api/src/db/courses/assignments.py b/apps/api/src/db/courses/assignments.py
index a7dbc221..e5d38b9e 100644
--- a/apps/api/src/db/courses/assignments.py
+++ b/apps/api/src/db/courses/assignments.py
@@ -127,11 +127,6 @@ class AssignmentTaskUpdate(SQLModel):
assignment_type: Optional[AssignmentTaskTypeEnum]
contents: Optional[Dict] = Field(default={}, sa_column=Column(JSON))
max_grade_value: Optional[int]
- assignment_id: Optional[int]
- org_id: Optional[int]
- course_id: Optional[int]
- chapter_id: Optional[int]
- activity_id: Optional[int]
class AssignmentTask(AssignmentTaskBase, table=True):
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index e238449c..c9a9509f 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -1,4 +1,4 @@
-from fastapi import APIRouter, Depends, Request
+from fastapi import APIRouter, Depends, Request, UploadFile
from src.db.courses.assignments import (
AssignmentCreate,
AssignmentRead,
@@ -21,6 +21,7 @@ from src.services.courses.activities.assignments import (
delete_assignment_submission,
delete_assignment_task,
delete_assignment_task_submission,
+ put_assignment_task_reference_file,
read_assignment,
read_assignment_from_activity_uuid,
read_assignment_submissions,
@@ -64,6 +65,7 @@ async def api_read_assignment(
"""
return await read_assignment(request, assignment_uuid, current_user, db_session)
+
@router.get("/activity/{activity_uuid}")
async def api_read_assignment_from_activity(
request: Request,
@@ -74,7 +76,9 @@ async def api_read_assignment_from_activity(
"""
Read an assignment
"""
- return await read_assignment_from_activity_uuid(request, activity_uuid, current_user, db_session)
+ return await read_assignment_from_activity_uuid(
+ request, activity_uuid, current_user, db_session
+ )
@router.put("/{assignment_uuid}")
@@ -105,6 +109,7 @@ async def api_delete_assignment(
"""
return await delete_assignment(request, assignment_uuid, current_user, db_session)
+
@router.delete("/activity/{activity_uuid}")
async def api_delete_assignment_from_activity(
request: Request,
@@ -115,7 +120,9 @@ async def api_delete_assignment_from_activity(
"""
Delete an assignment
"""
- return await delete_assignment_from_activity_uuid(request, activity_uuid, current_user, db_session)
+ return await delete_assignment_from_activity_uuid(
+ request, activity_uuid, current_user, db_session
+ )
## ASSIGNMENTS Tasks ##
@@ -166,7 +173,8 @@ async def api_read_assignment_task(
request, assignment_task_uuid, current_user, db_session
)
-@router.put("/{assignment_uuid}/tasks/{task_uuid}")
+
+@router.put("/{assignment_uuid}/tasks/{assignment_task_uuid}")
async def api_update_assignment_tasks(
request: Request,
assignment_task_uuid: str,
@@ -182,6 +190,22 @@ async def api_update_assignment_tasks(
)
+@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/ref_file")
+async def api_put_assignment_task_ref_file(
+ request: Request,
+ assignment_task_uuid: str,
+ reference_file: UploadFile | None = None,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Update tasks for an assignment
+ """
+ return await put_assignment_task_reference_file(
+ request, db_session, assignment_task_uuid, current_user, reference_file
+ )
+
+
@router.delete("/{assignment_uuid}/tasks/{task_uuid}")
async def api_delete_assignment_tasks(
request: Request,
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index 6414a222..e5e3ef85 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -5,7 +5,7 @@
from datetime import datetime
from typing import Literal
from uuid import uuid4
-from fastapi import HTTPException, Request
+from fastapi import HTTPException, Request, UploadFile
from sqlmodel import Session, select
from src.db.courses.activities import Activity
@@ -26,12 +26,16 @@ from src.db.courses.assignments import (
AssignmentUserSubmissionRead,
)
from src.db.courses.courses import Course
+from src.db.organizations import Organization
from src.db.users import AnonymousUser, PublicUser
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship_and_usergroups,
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_anon,
)
+from src.services.courses.activities.uploads.tasks_ref_files import (
+ upload_reference_file,
+)
## > Assignments CRUD
@@ -104,6 +108,7 @@ async def read_assignment(
# return assignment read
return AssignmentRead.model_validate(assignment)
+
async def read_assignment_from_activity_uuid(
request: Request,
activity_uuid: str,
@@ -119,7 +124,7 @@ async def read_assignment_from_activity_uuid(
status_code=404,
detail="Activity not found",
)
-
+
# Check if course exists
statement = select(Course).where(Course.id == activity.course_id)
course = db_session.exec(statement).first()
@@ -129,7 +134,7 @@ async def read_assignment_from_activity_uuid(
status_code=404,
detail="Course not found",
)
-
+
# Check if assignment exists
statement = select(Assignment).where(Assignment.activity_id == activity.id)
assignment = db_session.exec(statement).first()
@@ -227,6 +232,7 @@ async def delete_assignment(
return {"message": "Assignment deleted"}
+
async def delete_assignment_from_activity_uuid(
request: Request,
activity_uuid: str,
@@ -243,7 +249,7 @@ async def delete_assignment_from_activity_uuid(
status_code=404,
detail="Activity not found",
)
-
+
# Check if course exists
statement = select(Course).where(Course.id == activity.course_id)
course = db_session.exec(statement).first()
@@ -253,7 +259,7 @@ async def delete_assignment_from_activity_uuid(
status_code=404,
detail="Course not found",
)
-
+
# Check if assignment exists
statement = select(Assignment).where(Assignment.activity_id == activity.id)
assignment = db_session.exec(statement).first()
@@ -263,7 +269,7 @@ async def delete_assignment_from_activity_uuid(
status_code=404,
detail="Assignment not found",
)
-
+
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
@@ -317,7 +323,7 @@ async def create_assignment_task(
assignment_task.org_id = course.org_id
assignment_task.chapter_id = assignment.chapter_id
assignment_task.activity_id = assignment.activity_id
- assignment_task.assignment_id = assignment.id # type: ignore
+ assignment_task.assignment_id = assignment.id # type: ignore
assignment_task.course_id = assignment.course_id
# Insert Assignment Task in DB
@@ -369,6 +375,7 @@ async def read_assignment_tasks(
for assignment_task in db_session.exec(statement).all()
]
+
async def read_assignment_task(
request: Request,
assignment_task_uuid: str,
@@ -376,7 +383,9 @@ async def read_assignment_task(
db_session: Session,
):
# Find assignment
- statement = select(AssignmentTask).where(AssignmentTask.assignment_task_uuid == assignment_task_uuid)
+ statement = select(AssignmentTask).where(
+ AssignmentTask.assignment_task_uuid == assignment_task_uuid
+ )
assignmenttask = db_session.exec(statement).first()
if not assignmenttask:
@@ -384,7 +393,7 @@ async def read_assignment_task(
status_code=404,
detail="Assignment Task not found",
)
-
+
# Check if assignment exists
statement = select(Assignment).where(Assignment.id == assignmenttask.assignment_id)
assignment = db_session.exec(statement).first()
@@ -394,7 +403,57 @@ async def read_assignment_task(
status_code=404,
detail="Assignment not found",
)
-
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # return assignment task read
+ return AssignmentTaskRead.model_validate(assignmenttask)
+
+
+async def put_assignment_task_reference_file(
+ request: Request,
+ db_session: Session,
+ assignment_task_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ reference_file: UploadFile | None = None,
+):
+ # Check if assignment task exists
+ statement = select(AssignmentTask).where(
+ AssignmentTask.assignment_task_uuid == assignment_task_uuid
+ )
+ assignment_task = db_session.exec(statement).first()
+
+ if not assignment_task:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check for activity
+ statement = select(Activity).where(Activity.id == assignment.activity_id)
+ activity = db_session.exec(statement).first()
+
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
@@ -405,11 +464,34 @@ async def read_assignment_task(
detail="Course not found",
)
+ # Get org uuid
+ org_statement = select(Organization).where(Organization.id == course.org_id)
+ org = db_session.exec(org_statement).first()
+
# RBAC check
- await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+ await rbac_check(request, course.course_uuid, current_user, "update", db_session)
+
+ # Upload reference file
+ if reference_file and reference_file.filename and activity and org:
+ name_in_disk = (
+ f"{assignment_task_uuid}{uuid4()}.{reference_file.filename.split('.')[-1]}"
+ )
+ await upload_reference_file(
+ reference_file, name_in_disk, activity.activity_uuid, org.org_uuid, course.course_uuid, assignment.assignment_uuid, assignment_task_uuid
+ )
+ course.thumbnail_image = name_in_disk
+ # Update reference file
+ assignment_task.reference_file = name_in_disk
+
+ assignment_task.update_date = str(datetime.now())
+
+ # Insert Assignment Task in DB
+ db_session.add(assignment_task)
+ db_session.commit()
+ db_session.refresh(assignment_task)
# return assignment task read
- return AssignmentTaskRead.model_validate(assignmenttask)
+ return AssignmentTaskRead.model_validate(assignment_task)
async def update_assignment_task(
diff --git a/apps/api/src/services/courses/activities/uploads/tasks_ref_files.py b/apps/api/src/services/courses/activities/uploads/tasks_ref_files.py
new file mode 100644
index 00000000..d9f7c128
--- /dev/null
+++ b/apps/api/src/services/courses/activities/uploads/tasks_ref_files.py
@@ -0,0 +1,24 @@
+from uuid import uuid4
+from src.services.utils.upload_content import upload_content
+
+
+async def upload_reference_file(
+ file,
+ name_in_disk,
+ activity_uuid,
+ org_uuid,
+ course_uuid,
+ assignment_uuid,
+ assignment_task_uuid,
+):
+ contents = file.file.read()
+ file_format = file.filename.split(".")[-1]
+
+ await upload_content(
+ f"courses/{course_uuid}/activities/{activity_uuid}/assignments/{assignment_uuid}/tasks/{assignment_task_uuid}",
+ "orgs",
+ org_uuid,
+ contents,
+ f"{name_in_disk}",
+ ["pdf", "docx", "mp4", "jpg", "jpeg", "png", "pptx"],
+ )
diff --git a/apps/api/src/services/utils/upload_content.py b/apps/api/src/services/utils/upload_content.py
index 04448346..d32a787b 100644
--- a/apps/api/src/services/utils/upload_content.py
+++ b/apps/api/src/services/utils/upload_content.py
@@ -1,24 +1,37 @@
-from typing import Literal
+from typing import Literal, Optional
import boto3
from botocore.exceptions import ClientError
import os
+from fastapi import HTTPException
+
from config.config import get_learnhouse_config
async def upload_content(
directory: str,
type_of_dir: Literal["orgs", "users"],
- uuid: str, # org_uuid or user_uuid
+ uuid: str, # org_uuid or user_uuid
file_binary: bytes,
file_and_format: str,
+ allowed_formats: Optional[list[str]] = None,
):
# Get Learnhouse Config
learnhouse_config = get_learnhouse_config()
+ file_format = file_and_format.split(".")[-1].strip().lower()
+
# Get content delivery method
content_delivery = learnhouse_config.hosting_config.content_delivery.type
+ # Check if format file is allowed
+ if allowed_formats:
+ if file_format not in allowed_formats:
+ raise HTTPException(
+ status_code=400,
+ detail=f"File format {file_format} not allowed",
+ )
+
if content_delivery == "filesystem":
# create folder for activity
if not os.path.exists(f"content/{type_of_dir}/{uuid}/{directory}"):
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx
index 84a7e66f..fea5b9f3 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx
@@ -58,7 +58,7 @@ function NewTaskModal({ closeModal, assignment_uuid }: any) {
- File submissions
+ File submission
Students can submit files for this task
-
Forms
+
Form
Forms for students to fill out
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
index c9e917b5..818bffd0 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
@@ -1,7 +1,17 @@
'use client';
-import { useAssignmentsTask } from '@components/Contexts/Assignments/AssignmentsTaskContext';
-import { Info, TentTree } from 'lucide-react'
-import React, { useEffect } from 'react'
+import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
+import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import FormLayout, { FormField, FormLabelAndMessage, Input, Textarea } from '@components/StyledElements/Form/Form';
+import * as Form from '@radix-ui/react-form';
+import { getActivity } from '@services/courses/activities';
+import { updateAssignmentTask, updateReferenceFile } from '@services/courses/assignments';
+import { getTaskRefFileDir } from '@services/media/media';
+import { useFormik } from 'formik';
+import { ArrowBigUpDash, Cloud, File, GalleryVerticalEnd, Info, Loader, TentTree, Upload, UploadCloud } from 'lucide-react'
+import Link from 'next/link';
+import React, { use, useEffect } from 'react'
+import toast from 'react-hot-toast';
function AssignmentTaskEditor({ page }: any) {
const [selectedSubPage, setSelectedSubPage] = React.useState(page)
@@ -15,23 +25,41 @@ function AssignmentTaskEditor({ page }: any) {
return (
{assignmentTaskState.assignmentTask && Object.keys(assignmentTaskState.assignmentTask).length > 0 && (
-
-
- Assignment Test #1
-
-
-
-
-
-
Overview
+
+
+
+ {assignmentTaskState?.assignmentTask.title}
+
+
+
setSelectedSubPage('general')}
+ className={`flex space-x-4 py-2 w-fit text-center border-black transition-all ease-linear ${selectedSubPage === 'general'
+ ? 'border-b-4'
+ : 'opacity-50'
+ } cursor-pointer`}
+ >
+
+
+
setSelectedSubPage('content')}
+ className={`flex space-x-4 py-2 w-fit text-center border-black transition-all ease-linear ${selectedSubPage === 'content'
+ ? 'border-b-4'
+ : 'opacity-50'
+ } cursor-pointer`}
+ >
+
+
+ {selectedSubPage === 'general' &&
}
+
)}
{Object.keys(assignmentTaskState.assignmentTask).length == 0 && (
@@ -51,4 +79,255 @@ function AssignmentTaskEditor({ page }: any) {
)
}
+function AssignmentTaskGeneralEdit() {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const assignmentTaskState = useAssignmentsTask() as any
+ const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any
+ const assignment = useAssignments() as any
+
+ const validate = (values: any) => {
+ const errors: any = {};
+ if (values.max_grade_value < 20 || values.max_grade_value > 100) {
+ errors.max_grade_value = 'Value should be between 20 and 100';
+ }
+ return errors;
+ };
+
+
+
+ const formik = useFormik({
+ initialValues: {
+ title: assignmentTaskState.assignmentTask.title,
+ description: assignmentTaskState.assignmentTask.description,
+ hint: assignmentTaskState.assignmentTask.hint,
+ max_grade_value: assignmentTaskState.assignmentTask.max_grade_value,
+ },
+ validate,
+ onSubmit: async values => {
+ const res = await updateAssignmentTask(values, assignmentTaskState.assignmentTask.assignment_task_uuid, assignment.assignment_object.assignment_uuid, access_token)
+ if (res) {
+ assignmentTaskStateHook({ type: 'reload' })
+ }
+ else {
+ toast.error('Error updating task, please retry later.')
+ }
+ },
+ enableReinitialize: true,
+ }) as any;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Allowed formats : pdf, docx, mp4, jpg, jpeg, pptx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Submit button */}
+
+
+
+
+
+
+ )
+}
+
+function UpdateTaskRef() {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const assignmentTaskState = useAssignmentsTask() as any
+ const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any
+ const assignment = useAssignments() as any
+ const [isLoading, setIsLoading] = React.useState(false)
+ const [error, setError] = React.useState('') as any
+ const [localRefFile, setLocalRefFile] = React.useState(null) as any
+ const [activity, setActivity] = React.useState('') as any
+
+ const handleFileChange = async (event: any) => {
+ const file = event.target.files[0]
+ setLocalRefFile(file)
+ setIsLoading(true)
+ const res = await updateReferenceFile(
+ file,
+ assignmentTaskState.assignmentTask.assignment_task_uuid,
+ assignment.assignment_object.assignment_uuid,
+
+ access_token
+ )
+ assignmentTaskStateHook({ type: 'reload' })
+ // wait for 1 second to show loading animation
+ await new Promise((r) => setTimeout(r, 1500))
+ if (res.success === false) {
+ setError(res.data.detail)
+ setIsLoading(false)
+ } else {
+ setIsLoading(false)
+ setError('')
+ }
+ }
+
+ const deleteReferenceFile = async () => {
+ setIsLoading(true)
+ const res = await updateReferenceFile(
+ '',
+ assignmentTaskState.assignmentTask.assignment_task_uuid,
+ assignment.assignment_object.assignment_uuid,
+ access_token
+ )
+ assignmentTaskStateHook({ type: 'reload' })
+ // wait for 1 second to show loading animation
+ await new Promise((r) => setTimeout(r, 1500))
+ if (res.success === false) {
+ setError(res.data.detail)
+ setIsLoading(false)
+ } else {
+ setIsLoading(false)
+ setError('')
+ }
+ }
+
+ async function getActivityUI() {
+ const res = await getActivity(assignment.assignment_object.activity_id, null, access_token)
+ console.log(res)
+ setActivity(res.data)
+ }
+
+
+
+ useEffect(() => {
+ getActivityUI()
+ console.log(assignment.assignment_object.assignment_uuid)
+ console.log(assignmentTaskState.assignmentTask.assignment_task_uuid)
+ }
+ , [assignmentTaskState])
+
+
+
+ return (
+
+
+
+
+ {assignmentTaskState.assignmentTask.reference_file && (
+
+
+
+
+
+
+ {assignmentTaskState.assignmentTask.reference_file.split('.').pop()}
+
+
+ Download
+ {/** */}
+
+
+ )}
+
+ {isLoading ? (
+
+ ) : (
+
+
+
+
+ )}
+
+
+
+
+ )
+}
+
export default AssignmentTaskEditor
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx
index 1236cd45..63997abe 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Tasks.tsx
@@ -3,10 +3,11 @@ import Modal from '@components/StyledElements/Modal/Modal';
import { FileUp, ListTodo, PanelLeftOpen, Plus } from 'lucide-react';
import React, { useEffect } from 'react'
import NewTaskModal from './Modals/NewTaskModal';
-import { useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
+import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
function AssignmentTasks({ assignment_uuid }: any) {
const assignments = useAssignments() as any;
+ const assignmentTask = useAssignmentsTask() as any;
const assignmentTaskHook = useAssignmentsTaskDispatch() as any;
const [isNewTaskModalOpen, setIsNewTaskModalOpen] = React.useState(false)
@@ -21,30 +22,7 @@ function AssignmentTasks({ assignment_uuid }: any) {
return (
- {assignments && assignments?.assignment_tasks?.map((task: any) => {
- return (
-
setSelectTask(task.assignment_task_uuid)}
- >
-
-
-
- {task.assignment_type === 'QUIZ' && }
- {task.assignment_type === 'FILE_SUBMISSION' && }
-
-
{task.title}
-
-
-
-
- )
- })}
-
-
Add Task
}
- />
+ />)}
+ {assignments && assignments?.assignment_tasks?.map((task: any) => {
+ return (
+
setSelectTask(task.assignment_task_uuid)}
+ >
+
+
+
+ {task.assignment_type === 'QUIZ' && }
+ {task.assignment_type === 'FILE_SUBMISSION' && }
+
+
{task.title}
+
+
+
+
+ )
+ })}
+
+
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
index 47f9793e..76cb6eef 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
@@ -40,32 +40,32 @@ function AssignmentEdit() {
slateBlack
sideOffset={10}
content="Make your Assignment unavailable for students" >
-
+
)
diff --git a/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx b/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
index 64910a86..99d8adc2 100644
--- a/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
+++ b/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
@@ -2,10 +2,14 @@
import React, { createContext, useContext, useEffect, useReducer } from 'react'
import { useLHSession } from '@components/Contexts/LHSessionContext'
import { getAssignmentTask } from '@services/courses/assignments'
+import { useAssignments } from './AssignmentContext';
+import { mutate } from 'swr';
+import { getAPIUrl } from '@services/config/config';
interface State {
selectedAssignmentTaskUUID: string | null;
assignmentTask: Record;
+ reloadTrigger: number;
}
interface Action {
@@ -15,7 +19,8 @@ interface Action {
const initialState: State = {
selectedAssignmentTaskUUID: null,
- assignmentTask: {}
+ assignmentTask: {},
+ reloadTrigger: 0,
};
export const AssignmentsTaskContext = createContext(undefined);
@@ -24,21 +29,26 @@ export const AssignmentsTaskDispatchContext = createContext {
+
if (state.selectedAssignmentTaskUUID) {
fetchAssignmentTask(state.selectedAssignmentTaskUUID);
+ mutate(`${getAPIUrl()}assignments/${assignment.assignment_object?.assignment_uuid}/tasks`);
}
- }, [state.selectedAssignmentTaskUUID]);
+ }, [state.selectedAssignmentTaskUUID, state.reloadTrigger,assignment]);
return (
@@ -72,9 +82,8 @@ function assignmentstaskReducer(state: State, action: Action): State {
case 'setAssignmentTask':
return { ...state, assignmentTask: action.payload };
case 'reload':
- return { ...state };
+ return { ...state, reloadTrigger: state.reloadTrigger + 1 };
default:
return state;
}
}
-
diff --git a/apps/web/components/StyledElements/Form/Form.tsx b/apps/web/components/StyledElements/Form/Form.tsx
index 497ff3f9..182a33d2 100644
--- a/apps/web/components/StyledElements/Form/Form.tsx
+++ b/apps/web/components/StyledElements/Form/Form.tsx
@@ -58,7 +58,7 @@ export const inputStyles = {
borderRadius: 4,
fontSize: 15,
color: '#7c7c7c',
- background: '#F9FAFB',
+ background: '#fbfdff',
boxShadow: `0 0 0 1px #edeeef`,
'&:hover': { boxShadow: `0 0 0 1px #edeeef` },
'&:focus': { boxShadow: `0 0 0 2px #edeeef` },
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
index db88b95d..1e7fc28e 100644
--- a/apps/web/services/courses/assignments.ts
+++ b/apps/web/services/courses/assignments.ts
@@ -1,5 +1,6 @@
import { getAPIUrl } from '@services/config/config'
import {
+ RequestBodyFormWithAuthHeader,
RequestBodyWithAuthHeader,
getResponseMetadata,
} from '@services/utils/ts/requests'
@@ -76,3 +77,38 @@ export async function getAssignmentTask(
const res = await getResponseMetadata(result)
return res
}
+
+export async function updateAssignmentTask(
+ body: any,
+ assignmentTaskUUID: string,
+ assignmentUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}`,
+ RequestBodyWithAuthHeader('PUT', body, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
+
+export async function updateReferenceFile(
+ file: any,
+ assignmentTaskUUID: string,
+ assignmentUUID: string,
+ access_token: string
+) {
+
+ // Send file thumbnail as form data
+ const formData = new FormData()
+
+ if (file) {
+ formData.append('reference_file', file)
+ }
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/ref_file`,
+ RequestBodyFormWithAuthHeader('POST', formData, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
diff --git a/apps/web/services/media/media.ts b/apps/web/services/media/media.ts
index 9a7cb31a..2b0185ee 100644
--- a/apps/web/services/media/media.ts
+++ b/apps/web/services/media/media.ts
@@ -45,6 +45,19 @@ export function getActivityBlockMediaDirectory(
}
}
+export function getTaskRefFileDir(
+ orgUUID: string,
+ courseId: string,
+ activityId: string,
+ assignmentUUID: string,
+ assignmentTaskUUID: string,
+ fileID : string
+
+) {
+ let uri = `${getMediaUrl()}content/orgs/${orgUUID}/courses/${courseId}/activities/${activityId}/assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/${fileID}`
+ return uri
+}
+
export function getActivityMediaDirectory(
orgUUID: string,
courseId: string,
From aa55c51b4814c840c387233a1534483a2ee72422 Mon Sep 17 00:00:00 2001
From: swve
Date: Tue, 16 Jul 2024 22:07:54 +0200
Subject: [PATCH 09/25] feat: finalize basic task edition and ref files
---
apps/api/src/db/courses/activities.py | 2 +
.../routers/courses/activities/activities.py | 22 ++++-
apps/api/src/routers/courses/assignments.py | 2 +-
apps/api/src/routers/courses/courses.py | 34 +++++++-
.../services/courses/activities/activities.py | 32 +++++++
apps/api/src/services/courses/courses.py | 32 +++++++
.../_components/TaskEditor.tsx | 83 ++++++++++++++-----
.../Assignments/AssignmentContext.tsx | 27 ++++--
.../Assignments/AssignmentsTaskContext.tsx | 12 ++-
apps/web/services/courses/activities.ts | 15 +++-
apps/web/services/courses/assignments.ts | 13 +++
apps/web/services/courses/courses.ts | 9 ++
apps/web/services/media/media.ts | 14 ++--
13 files changed, 251 insertions(+), 46 deletions(-)
diff --git a/apps/api/src/db/courses/activities.py b/apps/api/src/db/courses/activities.py
index d6d8f0d8..50ec31c8 100644
--- a/apps/api/src/db/courses/activities.py
+++ b/apps/api/src/db/courses/activities.py
@@ -67,6 +67,8 @@ class ActivityUpdate(ActivityBase):
class ActivityRead(ActivityBase):
id: int
+ org_id: int
+ course_id: int
activity_uuid: str
creation_date: str
update_date: str
diff --git a/apps/api/src/routers/courses/activities/activities.py b/apps/api/src/routers/courses/activities/activities.py
index d7c69035..8ca5877a 100644
--- a/apps/api/src/routers/courses/activities/activities.py
+++ b/apps/api/src/routers/courses/activities/activities.py
@@ -7,6 +7,7 @@ from src.services.courses.activities.activities import (
create_activity,
get_activity,
get_activities,
+ get_activityby_id,
update_activity,
delete_activity,
)
@@ -34,8 +35,22 @@ async def api_create_activity(
return await create_activity(request, activity_object, current_user, db_session)
-@router.get("/{activity_id}")
+@router.get("/{activity_uuid}")
async def api_get_activity(
+ request: Request,
+ activity_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+) -> ActivityRead:
+ """
+ Get single activity by activity_id
+ """
+ return await get_activity(
+ request, activity_uuid, current_user=current_user, db_session=db_session
+ )
+
+@router.get("/id/{activity_id}")
+async def api_get_activityby_id(
request: Request,
activity_id: str,
current_user: PublicUser = Depends(get_current_user),
@@ -44,11 +59,10 @@ async def api_get_activity(
"""
Get single activity by activity_id
"""
- return await get_activity(
+ return await get_activityby_id(
request, activity_id, current_user=current_user, db_session=db_session
)
-
-
+
@router.get("/chapter/{chapter_id}")
async def api_get_chapter_activities(
request: Request,
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index c9a9509f..8f564915 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -206,7 +206,7 @@ async def api_put_assignment_task_ref_file(
)
-@router.delete("/{assignment_uuid}/tasks/{task_uuid}")
+@router.delete("/{assignment_uuid}/tasks/{assignment_task_uuid}")
async def api_delete_assignment_tasks(
request: Request,
assignment_task_uuid: str,
diff --git a/apps/api/src/routers/courses/courses.py b/apps/api/src/routers/courses/courses.py
index e81bf9ae..2afd99e4 100644
--- a/apps/api/src/routers/courses/courses.py
+++ b/apps/api/src/routers/courses/courses.py
@@ -18,13 +18,19 @@ from src.security.auth import get_current_user
from src.services.courses.courses import (
create_course,
get_course,
+ get_course_by_id,
get_course_meta,
get_courses_orgslug,
update_course,
delete_course,
update_course_thumbnail,
)
-from src.services.courses.updates import create_update, delete_update, get_updates_by_course_uuid, update_update
+from src.services.courses.updates import (
+ create_update,
+ delete_update,
+ get_updates_by_course_uuid,
+ update_update,
+)
router = APIRouter()
@@ -93,6 +99,21 @@ async def api_get_course(
)
+@router.get("/id/{course_id}")
+async def api_get_course_by_id(
+ request: Request,
+ course_id: str,
+ db_session: Session = Depends(get_db_session),
+ current_user: PublicUser = Depends(get_current_user),
+) -> CourseRead:
+ """
+ Get single Course by id
+ """
+ return await get_course_by_id(
+ request, course_id, current_user=current_user, db_session=db_session
+ )
+
+
@router.get("/{course_uuid}/meta")
async def api_get_course_meta(
request: Request,
@@ -154,7 +175,8 @@ async def api_delete_course(
return await delete_course(request, course_uuid, current_user, db_session)
-@ router.get("/{course_uuid}/updates")
+
+@router.get("/{course_uuid}/updates")
async def api_get_course_updates(
request: Request,
course_uuid: str,
@@ -165,7 +187,10 @@ async def api_get_course_updates(
Get Course Updates by course_uuid
"""
- return await get_updates_by_course_uuid(request, course_uuid, current_user, db_session)
+ return await get_updates_by_course_uuid(
+ request, course_uuid, current_user, db_session
+ )
+
@router.post("/{course_uuid}/updates")
async def api_create_course_update(
@@ -183,6 +208,7 @@ async def api_create_course_update(
request, course_uuid, update_object, current_user, db_session
)
+
@router.put("/{course_uuid}/update/{courseupdate_uuid}")
async def api_update_course_update(
request: Request,
@@ -200,6 +226,7 @@ async def api_update_course_update(
request, courseupdate_uuid, update_object, current_user, db_session
)
+
@router.delete("/{course_uuid}/update/{courseupdate_uuid}")
async def api_delete_course_update(
request: Request,
@@ -213,4 +240,3 @@ async def api_delete_course_update(
"""
return await delete_update(request, courseupdate_uuid, current_user, db_session)
-
diff --git a/apps/api/src/services/courses/activities/activities.py b/apps/api/src/services/courses/activities/activities.py
index f3a93d2c..8b5c7d03 100644
--- a/apps/api/src/services/courses/activities/activities.py
+++ b/apps/api/src/services/courses/activities/activities.py
@@ -116,6 +116,38 @@ async def get_activity(
return activity
+async def get_activityby_id(
+ request: Request,
+ activity_id: str,
+ current_user: PublicUser,
+ db_session: Session,
+):
+ statement = select(Activity).where(Activity.id == activity_id)
+ activity = db_session.exec(statement).first()
+
+ if not activity:
+ raise HTTPException(
+ status_code=404,
+ detail="Activity not found",
+ )
+
+ # Get course from that activity
+ statement = select(Course).where(Course.id == activity.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ activity = ActivityRead.model_validate(activity)
+
+ return activity
+
async def update_activity(
request: Request,
diff --git a/apps/api/src/services/courses/courses.py b/apps/api/src/services/courses/courses.py
index b3d2ed33..744f77b4 100644
--- a/apps/api/src/services/courses/courses.py
+++ b/apps/api/src/services/courses/courses.py
@@ -58,6 +58,38 @@ async def get_course(
return course
+async def get_course_by_id(
+ request: Request,
+ course_id: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ statement = select(Course).where(Course.id == course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # Get course authors
+ authors_statement = (
+ select(User)
+ .join(ResourceAuthor)
+ .where(ResourceAuthor.resource_uuid == course.course_uuid)
+ )
+ authors = db_session.exec(authors_statement).all()
+
+ # convert from User to UserRead
+ authors = [UserRead.model_validate(author) for author in authors]
+
+ course = CourseRead(**course.model_dump(), authors=authors)
+
+ return course
async def get_course_meta(
request: Request,
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
index 818bffd0..85557ec4 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
@@ -2,33 +2,66 @@
import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import { useLHSession } from '@components/Contexts/LHSessionContext';
+import { useOrg } from '@components/Contexts/OrgContext';
import FormLayout, { FormField, FormLabelAndMessage, Input, Textarea } from '@components/StyledElements/Form/Form';
import * as Form from '@radix-ui/react-form';
-import { getActivity } from '@services/courses/activities';
-import { updateAssignmentTask, updateReferenceFile } from '@services/courses/assignments';
+import { getAPIUrl } from '@services/config/config';
+import { getActivity, getActivityByID } from '@services/courses/activities';
+import { deleteAssignmentTask, updateAssignmentTask, updateReferenceFile } from '@services/courses/assignments';
import { getTaskRefFileDir } from '@services/media/media';
import { useFormik } from 'formik';
-import { ArrowBigUpDash, Cloud, File, GalleryVerticalEnd, Info, Loader, TentTree, Upload, UploadCloud } from 'lucide-react'
+import { ArrowBigUpDash, Cloud, File, GalleryVerticalEnd, Info, Loader, TentTree, Trash, Upload, UploadCloud } from 'lucide-react'
import Link from 'next/link';
import React, { use, useEffect } from 'react'
import toast from 'react-hot-toast';
+import { mutate } from 'swr';
function AssignmentTaskEditor({ page }: any) {
const [selectedSubPage, setSelectedSubPage] = React.useState(page)
+ const assignment = useAssignments() as any
const assignmentTaskState = useAssignmentsTask() as any
+ const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+
+ async function deleteTaskUI() {
+ const res = await deleteAssignmentTask(assignmentTaskState.assignmentTask.assignment_task_uuid, assignment.assignment_object.assignment_uuid, access_token)
+ if (res) {
+ assignmentTaskStateHook({
+ type: 'SET_MULTIPLE_STATES',
+ payload: {
+ selectedAssignmentTaskUUID: null,
+ assignmentTask: {},
+ },
+ });
+ mutate(`${getAPIUrl()}assignments/${assignment.assignment_object.assignment_uuid}/tasks`)
+ toast.success('Task deleted successfully')
+ } else {
+ toast.error('Error deleting task, please retry later.')
+ }
+ }
useEffect(() => {
- console.log(assignmentTaskState)
}
- , [assignmentTaskState])
+ , [assignmentTaskState,assignmentTaskStateHook])
return (
{assignmentTaskState.assignmentTask && Object.keys(assignmentTaskState.assignmentTask).length > 0 && (
-
- {assignmentTaskState?.assignmentTask.title}
+
+
+ {assignmentTaskState?.assignmentTask.title}
+
+
+
deleteTaskUI()}
+ className='flex px-2 py-1.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-red-800 bg-rose-100 border border-rose-600/10 shadow-rose-900/10 shadow-lg'>
+
+
Delete Task
+
+
{
+ return getTaskRefFileDir(
+ org?.org_uuid,
+ assignment.course_object.course_uuid,
+ assignment.activity_object.activity_uuid,
+ assignment.assignment_object.assignment_uuid,
+ assignmentTaskState.assignmentTask.assignment_task_uuid,
+ assignmentTaskState.assignmentTask.reference_file
+ )
+ }
+
const deleteReferenceFile = async () => {
setIsLoading(true)
const res = await updateReferenceFile(
@@ -245,19 +292,16 @@ function UpdateTaskRef() {
}
async function getActivityUI() {
- const res = await getActivity(assignment.assignment_object.activity_id, null, access_token)
- console.log(res)
+ const res = await getActivityByID(assignment.assignment_object.activity_id, null, access_token)
setActivity(res.data)
}
-
+
useEffect(() => {
getActivityUI()
- console.log(assignment.assignment_object.assignment_uuid)
- console.log(assignmentTaskState.assignmentTask.assignment_task_uuid)
}
- , [assignmentTaskState])
+ , [assignmentTaskState, org])
@@ -273,7 +317,7 @@ function UpdateTaskRef() {
)}
- {assignmentTaskState.assignmentTask.reference_file && (
+ {assignmentTaskState.assignmentTask.reference_file && !isLoading && (
@@ -283,10 +327,11 @@ function UpdateTaskRef() {
{assignmentTaskState.assignmentTask.reference_file.split('.').pop()}
- Download
+ Download
{/** */}
diff --git a/apps/web/components/Contexts/Assignments/AssignmentContext.tsx b/apps/web/components/Contexts/Assignments/AssignmentContext.tsx
index f54844ee..8feb351b 100644
--- a/apps/web/components/Contexts/Assignments/AssignmentContext.tsx
+++ b/apps/web/components/Contexts/Assignments/AssignmentContext.tsx
@@ -10,7 +10,7 @@ export const AssignmentContext = createContext({})
export function AssignmentProvider({ children, assignment_uuid }: { children: React.ReactNode, assignment_uuid: string }) {
const session = useLHSession() as any
const accessToken = session?.data?.tokens?.access_token
- const [assignmentsFull, setAssignmentsFull] = React.useState({ assignment_object: null, assignment_tasks: null })
+ const [assignmentsFull, setAssignmentsFull] = React.useState({ assignment_object: null, assignment_tasks: null, course_object: null , activity_object: null})
const { data: assignment, error: assignmentError } = useSWR(
`${getAPIUrl()}assignments/${assignment_uuid}`,
@@ -22,15 +22,28 @@ export function AssignmentProvider({ children, assignment_uuid }: { children: Re
(url) => swrFetcher(url, accessToken)
)
+ // Define a key for the course object based on assignment data
+ const course_id = assignment?.course_id
+
+ const { data: course_object, error: courseObjectError } = useSWR(
+ course_id ? `${getAPIUrl()}courses/id/${course_id}` : null,
+ (url) => swrFetcher(url, accessToken)
+ )
+
+ const activity_id = assignment?.activity_id
+
+ const { data: activity_object, error: activityObjectError } = useSWR(
+ activity_id ? `${getAPIUrl()}activities/id/${activity_id}` : null,
+ (url) => swrFetcher(url, accessToken)
+ )
+
useEffect(() => {
- setAssignmentsFull({ assignment_object: assignment, assignment_tasks: assignment_tasks })
- }
- , [assignment, assignment_tasks])
+ setAssignmentsFull({ assignment_object: assignment, assignment_tasks: assignment_tasks, course_object: course_object, activity_object: activity_object })
+ }, [assignment, assignment_tasks, course_object, activity_object])
- if (assignmentError || assignmentTasksError) return
-
- if (!assignment || !assignment_tasks) return
+ if (assignmentError || assignmentTasksError || courseObjectError) return
+ if (!assignment || !assignment_tasks || (course_id && !course_object)) return
return
{children}
}
diff --git a/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx b/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
index 99d8adc2..32b69145 100644
--- a/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
+++ b/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
@@ -36,19 +36,19 @@ export function AssignmentsTaskProvider({ children }: { children: React.ReactNod
async function fetchAssignmentTask(assignmentTaskUUID: string) {
const res = await getAssignmentTask(assignmentTaskUUID, access_token);
-
+
if (res.success) {
dispatch({ type: 'setAssignmentTask', payload: res.data });
}
}
useEffect(() => {
-
+
if (state.selectedAssignmentTaskUUID) {
fetchAssignmentTask(state.selectedAssignmentTaskUUID);
mutate(`${getAPIUrl()}assignments/${assignment.assignment_object?.assignment_uuid}/tasks`);
}
- }, [state.selectedAssignmentTaskUUID, state.reloadTrigger,assignment]);
+ }, [state.selectedAssignmentTaskUUID, state.reloadTrigger, assignment]);
return (
@@ -78,11 +78,17 @@ export function useAssignmentsTaskDispatch() {
function assignmentstaskReducer(state: State, action: Action): State {
switch (action.type) {
case 'setSelectedAssignmentTaskUUID':
+ console.log('st', action.payload)
return { ...state, selectedAssignmentTaskUUID: action.payload };
case 'setAssignmentTask':
return { ...state, assignmentTask: action.payload };
case 'reload':
return { ...state, reloadTrigger: state.reloadTrigger + 1 };
+ case 'SET_MULTIPLE_STATES':
+ return {
+ ...state,
+ ...action.payload,
+ };
default:
return state;
}
diff --git a/apps/web/services/courses/activities.ts b/apps/web/services/courses/activities.ts
index 1fa050f0..162780f7 100644
--- a/apps/web/services/courses/activities.ts
+++ b/apps/web/services/courses/activities.ts
@@ -74,12 +74,25 @@ export async function createExternalVideoActivity(
}
export async function getActivity(
+ activity_uuid: any,
+ next: any,
+ access_token: string
+) {
+ const result = await fetch(
+ `${getAPIUrl()}activities/${activity_uuid}`,
+ RequestBodyWithAuthHeader('GET', null, next, access_token)
+ )
+ const res = await result.json()
+ return res
+}
+
+export async function getActivityByID(
activity_id: any,
next: any,
access_token: string
) {
const result = await fetch(
- `${getAPIUrl()}activities/${activity_id}`,
+ `${getAPIUrl()}activities/id/${activity_id}`,
RequestBodyWithAuthHeader('GET', null, next, access_token)
)
const res = await result.json()
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
index 1e7fc28e..a8a32523 100644
--- a/apps/web/services/courses/assignments.ts
+++ b/apps/web/services/courses/assignments.ts
@@ -92,6 +92,19 @@ export async function updateAssignmentTask(
return res
}
+export async function deleteAssignmentTask(
+ assignmentTaskUUID: string,
+ assignmentUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}`,
+ RequestBodyWithAuthHeader('DELETE', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
+
export async function updateReferenceFile(
file: any,
assignmentTaskUUID: string,
diff --git a/apps/web/services/courses/courses.ts b/apps/web/services/courses/courses.ts
index 7c9313ed..a8b687fd 100644
--- a/apps/web/services/courses/courses.ts
+++ b/apps/web/services/courses/courses.ts
@@ -55,6 +55,15 @@ export async function getCourse(course_uuid: string, next: any, access_token:any
return res
}
+export async function getCourseById(course_id: string, next: any, access_token:any) {
+ const result: any = await fetch(
+ `${getAPIUrl()}courses/id/${course_id}`,
+ RequestBodyWithAuthHeader('GET', null, next,access_token)
+ )
+ const res = await errorHandling(result)
+ return res
+}
+
export async function updateCourseThumbnail(course_uuid: any, thumbnail: any, access_token:any) {
const formData = new FormData()
formData.append('thumbnail', thumbnail)
diff --git a/apps/web/services/media/media.ts b/apps/web/services/media/media.ts
index 2b0185ee..67dd305d 100644
--- a/apps/web/services/media/media.ts
+++ b/apps/web/services/media/media.ts
@@ -47,30 +47,30 @@ export function getActivityBlockMediaDirectory(
export function getTaskRefFileDir(
orgUUID: string,
- courseId: string,
- activityId: string,
+ courseUUID: string,
+ activityUUID: string,
assignmentUUID: string,
assignmentTaskUUID: string,
fileID : string
) {
- let uri = `${getMediaUrl()}content/orgs/${orgUUID}/courses/${courseId}/activities/${activityId}/assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/${fileID}`
+ let uri = `${getMediaUrl()}content/orgs/${orgUUID}/courses/${courseUUID}/activities/${activityUUID}/assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/${fileID}`
return uri
}
export function getActivityMediaDirectory(
orgUUID: string,
- courseId: string,
- activityId: string,
+ courseUUID: string,
+ activityUUID: string,
fileId: string,
activityType: string
) {
if (activityType == 'video') {
- let uri = `${getMediaUrl()}content/orgs/${orgUUID}/courses/${courseId}/activities/${activityId}/video/${fileId}`
+ let uri = `${getMediaUrl()}content/orgs/${orgUUID}/courses/${courseUUID}/activities/${activityUUID}/video/${fileId}`
return uri
}
if (activityType == 'documentpdf') {
- let uri = `${getMediaUrl()}content/orgs/${orgUUID}/courses/${courseId}/activities/${activityId}/documentpdf/${fileId}`
+ let uri = `${getMediaUrl()}content/orgs/${orgUUID}/courses/${courseUUID}/activities/${activityUUID}/documentpdf/${fileId}`
return uri
}
}
From 175a5a97fa0c981dd1d1350d3ab9a9bb2769ced0 Mon Sep 17 00:00:00 2001
From: swve
Date: Wed, 17 Jul 2024 23:41:46 +0200
Subject: [PATCH 10/25] feat: full quiz tasks edition and creation
---
.../courses/activities/assignments.py | 2 +-
.../_components/Modals/NewTaskModal.tsx | 5 +-
.../Subs/AssignmentTaskContentEdit.tsx | 24 +++
.../Subs/AssignmentTaskGeneralEdit.tsx} | 104 +---------
.../Subs/TaskTypes/TaskQuizObject.tsx | 192 ++++++++++++++++++
.../_components/TaskEditor/TaskEditor.tsx | 125 ++++++++++++
.../assignments/[assignmentuuid]/page.tsx | 92 +++++----
.../Objects/Assignments/AssignmentBoxUI.tsx | 53 +++++
8 files changed, 453 insertions(+), 144 deletions(-)
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
rename apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/{TaskEditor.tsx => TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx} (69%)
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx
create mode 100644 apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index e5e3ef85..4d58e196 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -363,7 +363,7 @@ async def read_assignment_tasks(
# Find assignments tasks for an assignment
statement = select(AssignmentTask).where(
- assignment.assignment_uuid == assignment_uuid
+ AssignmentTask.assignment_id == assignment.id
)
# RBAC check
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx
index fea5b9f3..73a74beb 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/Modals/NewTaskModal.tsx
@@ -1,3 +1,4 @@
+import { useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import { useLHSession } from '@components/Contexts/LHSessionContext';
import { getAPIUrl } from '@services/config/config';
import { createAssignmentTask } from '@services/courses/assignments'
@@ -10,6 +11,7 @@ function NewTaskModal({ closeModal, assignment_uuid }: any) {
const session = useLHSession() as any;
const access_token = session?.data?.tokens?.access_token;
const reminderShownRef = React.useRef(false);
+ const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any
function showReminderToast() {
// Check if the reminder has already been shown using sessionStorage
@@ -33,10 +35,11 @@ function NewTaskModal({ closeModal, assignment_uuid }: any) {
contents: {},
max_grade_value: 100,
}
- await createAssignmentTask(task_object, assignment_uuid, access_token)
+ const res = await createAssignmentTask(task_object, assignment_uuid, access_token)
toast.success('Task created successfully')
showReminderToast()
mutate(`${getAPIUrl()}assignments/${assignment_uuid}/tasks`)
+ assignmentTaskStateHook({ type: 'setSelectedAssignmentTaskUUID', payload: res.data.assignment_task_uuid })
closeModal(false)
}
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
new file mode 100644
index 00000000..0485d125
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
@@ -0,0 +1,24 @@
+import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
+import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import React, { useEffect } from 'react'
+import TaskQuizObject from './TaskTypes/TaskQuizObject';
+
+function AssignmentTaskContentEdit() {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any
+ const assignment = useAssignments() as any
+
+ useEffect(() => {
+ }
+ , [assignment, assignmentTaskStateHook])
+
+ return (
+
+
+
+ )
+}
+
+export default AssignmentTaskContentEdit
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx
similarity index 69%
rename from apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
rename to apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx
index 85557ec4..271bd7e8 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx
@@ -16,103 +16,7 @@ import React, { use, useEffect } from 'react'
import toast from 'react-hot-toast';
import { mutate } from 'swr';
-function AssignmentTaskEditor({ page }: any) {
- const [selectedSubPage, setSelectedSubPage] = React.useState(page)
- const assignment = useAssignments() as any
- const assignmentTaskState = useAssignmentsTask() as any
- const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any
- const session = useLHSession() as any;
- const access_token = session?.data?.tokens?.access_token;
-
- async function deleteTaskUI() {
- const res = await deleteAssignmentTask(assignmentTaskState.assignmentTask.assignment_task_uuid, assignment.assignment_object.assignment_uuid, access_token)
- if (res) {
- assignmentTaskStateHook({
- type: 'SET_MULTIPLE_STATES',
- payload: {
- selectedAssignmentTaskUUID: null,
- assignmentTask: {},
- },
- });
- mutate(`${getAPIUrl()}assignments/${assignment.assignment_object.assignment_uuid}/tasks`)
- toast.success('Task deleted successfully')
- } else {
- toast.error('Error deleting task, please retry later.')
- }
- }
-
- useEffect(() => {
- }
- , [assignmentTaskState,assignmentTaskStateHook])
-
- return (
-
- {assignmentTaskState.assignmentTask && Object.keys(assignmentTaskState.assignmentTask).length > 0 && (
-
-
-
-
- {assignmentTaskState?.assignmentTask.title}
-
-
-
deleteTaskUI()}
- className='flex px-2 py-1.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-red-800 bg-rose-100 border border-rose-600/10 shadow-rose-900/10 shadow-lg'>
-
-
Delete Task
-
-
-
-
-
setSelectedSubPage('general')}
- className={`flex space-x-4 py-2 w-fit text-center border-black transition-all ease-linear ${selectedSubPage === 'general'
- ? 'border-b-4'
- : 'opacity-50'
- } cursor-pointer`}
- >
-
-
-
setSelectedSubPage('content')}
- className={`flex space-x-4 py-2 w-fit text-center border-black transition-all ease-linear ${selectedSubPage === 'content'
- ? 'border-b-4'
- : 'opacity-50'
- } cursor-pointer`}
- >
-
-
-
-
-
- {selectedSubPage === 'general' &&
}
-
-
- )}
- {Object.keys(assignmentTaskState.assignmentTask).length == 0 && (
-
-
-
-
-
- No Task Selected
-
-
-
-
- )}
-
-
- )
-}
-
-function AssignmentTaskGeneralEdit() {
+export function AssignmentTaskGeneralEdit() {
const session = useLHSession() as any;
const access_token = session?.data?.tokens?.access_token;
const assignmentTaskState = useAssignmentsTask() as any
@@ -127,8 +31,6 @@ function AssignmentTaskGeneralEdit() {
return errors;
};
-
-
const formik = useFormik({
initialValues: {
title: assignmentTaskState.assignmentTask.title,
@@ -373,6 +275,4 @@ function UpdateTaskRef() {
)
-}
-
-export default AssignmentTaskEditor
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
new file mode 100644
index 00000000..1b53c085
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
@@ -0,0 +1,192 @@
+import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
+import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import AssignmentBoxUI from '@components/Objects/Assignments/AssignmentBoxUI';
+import { updateAssignmentTask } from '@services/courses/assignments';
+import { Check, Minus, Plus, PlusCircle, X } from 'lucide-react';
+import React, { useEffect, useState } from 'react';
+import toast from 'react-hot-toast';
+import { v4 as uuidv4 } from 'uuid';
+
+type QuizSchema = {
+ questionText: string;
+ questionUUID?: string;
+ options: {
+ optionUUID?: string;
+ text: string;
+ fileID: string;
+ type: 'text' | 'image' | 'audio' | 'video';
+ correct: boolean;
+ }[];
+};
+
+function TaskQuizObject() {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const assignmentTaskState = useAssignmentsTask() as any;
+ const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any;
+ const assignment = useAssignments() as any;
+
+ // Teacher area
+ const [questions, setQuestions] = useState
([
+ { questionText: '', questionUUID: 'question_' + uuidv4(), options: [{ text: '', fileID: '', type: 'text', correct: false, optionUUID: 'option_' + uuidv4() }] },
+ ]);
+
+ const handleQuestionChange = (index: number, value: string) => {
+ const updatedQuestions = [...questions];
+ updatedQuestions[index].questionText = value;
+ setQuestions(updatedQuestions);
+ };
+
+ const handleOptionChange = (qIndex: number, oIndex: number, value: string) => {
+ const updatedQuestions = [...questions];
+ updatedQuestions[qIndex].options[oIndex].text = value;
+ setQuestions(updatedQuestions);
+ };
+
+ const addOption = (qIndex: number) => {
+ const updatedQuestions = [...questions];
+ updatedQuestions[qIndex].options.push({ text: '', fileID: '', type: 'text', correct: false, optionUUID: 'option_' + uuidv4() });
+ setQuestions(updatedQuestions);
+ };
+
+ const removeOption = (qIndex: number, oIndex: number) => {
+ const updatedQuestions = [...questions];
+ updatedQuestions[qIndex].options.splice(oIndex, 1);
+ setQuestions(updatedQuestions);
+ };
+
+ const addQuestion = () => {
+ setQuestions([...questions, { questionText: '', questionUUID: 'question_' + uuidv4(), options: [{ text: '', fileID: '', type: 'text', correct: false, optionUUID: 'option_' + uuidv4() }] }]);
+ };
+
+ const removeQuestion = (qIndex: number) => {
+ const updatedQuestions = [...questions];
+ updatedQuestions.splice(qIndex, 1);
+ setQuestions(updatedQuestions);
+ };
+
+ const toggleCorrectOption = (qIndex: number, oIndex: number) => {
+ const updatedQuestions = [...questions];
+ // Find the option to toggle
+ const optionToToggle = updatedQuestions[qIndex].options[oIndex];
+ // Toggle the 'correct' property of the option
+ optionToToggle.correct = !optionToToggle.correct;
+ setQuestions(updatedQuestions);
+ };
+
+ const saveFC = async () => {
+ // Save the quiz to the server
+ const values = {
+ contents: {
+ questions,
+ },
+ };
+ const res = await updateAssignmentTask(values, assignmentTaskState.assignmentTask.assignment_task_uuid, assignment.assignment_object.assignment_uuid, access_token);
+ if (res) {
+ assignmentTaskStateHook({
+ type: 'reload',
+ });
+ toast.success('Task saved successfully');
+ } else {
+ toast.error('Error saving task, please retry later.');
+ }
+ };
+
+ useEffect(() => {
+ if (assignmentTaskState.assignmentTask.contents?.questions) {
+ setQuestions(assignmentTaskState.assignmentTask.contents.questions);
+ }
+ }, [assignmentTaskState,assignment,assignmentTaskStateHook,access_token]);
+
+ // Teacher area end
+
+ return (
+
+
+ {questions.map((question, qIndex) => (
+
+
+
handleQuestionChange(qIndex, e.target.value)}
+ placeholder="Question"
+ className="w-full px-3 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold"
+ />
+
removeQuestion(qIndex)}
+ >
+
+
+
+
+ {question.options.map((option, oIndex) => (
+
+
+
+
{String.fromCharCode(65 + oIndex)}
+
+
handleOptionChange(qIndex, oIndex, e.target.value)}
+ placeholder="Option"
+ className="w-full mx-2 px-3 pr-6 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold"
+ />
+
toggleCorrectOption(qIndex, oIndex)}
+ >
+ {option.correct ?
:
}
+ {option.correct ? (
+
Correct
+ ) : (
+
Incorrect
+ )}
+
+
removeOption(qIndex, oIndex)}
+ >
+
+
+
+
+ {/* Show this at the last option */}
+ {oIndex === question.options.length - 1 && (
+
+
addOption(qIndex)}
+ >
+
+
+
+
+ )}
+
+
+ ))}
+
+
+ ))}
+
+
+
+ );
+}
+
+export default TaskQuizObject;
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx
new file mode 100644
index 00000000..6d14990b
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx
@@ -0,0 +1,125 @@
+'use client';
+import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
+import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import { useOrg } from '@components/Contexts/OrgContext';
+import FormLayout, { FormField, FormLabelAndMessage, Input, Textarea } from '@components/StyledElements/Form/Form';
+import * as Form from '@radix-ui/react-form';
+import { getAPIUrl } from '@services/config/config';
+import { getActivity, getActivityByID } from '@services/courses/activities';
+import { deleteAssignmentTask, updateAssignmentTask, updateReferenceFile } from '@services/courses/assignments';
+import { getTaskRefFileDir } from '@services/media/media';
+import { useFormik } from 'formik';
+import { ArrowBigUpDash, Cloud, File, GalleryVerticalEnd, Info, Loader, TentTree, Trash, Upload, UploadCloud } from 'lucide-react'
+import Link from 'next/link';
+import React, { use, useEffect } from 'react'
+import toast from 'react-hot-toast';
+import { mutate } from 'swr';
+import { AssignmentTaskGeneralEdit } from './Subs/AssignmentTaskGeneralEdit';
+import AssignmentTaskContentEdit from './Subs/AssignmentTaskContentEdit';
+
+function AssignmentTaskEditor({ page }: any) {
+ const [selectedSubPage, setSelectedSubPage] = React.useState(page)
+ const assignment = useAssignments() as any
+ const assignmentTaskState = useAssignmentsTask() as any
+ const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+
+ async function deleteTaskUI() {
+ const res = await deleteAssignmentTask(assignmentTaskState.assignmentTask.assignment_task_uuid, assignment.assignment_object.assignment_uuid, access_token)
+ if (res) {
+ assignmentTaskStateHook({
+ type: 'SET_MULTIPLE_STATES',
+ payload: {
+ selectedAssignmentTaskUUID: null,
+ assignmentTask: {},
+ },
+ });
+ mutate(`${getAPIUrl()}assignments/${assignment.assignment_object.assignment_uuid}/tasks`)
+ mutate(`${getAPIUrl()}assignments/${assignment.assignment_object.assignment_uuid}`)
+ toast.success('Task deleted successfully')
+ } else {
+ toast.error('Error deleting task, please retry later.')
+ }
+ }
+
+ useEffect(() => {
+ // Switch back to general page if the selectedAssignmentTaskUUID is changed
+ if (assignmentTaskState.selectedAssignmentTaskUUID !== assignmentTaskState.assignmentTask.assignment_task_uuid) {
+ setSelectedSubPage('general')
+ }
+ }
+ , [assignmentTaskState, assignmentTaskStateHook, selectedSubPage, assignment])
+
+ return (
+
+ {assignmentTaskState.assignmentTask && Object.keys(assignmentTaskState.assignmentTask).length > 0 && (
+
+
+
+
+ {assignmentTaskState?.assignmentTask.title}
+
+
+
deleteTaskUI()}
+ className='flex px-2 py-1.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-red-800 bg-rose-100 border border-rose-600/10 shadow-rose-900/10 shadow-lg'>
+
+
Delete Task
+
+
+
+
+
setSelectedSubPage('general')}
+ className={`flex space-x-4 py-2 w-fit text-center border-black transition-all ease-linear ${selectedSubPage === 'general'
+ ? 'border-b-4'
+ : 'opacity-50'
+ } cursor-pointer`}
+ >
+
+
+
setSelectedSubPage('content')}
+ className={`flex space-x-4 py-2 w-fit text-center border-black transition-all ease-linear ${selectedSubPage === 'content'
+ ? 'border-b-4'
+ : 'opacity-50'
+ } cursor-pointer`}
+ >
+
+
+
+
+
+ {selectedSubPage === 'general' &&
}
+ {selectedSubPage === 'content' &&
}
+
+
+ )}
+ {Object.keys(assignmentTaskState.assignmentTask).length == 0 && (
+
+
+
+
+
+ No Task Selected
+
+
+
+
+ )}
+
+
+ )
+}
+
+
+
+export default AssignmentTaskEditor
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
index 76cb6eef..66664d94 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
@@ -1,56 +1,57 @@
'use client';
import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'
import { BookOpen, BookX, EllipsisVertical, LayoutList } from 'lucide-react'
-import React from 'react'
-import AssignmentTaskEditor from './_components/TaskEditor';
-import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext';
+import React, { useEffect } from 'react'
+import { AssignmentProvider, useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
import AssignmentTasks from './_components/Tasks';
import { useParams } from 'next/navigation';
import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import ToolTip from '@components/StyledElements/Tooltip/Tooltip';
+import AssignmentTaskEditor from './_components/TaskEditor/TaskEditor';
function AssignmentEdit() {
const params = useParams<{ assignmentuuid: string; }>()
return (
-
-
-
-
-
-
Assignment Editor
+
+
+
-
-
-
Published
-
-
-
-
-
-
-
+
+
+
Published
+
+
+
+
+
+
+
+
-
-
-
+
+
@@ -65,10 +66,21 @@ function AssignmentEdit() {
-
-
+
+
)
}
-export default AssignmentEdit
\ No newline at end of file
+export default AssignmentEdit
+
+function BrdCmpx() {
+ const assignment = useAssignments() as any
+
+ useEffect(() => {
+ }, [assignment])
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx b/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
new file mode 100644
index 00000000..d27769e7
--- /dev/null
+++ b/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
@@ -0,0 +1,53 @@
+import { BookUser, EllipsisVertical, ListTodo, Save } from 'lucide-react'
+import React from 'react'
+
+type AssignmentBoxProps = {
+ type: 'quiz' | 'task'
+ view?: 'teacher' | 'student'
+ saveFC?: () => void
+ children: React.ReactNode
+
+}
+
+function AssignmentBoxUI({ type, view, saveFC, children }: AssignmentBoxProps) {
+ return (
+
+
+
+
+ {type === 'quiz' &&
+
}
+
+
+
+
+
+
+ {view === 'teacher' &&
+
+ }
+
+
+
+ {/* Save button */}
+
saveFC && saveFC()}
+ className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-slate-500 bg-white/60 hover:bg-white/80 linear transition-all nice-shadow '>
+
+
Save
+
+
+
+
+ {children}
+
+ )
+}
+
+export default AssignmentBoxUI
\ No newline at end of file
From ccf387cc98aa463e40ebbd210043f8f19c1077fc Mon Sep 17 00:00:00 2001
From: swve
Date: Thu, 18 Jul 2024 00:15:42 +0200
Subject: [PATCH 11/25] feat: assignment publishing state switching
---
.../Subs/AssignmentTaskContentEdit.tsx | 8 +-
.../Subs/TaskTypes/TaskFileObject.tsx | 14 +++
.../assignments/[assignmentuuid]/page.tsx | 90 +++++++++++++------
.../Objects/Assignments/AssignmentBoxUI.tsx | 9 +-
apps/web/services/courses/assignments.ts | 13 +++
5 files changed, 102 insertions(+), 32 deletions(-)
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
index 0485d125..5d79a324 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
@@ -3,20 +3,22 @@ import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Cont
import { useLHSession } from '@components/Contexts/LHSessionContext';
import React, { useEffect } from 'react'
import TaskQuizObject from './TaskTypes/TaskQuizObject';
+import TaskFileObject from './TaskTypes/TaskFileObject';
function AssignmentTaskContentEdit() {
const session = useLHSession() as any;
const access_token = session?.data?.tokens?.access_token;
const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any
- const assignment = useAssignments() as any
+ const assignment_task = useAssignmentsTask() as any
useEffect(() => {
}
- , [assignment, assignmentTaskStateHook])
+ , [assignment_task, assignmentTaskStateHook])
return (
-
+ {assignment_task?.assignmentTask.assignment_type === 'QUIZ' && }
+ {assignment_task?.assignmentTask.assignment_type === 'FILE_SUBMISSION' && }
)
}
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
new file mode 100644
index 00000000..ed7bd2e8
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
@@ -0,0 +1,14 @@
+import AssignmentBoxUI from '@components/Objects/Assignments/AssignmentBoxUI'
+import { Info } from 'lucide-react'
+import React from 'react'
+
+export default function TaskFileObject({ view }: any) {
+ return (
+
+
+
+
User will be able to submit a file for this task, you'll be able to review it in the Submissions Tab
+
+
+ )
+}
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
index 66664d94..44b2c164 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
@@ -8,6 +8,11 @@ import { useParams } from 'next/navigation';
import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import ToolTip from '@components/StyledElements/Tooltip/Tooltip';
import AssignmentTaskEditor from './_components/TaskEditor/TaskEditor';
+import { updateAssignment } from '@services/courses/assignments';
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import { mutate } from 'swr';
+import { getAPIUrl } from '@services/config/config';
+import toast from 'react-hot-toast';
function AssignmentEdit() {
const params = useParams<{ assignmentuuid: string; }>()
@@ -17,41 +22,17 @@ function AssignmentEdit() {
-
-
Published
-
-
-
-
-
-
-
-
+
-
@@ -83,4 +64,59 @@ function BrdCmpx() {
return (
)
-}
\ No newline at end of file
+}
+
+function PublishingState() {
+ const assignment = useAssignments() as any;
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+
+ async function updateAssignmentPublishState(assignmentUUID: string) {
+ const res = await updateAssignment({ published: !assignment?.assignment_object?.published }, assignmentUUID, access_token)
+ if (res.success) {
+ mutate(`${getAPIUrl()}assignments/${assignmentUUID}`)
+ toast.success('The assignment has been updated successfully')
+ }
+ else {
+ toast.error('Error updating assignment, please retry later.')
+ }
+ }
+
+ useEffect(() => {
+ console.log('assignment', assignment?.assignment_object?.assignment_uuid)
+ }, [assignment])
+
+ return (
+
+
+ {assignment?.assignment_object?.published ? 'Published' : 'Unpublished'}
+
+
+ {assignment?.assignment_object?.published &&
+ updateAssignmentPublishState(assignment?.assignment_object?.assignment_uuid)}
+ className='flex px-3 py-2 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-gray-800 font-medium from-gray-400/50 to-gray-200/80 border border-gray-600/10 shadow-gray-900/10 shadow-lg'>
+
+
Unpublish
+
+ }
+ {!assignment?.assignment_object?.published &&
+
+ updateAssignmentPublishState(assignment?.assignment_object?.assignment_uuid)}
+ className='flex px-3 py-2 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-green-800 font-medium from-green-400/50 to-lime-200/80 border border-green-600/10 shadow-green-900/10 shadow-lg'>
+
+
Publish
+
+ }
+
+ )
+}
diff --git a/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx b/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
index d27769e7..0c281866 100644
--- a/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
+++ b/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
@@ -1,8 +1,8 @@
-import { BookUser, EllipsisVertical, ListTodo, Save } from 'lucide-react'
+import { BookUser, EllipsisVertical, File, FileUp, ListTodo, Save } from 'lucide-react'
import React from 'react'
type AssignmentBoxProps = {
- type: 'quiz' | 'task'
+ type: 'quiz' | 'file'
view?: 'teacher' | 'student'
saveFC?: () => void
children: React.ReactNode
@@ -20,6 +20,11 @@ function AssignmentBoxUI({ type, view, saveFC, children }: AssignmentBoxProps) {
Quiz
}
+ {type === 'file' &&
+
}
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
index a8a32523..1a6e54e8 100644
--- a/apps/web/services/courses/assignments.ts
+++ b/apps/web/services/courses/assignments.ts
@@ -14,6 +14,19 @@ export async function createAssignment(body: any, access_token: string) {
return res
}
+export async function updateAssignment(
+ body: any,
+ assignmentUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}`,
+ RequestBodyWithAuthHeader('PUT', body, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
+
export async function getAssignmentFromActivityUUID(
activityUUID: string,
access_token: string
From 182cd73001f42cc3f58b5d868ade234c00c783a2 Mon Sep 17 00:00:00 2001
From: swve
Date: Thu, 18 Jul 2024 00:36:58 +0200
Subject: [PATCH 12/25] feat: Remove unused imports and update some packages
---
.../Subs/AssignmentTaskContentEdit.tsx | 1 -
.../Subs/AssignmentTaskGeneralEdit.tsx | 10 +-
.../_components/TaskEditor/TaskEditor.tsx | 13 +-
.../DraggableElements/ActivityElement.tsx | 2 +-
.../Objects/Assignments/AssignmentBoxUI.tsx | 2 +-
.../Dash/OrgUserGroups/AddUserGroup.tsx | 5 -
.../Objects/Thumbnails/CourseThumbnail.tsx | 2 +-
apps/web/components/Onboarding/Onboarding.tsx | 2 +-
apps/web/package.json | 50 +-
apps/web/pnpm-lock.yaml | 1706 +++++++++--------
10 files changed, 982 insertions(+), 811 deletions(-)
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
index 5d79a324..ee38744a 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
@@ -1,4 +1,3 @@
-import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import { useLHSession } from '@components/Contexts/LHSessionContext';
import React, { useEffect } from 'react'
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx
index 271bd7e8..42255b16 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx
@@ -5,16 +5,14 @@ import { useLHSession } from '@components/Contexts/LHSessionContext';
import { useOrg } from '@components/Contexts/OrgContext';
import FormLayout, { FormField, FormLabelAndMessage, Input, Textarea } from '@components/StyledElements/Form/Form';
import * as Form from '@radix-ui/react-form';
-import { getAPIUrl } from '@services/config/config';
-import { getActivity, getActivityByID } from '@services/courses/activities';
-import { deleteAssignmentTask, updateAssignmentTask, updateReferenceFile } from '@services/courses/assignments';
+import { getActivityByID } from '@services/courses/activities';
+import { updateAssignmentTask, updateReferenceFile } from '@services/courses/assignments';
import { getTaskRefFileDir } from '@services/media/media';
import { useFormik } from 'formik';
-import { ArrowBigUpDash, Cloud, File, GalleryVerticalEnd, Info, Loader, TentTree, Trash, Upload, UploadCloud } from 'lucide-react'
+import { Cloud, File, Info, Loader, UploadCloud } from 'lucide-react'
import Link from 'next/link';
-import React, { use, useEffect } from 'react'
+import React, { useEffect } from 'react'
import toast from 'react-hot-toast';
-import { mutate } from 'swr';
export function AssignmentTaskGeneralEdit() {
const session = useLHSession() as any;
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx
index 6d14990b..09ba8d58 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx
@@ -2,17 +2,10 @@
import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import { useLHSession } from '@components/Contexts/LHSessionContext';
-import { useOrg } from '@components/Contexts/OrgContext';
-import FormLayout, { FormField, FormLabelAndMessage, Input, Textarea } from '@components/StyledElements/Form/Form';
-import * as Form from '@radix-ui/react-form';
import { getAPIUrl } from '@services/config/config';
-import { getActivity, getActivityByID } from '@services/courses/activities';
-import { deleteAssignmentTask, updateAssignmentTask, updateReferenceFile } from '@services/courses/assignments';
-import { getTaskRefFileDir } from '@services/media/media';
-import { useFormik } from 'formik';
-import { ArrowBigUpDash, Cloud, File, GalleryVerticalEnd, Info, Loader, TentTree, Trash, Upload, UploadCloud } from 'lucide-react'
-import Link from 'next/link';
-import React, { use, useEffect } from 'react'
+import { deleteAssignmentTask } from '@services/courses/assignments';
+import { GalleryVerticalEnd, Info, TentTree, Trash } from 'lucide-react'
+import React, { useEffect } from 'react'
import toast from 'react-hot-toast';
import { mutate } from 'swr';
import { AssignmentTaskGeneralEdit } from './Subs/AssignmentTaskGeneralEdit';
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
index daeea79a..9a226bb0 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
@@ -20,7 +20,7 @@ import { useRouter } from 'next/navigation'
import React, { useEffect, useState } from 'react'
import { Draggable } from 'react-beautiful-dnd'
import { mutate } from 'swr'
-import { deleteAssignment, deleteAssignmentUsingActivityUUID, getAssignmentFromActivityUUID } from '@services/courses/assignments'
+import { deleteAssignmentUsingActivityUUID, getAssignmentFromActivityUUID } from '@services/courses/assignments'
import { useOrg } from '@components/Contexts/OrgContext'
import { useCourse } from '@components/Contexts/CourseContext'
diff --git a/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx b/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
index 0c281866..f91f10d9 100644
--- a/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
+++ b/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
@@ -1,4 +1,4 @@
-import { BookUser, EllipsisVertical, File, FileUp, ListTodo, Save } from 'lucide-react'
+import { BookUser, EllipsisVertical, FileUp, ListTodo, Save } from 'lucide-react'
import React from 'react'
type AssignmentBoxProps = {
diff --git a/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx b/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx
index 9325e264..705a82bb 100644
--- a/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx
+++ b/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx
@@ -1,17 +1,12 @@
'use client'
import FormLayout, {
- ButtonBlack,
- Flex,
FormField,
- FormLabel,
FormLabelAndMessage,
- FormMessage,
Input,
} from '@components/StyledElements/Form/Form'
import * as Form from '@radix-ui/react-form'
import { useOrg } from '@components/Contexts/OrgContext'
import React from 'react'
-import { BarLoader } from 'react-spinners'
import { createUserGroup } from '@services/usergroups/usergroups'
import { mutate } from 'swr'
import { getAPIUrl } from '@services/config/config'
diff --git a/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx b/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx
index 995daf4a..0362779f 100644
--- a/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx
+++ b/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx
@@ -6,7 +6,7 @@ import { getUriWithOrg } from '@services/config/config'
import { deleteCourseFromBackend } from '@services/courses/courses'
import { getCourseThumbnailMediaDirectory } from '@services/media/media'
import { revalidateTags } from '@services/utils/ts/requests'
-import { BookMinus, FilePenLine, Settings, Settings2, X, EllipsisVertical } from 'lucide-react'
+import { BookMinus, FilePenLine, Settings2, EllipsisVertical } from 'lucide-react'
import { useLHSession } from '@components/Contexts/LHSessionContext'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
diff --git a/apps/web/components/Onboarding/Onboarding.tsx b/apps/web/components/Onboarding/Onboarding.tsx
index d958878b..7872f751 100644
--- a/apps/web/components/Onboarding/Onboarding.tsx
+++ b/apps/web/components/Onboarding/Onboarding.tsx
@@ -9,7 +9,7 @@ import OnBoardAI from '@public/onboarding/OnBoardAI.png';
import OnBoardUGs from '@public/onboarding/OnBoardUGs.png';
import OnBoardAccess from '@public/onboarding/OnBoardAccess.png';
import OnBoardMore from '@public/onboarding/OnBoardMore.png';
-import { ArrowRight, Book, Check, Globe, Info, PictureInPicture, Sparkle, Sprout, SquareUser, Users } from 'lucide-react';
+import { ArrowRight, Book, Check, Globe, Info, PictureInPicture, Sparkle, Sprout, SquareUser } from 'lucide-react';
import { useRouter } from 'next/navigation';
import { getUriWithOrg } from '@services/config/config';
import { useOrg } from '@components/Contexts/OrgContext';
diff --git a/apps/web/package.json b/apps/web/package.json
index 44deefd7..13591031 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -11,35 +11,35 @@
"lint:fix": "eslint --fix ."
},
"dependencies": {
- "@hocuspocus/provider": "^2.13.1",
+ "@hocuspocus/provider": "^2.13.5",
"@radix-ui/colors": "^0.1.9",
- "@radix-ui/react-aspect-ratio": "^1.0.3",
- "@radix-ui/react-dialog": "^1.0.5",
+ "@radix-ui/react-aspect-ratio": "^1.1.0",
+ "@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-form": "^0.0.3",
"@radix-ui/react-icons": "^1.3.0",
- "@radix-ui/react-switch": "^1.0.3",
- "@radix-ui/react-tooltip": "^1.0.7",
+ "@radix-ui/react-switch": "^1.1.0",
+ "@radix-ui/react-tooltip": "^1.1.2",
"@stitches/react": "^1.2.8",
- "@tiptap/core": "^2.4.0",
- "@tiptap/extension-code-block-lowlight": "^2.4.0",
- "@tiptap/extension-collaboration": "^2.4.0",
- "@tiptap/extension-collaboration-cursor": "^2.4.0",
- "@tiptap/extension-youtube": "^2.4.0",
- "@tiptap/html": "^2.4.0",
- "@tiptap/pm": "^2.4.0",
- "@tiptap/react": "^2.4.0",
- "@tiptap/starter-kit": "^2.4.0",
+ "@tiptap/core": "^2.5.4",
+ "@tiptap/extension-code-block-lowlight": "^2.5.4",
+ "@tiptap/extension-collaboration": "^2.5.4",
+ "@tiptap/extension-collaboration-cursor": "^2.5.4",
+ "@tiptap/extension-youtube": "^2.5.4",
+ "@tiptap/html": "^2.5.4",
+ "@tiptap/pm": "^2.5.4",
+ "@tiptap/react": "^2.5.4",
+ "@tiptap/starter-kit": "^2.5.4",
"@types/randomcolor": "^0.5.9",
"avvvatars-react": "^0.4.2",
"dayjs": "^1.11.11",
"formik": "^2.4.6",
"framer-motion": "^10.18.0",
"get-youtube-id": "^1.0.1",
- "highlight.js": "^11.9.0",
- "katex": "^0.16.10",
+ "highlight.js": "^11.10.0",
+ "katex": "^0.16.11",
"lowlight": "^3.1.0",
- "lucide-react": "^0.363.0",
- "next": "14.2.4",
+ "lucide-react": "^0.408.0",
+ "next": "14.2.5",
"next-auth": "^4.24.7",
"nextjs-toploader": "^1.6.12",
"prosemirror-state": "^1.4.3",
@@ -54,15 +54,15 @@
"react-spinners": "^0.13.8",
"react-youtube": "^10.1.0",
"sharp": "^0.33.4",
- "styled-components": "^6.1.11",
+ "styled-components": "^6.1.12",
"swr": "^2.2.5",
- "tailwind-merge": "^2.3.0",
+ "tailwind-merge": "^2.4.0",
"tailwind-scrollbar": "^3.1.0",
"uuid": "^9.0.1",
"y-indexeddb": "^9.0.12",
- "y-prosemirror": "^1.2.8",
+ "y-prosemirror": "^1.2.9",
"y-webrtc": "^10.3.0",
- "yjs": "^13.6.16"
+ "yjs": "^13.6.18"
},
"devDependencies": {
"@types/node": "20.12.2",
@@ -75,10 +75,10 @@
"@types/uuid": "^9.0.8",
"autoprefixer": "^10.4.19",
"eslint": "^8.57.0",
- "eslint-config-next": "^14.2.3",
+ "eslint-config-next": "^14.2.5",
"eslint-plugin-unused-imports": "^3.2.0",
- "postcss": "^8.4.38",
- "tailwindcss": "^3.4.4",
+ "postcss": "^8.4.39",
+ "tailwindcss": "^3.4.6",
"typescript": "5.4.4"
}
}
diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml
index 5d924813..986953f2 100644
--- a/apps/web/pnpm-lock.yaml
+++ b/apps/web/pnpm-lock.yaml
@@ -9,17 +9,17 @@ importers:
.:
dependencies:
'@hocuspocus/provider':
- specifier: ^2.13.1
- version: 2.13.1(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)
+ specifier: ^2.13.5
+ version: 2.13.5(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
'@radix-ui/colors':
specifier: ^0.1.9
version: 0.1.9
'@radix-ui/react-aspect-ratio':
- specifier: ^1.0.3
- version: 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: ^1.1.0
+ version: 1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-dialog':
- specifier: ^1.0.5
- version: 1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: ^1.1.1
+ version: 1.1.1(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-form':
specifier: ^0.0.3
version: 0.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -27,41 +27,41 @@ importers:
specifier: ^1.3.0
version: 1.3.0(react@18.3.1)
'@radix-ui/react-switch':
- specifier: ^1.0.3
- version: 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: ^1.1.0
+ version: 1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-tooltip':
- specifier: ^1.0.7
- version: 1.0.7(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: ^1.1.2
+ version: 1.1.2(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@stitches/react':
specifier: ^1.2.8
version: 1.2.8(react@18.3.1)
'@tiptap/core':
- specifier: ^2.4.0
- version: 2.4.0(@tiptap/pm@2.4.0)
+ specifier: ^2.5.4
+ version: 2.5.4(@tiptap/pm@2.5.4)
'@tiptap/extension-code-block-lowlight':
- specifier: ^2.4.0
- version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/extension-code-block@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
+ specifier: ^2.5.4
+ version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/extension-code-block@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
'@tiptap/extension-collaboration':
- specifier: ^2.4.0
- version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)(y-prosemirror@1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))
+ specifier: ^2.5.4
+ version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)(y-prosemirror@1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))
'@tiptap/extension-collaboration-cursor':
- specifier: ^2.4.0
- version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(y-prosemirror@1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))
+ specifier: ^2.5.4
+ version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(y-prosemirror@1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))
'@tiptap/extension-youtube':
- specifier: ^2.4.0
- version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
+ specifier: ^2.5.4
+ version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
'@tiptap/html':
- specifier: ^2.4.0
- version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
+ specifier: ^2.5.4
+ version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
'@tiptap/pm':
- specifier: ^2.4.0
- version: 2.4.0
+ specifier: ^2.5.4
+ version: 2.5.4
'@tiptap/react':
- specifier: ^2.4.0
- version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: ^2.5.4
+ version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@tiptap/starter-kit':
- specifier: ^2.4.0
- version: 2.4.0(@tiptap/pm@2.4.0)
+ specifier: ^2.5.4
+ version: 2.5.4(@tiptap/pm@2.5.4)
'@types/randomcolor':
specifier: ^0.5.9
version: 0.5.9
@@ -81,26 +81,26 @@ importers:
specifier: ^1.0.1
version: 1.0.1
highlight.js:
- specifier: ^11.9.0
- version: 11.9.0
+ specifier: ^11.10.0
+ version: 11.10.0
katex:
- specifier: ^0.16.10
- version: 0.16.10
+ specifier: ^0.16.11
+ version: 0.16.11
lowlight:
specifier: ^3.1.0
version: 3.1.0
lucide-react:
- specifier: ^0.363.0
- version: 0.363.0(react@18.3.1)
+ specifier: ^0.408.0
+ version: 0.408.0(react@18.3.1)
next:
- specifier: 14.2.4
- version: 14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: 14.2.5
+ version: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next-auth:
specifier: ^4.24.7
- version: 4.24.7(next@14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 4.24.7(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
nextjs-toploader:
specifier: ^1.6.12
- version: 1.6.12(next@14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 1.6.12(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
prosemirror-state:
specifier: ^1.4.3
version: 1.4.3
@@ -138,32 +138,32 @@ importers:
specifier: ^0.33.4
version: 0.33.4
styled-components:
- specifier: ^6.1.11
- version: 6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: ^6.1.12
+ version: 6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
swr:
specifier: ^2.2.5
version: 2.2.5(react@18.3.1)
tailwind-merge:
- specifier: ^2.3.0
- version: 2.3.0
+ specifier: ^2.4.0
+ version: 2.4.0
tailwind-scrollbar:
specifier: ^3.1.0
- version: 3.1.0(tailwindcss@3.4.4)
+ version: 3.1.0(tailwindcss@3.4.6)
uuid:
specifier: ^9.0.1
version: 9.0.1
y-indexeddb:
specifier: ^9.0.12
- version: 9.0.12(yjs@13.6.16)
+ version: 9.0.12(yjs@13.6.18)
y-prosemirror:
- specifier: ^1.2.8
- version: 1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)
+ specifier: ^1.2.9
+ version: 1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
y-webrtc:
specifier: ^10.3.0
- version: 10.3.0(yjs@13.6.16)
+ version: 10.3.0(yjs@13.6.18)
yjs:
- specifier: ^13.6.16
- version: 13.6.16
+ specifier: ^13.6.18
+ version: 13.6.18
devDependencies:
'@types/node':
specifier: 20.12.2
@@ -191,22 +191,22 @@ importers:
version: 9.0.8
autoprefixer:
specifier: ^10.4.19
- version: 10.4.19(postcss@8.4.38)
+ version: 10.4.19(postcss@8.4.39)
eslint:
specifier: ^8.57.0
version: 8.57.0
eslint-config-next:
- specifier: ^14.2.3
- version: 14.2.3(eslint@8.57.0)(typescript@5.4.4)
+ specifier: ^14.2.5
+ version: 14.2.5(eslint@8.57.0)(typescript@5.4.4)
eslint-plugin-unused-imports:
specifier: ^3.2.0
version: 3.2.0(eslint@8.57.0)
postcss:
- specifier: ^8.4.38
- version: 8.4.38
+ specifier: ^8.4.39
+ version: 8.4.39
tailwindcss:
- specifier: ^3.4.4
- version: 3.4.4
+ specifier: ^3.4.6
+ version: 3.4.6
typescript:
specifier: 5.4.4
version: 5.4.4
@@ -217,8 +217,8 @@ packages:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
- '@babel/runtime@7.24.7':
- resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==}
+ '@babel/runtime@7.24.8':
+ resolution: {integrity: sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==}
engines: {node: '>=6.9.0'}
'@emnapi/runtime@1.2.0':
@@ -245,8 +245,8 @@ packages:
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
- '@eslint-community/regexpp@4.10.1':
- resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==}
+ '@eslint-community/regexpp@4.11.0':
+ resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
'@eslint/eslintrc@2.1.4':
@@ -257,26 +257,26 @@ packages:
resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- '@floating-ui/core@1.6.2':
- resolution: {integrity: sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==}
+ '@floating-ui/core@1.6.4':
+ resolution: {integrity: sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==}
- '@floating-ui/dom@1.6.5':
- resolution: {integrity: sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==}
+ '@floating-ui/dom@1.6.7':
+ resolution: {integrity: sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==}
- '@floating-ui/react-dom@2.1.0':
- resolution: {integrity: sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==}
+ '@floating-ui/react-dom@2.1.1':
+ resolution: {integrity: sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==}
peerDependencies:
react: '>=16.8.0'
react-dom: '>=16.8.0'
- '@floating-ui/utils@0.2.2':
- resolution: {integrity: sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==}
+ '@floating-ui/utils@0.2.4':
+ resolution: {integrity: sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==}
- '@hocuspocus/common@2.13.1':
- resolution: {integrity: sha512-LN5h8+zaU+JlohCYHfKQmi500FyS76A7VtytacQ7iK6J+BKuTX2UhoKUCiWNkiIxv+fEsETQfdOjOmALSYFJPw==}
+ '@hocuspocus/common@2.13.5':
+ resolution: {integrity: sha512-8D9FzhZFlt0WsgXw5yT2zwSxi6z9d4V2vUz6co2vo3Cj+Y2bvGZsdDiTvU/MerGcCLME5k/w6PwLPojLYH/4pg==}
- '@hocuspocus/provider@2.13.1':
- resolution: {integrity: sha512-g0GRhFPcjlZ0ThELpGRT/V4feRfK9RKOxai7g14hpbhRGclqMXDtBe2HnRWYh9Xusch4kqZeYjTB6yCzIMlIIw==}
+ '@hocuspocus/provider@2.13.5':
+ resolution: {integrity: sha512-G3S0OiFSYkmbOwnbhV7FyJs4OBqB/+1YT9c44Ujux1RKowGm5H8+0p3FUHfXwd/3v9V0jE+E1FnFKoGonJSQwA==}
peerDependencies:
y-protocols: ^1.0.6
yjs: ^13.6.8
@@ -284,6 +284,7 @@ packages:
'@humanwhocodes/config-array@0.11.14':
resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
engines: {node: '>=10.10.0'}
+ deprecated: Use @eslint/config-array instead
'@humanwhocodes/module-importer@1.0.1':
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
@@ -291,6 +292,7 @@ packages:
'@humanwhocodes/object-schema@2.0.3':
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
+ deprecated: Use @eslint/object-schema instead
'@img/sharp-darwin-arm64@0.33.4':
resolution: {integrity: sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==}
@@ -421,8 +423,8 @@ packages:
resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
engines: {node: '>=6.0.0'}
- '@jridgewell/sourcemap-codec@1.4.15':
- resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
@@ -430,62 +432,62 @@ packages:
'@lifeomic/attempt@3.1.0':
resolution: {integrity: sha512-QZqem4QuAnAyzfz+Gj5/+SLxqwCAw2qmt7732ZXodr6VDWGeYLG6w1i/vYLa55JQM9wRuBKLmXmiZ2P0LtE5rw==}
- '@next/env@14.2.4':
- resolution: {integrity: sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==}
+ '@next/env@14.2.5':
+ resolution: {integrity: sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==}
- '@next/eslint-plugin-next@14.2.3':
- resolution: {integrity: sha512-L3oDricIIjgj1AVnRdRor21gI7mShlSwU/1ZGHmqM3LzHhXXhdkrfeNY5zif25Bi5Dd7fiJHsbhoZCHfXYvlAw==}
+ '@next/eslint-plugin-next@14.2.5':
+ resolution: {integrity: sha512-LY3btOpPh+OTIpviNojDpUdIbHW9j0JBYBjsIp8IxtDFfYFyORvw3yNq6N231FVqQA7n7lwaf7xHbVJlA1ED7g==}
- '@next/swc-darwin-arm64@14.2.4':
- resolution: {integrity: sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==}
+ '@next/swc-darwin-arm64@14.2.5':
+ resolution: {integrity: sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
- '@next/swc-darwin-x64@14.2.4':
- resolution: {integrity: sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==}
+ '@next/swc-darwin-x64@14.2.5':
+ resolution: {integrity: sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
- '@next/swc-linux-arm64-gnu@14.2.4':
- resolution: {integrity: sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==}
+ '@next/swc-linux-arm64-gnu@14.2.5':
+ resolution: {integrity: sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@next/swc-linux-arm64-musl@14.2.4':
- resolution: {integrity: sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==}
+ '@next/swc-linux-arm64-musl@14.2.5':
+ resolution: {integrity: sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@next/swc-linux-x64-gnu@14.2.4':
- resolution: {integrity: sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==}
+ '@next/swc-linux-x64-gnu@14.2.5':
+ resolution: {integrity: sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@next/swc-linux-x64-musl@14.2.4':
- resolution: {integrity: sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==}
+ '@next/swc-linux-x64-musl@14.2.5':
+ resolution: {integrity: sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@next/swc-win32-arm64-msvc@14.2.4':
- resolution: {integrity: sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==}
+ '@next/swc-win32-arm64-msvc@14.2.5':
+ resolution: {integrity: sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
- '@next/swc-win32-ia32-msvc@14.2.4':
- resolution: {integrity: sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==}
+ '@next/swc-win32-ia32-msvc@14.2.5':
+ resolution: {integrity: sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
- '@next/swc-win32-x64-msvc@14.2.4':
- resolution: {integrity: sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==}
+ '@next/swc-win32-x64-msvc@14.2.5':
+ resolution: {integrity: sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@@ -502,8 +504,8 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
- '@panva/hkdf@1.1.1':
- resolution: {integrity: sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==}
+ '@panva/hkdf@1.2.1':
+ resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==}
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
@@ -518,26 +520,29 @@ packages:
'@radix-ui/primitive@1.0.1':
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
- '@radix-ui/react-arrow@1.0.3':
- resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==}
+ '@radix-ui/primitive@1.1.0':
+ resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==}
+
+ '@radix-ui/react-arrow@1.1.0':
+ resolution: {integrity: sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
- '@radix-ui/react-aspect-ratio@1.0.3':
- resolution: {integrity: sha512-fXR5kbMan9oQqMuacfzlGG/SQMcmMlZ4wrvpckv8SgUulD0MMpspxJrxg/Gp/ISV3JfV1AeSWTYK9GvxA4ySwA==}
+ '@radix-ui/react-aspect-ratio@1.1.0':
+ resolution: {integrity: sha512-dP87DM/Y7jFlPgUZTlhx6FF5CEzOiaxp2rBCKlaXlpH5Ip/9Fg5zZ9lDOQ5o/MOfUlf36eak14zoWYpgcgGoOg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
@@ -553,6 +558,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-compose-refs@1.1.0':
+ resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-context@1.0.1':
resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==}
peerDependencies:
@@ -562,48 +576,57 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-dialog@1.0.5':
- resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==}
+ '@radix-ui/react-context@1.1.0':
+ resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/react-dialog@1.1.1':
+ resolution: {integrity: sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
- '@radix-ui/react-dismissable-layer@1.0.5':
- resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==}
+ '@radix-ui/react-dismissable-layer@1.1.0':
+ resolution: {integrity: sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
- '@radix-ui/react-focus-guards@1.0.1':
- resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
+ '@radix-ui/react-focus-guards@1.1.0':
+ resolution: {integrity: sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==}
peerDependencies:
'@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
- '@radix-ui/react-focus-scope@1.0.4':
- resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==}
+ '@radix-ui/react-focus-scope@1.1.0':
+ resolution: {integrity: sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
@@ -637,6 +660,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-id@1.1.0':
+ resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-label@2.0.2':
resolution: {integrity: sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==}
peerDependencies:
@@ -650,39 +682,39 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-popper@1.1.3':
- resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==}
+ '@radix-ui/react-popper@1.2.0':
+ resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
- '@radix-ui/react-portal@1.0.4':
- resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==}
+ '@radix-ui/react-portal@1.1.1':
+ resolution: {integrity: sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
- '@radix-ui/react-presence@1.0.1':
- resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==}
+ '@radix-ui/react-presence@1.1.0':
+ resolution: {integrity: sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
@@ -702,6 +734,19 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-primitive@2.0.0':
+ resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-slot@1.0.2':
resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
peerDependencies:
@@ -711,55 +756,64 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-switch@1.0.3':
- resolution: {integrity: sha512-mxm87F88HyHztsI7N+ZUmEoARGkC22YVW5CaC+Byc+HRpuvCrOBPTAnXgf+tZ/7i0Sg/eOePGdMhUKhPaQEqow==}
+ '@radix-ui/react-slot@1.1.0':
+ resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/react-switch@1.1.0':
+ resolution: {integrity: sha512-OBzy5WAj641k0AOSpKQtreDMe+isX0MQJ1IVyF03ucdF3DunOnROVrjWs8zsXUxC3zfZ6JL9HFVCUlMghz9dJw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
- '@radix-ui/react-tooltip@1.0.7':
- resolution: {integrity: sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==}
+ '@radix-ui/react-tooltip@1.1.2':
+ resolution: {integrity: sha512-9XRsLwe6Yb9B/tlnYCPVUd/TFS4J7HuOZW345DCeC6vKIxQGMZdx21RK4VoZauPD5frgkXTYVS5y90L+3YBn4w==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
- '@radix-ui/react-use-callback-ref@1.0.1':
- resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
+ '@radix-ui/react-use-callback-ref@1.1.0':
+ resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==}
peerDependencies:
'@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
- '@radix-ui/react-use-controllable-state@1.0.1':
- resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==}
+ '@radix-ui/react-use-controllable-state@1.1.0':
+ resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==}
peerDependencies:
'@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
- '@radix-ui/react-use-escape-keydown@1.0.3':
- resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==}
+ '@radix-ui/react-use-escape-keydown@1.1.0':
+ resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==}
peerDependencies:
'@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
@@ -773,48 +827,57 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-use-previous@1.0.1':
- resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==}
+ '@radix-ui/react-use-layout-effect@1.1.0':
+ resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==}
peerDependencies:
'@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
- '@radix-ui/react-use-rect@1.0.1':
- resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==}
+ '@radix-ui/react-use-previous@1.1.0':
+ resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==}
peerDependencies:
'@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
- '@radix-ui/react-use-size@1.0.1':
- resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==}
+ '@radix-ui/react-use-rect@1.1.0':
+ resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==}
peerDependencies:
'@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
- '@radix-ui/react-visually-hidden@1.0.3':
- resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==}
+ '@radix-ui/react-use-size@1.1.0':
+ resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/react-visually-hidden@1.1.0':
+ resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0
- react-dom: ^16.8 || ^17.0 || ^18.0
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
- '@radix-ui/rect@1.0.1':
- resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==}
+ '@radix-ui/rect@1.1.0':
+ resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
'@remirror/core-constants@2.0.2':
resolution: {integrity: sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ==}
@@ -833,162 +896,162 @@ packages:
'@swc/helpers@0.5.5':
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
- '@tiptap/core@2.4.0':
- resolution: {integrity: sha512-YJSahk8pkxpCs8SflCZfTnJpE7IPyUWIylfgXM2DefjRQa5DZ+c6sNY0s/zbxKYFQ6AuHVX40r9pCfcqHChGxQ==}
+ '@tiptap/core@2.5.4':
+ resolution: {integrity: sha512-Zs/hShr4+W02+0nOlpmr5cS2YjDRLqd+XMt+jsiQH0QNr3s1Lc82pfF6C3CjgLEZtdUzImZrW2ABtLlpvbogaA==}
peerDependencies:
- '@tiptap/pm': ^2.0.0
+ '@tiptap/pm': ^2.5.4
- '@tiptap/extension-blockquote@2.4.0':
- resolution: {integrity: sha512-nJJy4KsPgQqWTTDOWzFRdjCfG5+QExfZj44dulgDFNh+E66xhamnbM70PklllXJgEcge7xmT5oKM0gKls5XgFw==}
+ '@tiptap/extension-blockquote@2.5.4':
+ resolution: {integrity: sha512-UqeJunZM3IiCQGZE0X5YNUOWYkuIieqrwPgOEghAIjnhDcQizQcouRQ5R7cwwv/scNr2JvZHncOTLrALV3Janw==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-bold@2.4.0':
- resolution: {integrity: sha512-csnW6hMDEHoRfxcPRLSqeJn+j35Lgtt1YRiOwn7DlS66sAECGRuoGfCvQSPij0TCDp4VCR9if5Sf8EymhnQumQ==}
+ '@tiptap/extension-bold@2.5.4':
+ resolution: {integrity: sha512-H5sjqloFMjq7VOSfE+U4T7dqGoflOiF6RW6/gZm/U6KYeHG2/bG0ktq7mWAnnhbiKiy7gUcxyJCV+ILdGX9C5g==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-bubble-menu@2.4.0':
- resolution: {integrity: sha512-s99HmttUtpW3rScWq8rqk4+CGCwergNZbHLTkF6Rp6TSboMwfp+rwL5Q/JkcAG9KGLso1vGyXKbt1xHOvm8zMw==}
+ '@tiptap/extension-bubble-menu@2.5.4':
+ resolution: {integrity: sha512-GHwef912K1yd75pp9JGDnKSp1DvdOHH8BcHQv0no+a3q2ePFPYcgaSwVRR59jHRX9WzdVfoLcqDSAeoNGOrISw==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/pm': ^2.0.0
+ '@tiptap/core': ^2.5.4
+ '@tiptap/pm': ^2.5.4
- '@tiptap/extension-bullet-list@2.4.0':
- resolution: {integrity: sha512-9S5DLIvFRBoExvmZ+/ErpTvs4Wf1yOEs8WXlKYUCcZssK7brTFj99XDwpHFA29HKDwma5q9UHhr2OB2o0JYAdw==}
+ '@tiptap/extension-bullet-list@2.5.4':
+ resolution: {integrity: sha512-aAfpALeD6OxymkbtrzDqbgkAkzVVHudxOb8GsK1N6m42nFL7Q9JzHJ5/8KzB+xi25CcIbS+HmXJkRIQJXgNbSA==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-code-block-lowlight@2.4.0':
- resolution: {integrity: sha512-j0SdFq66A97Cn7bQOMqFYBaYsmOltZZ6o4uDZH6fdTvEFbfXTdtTYs2awsNSbW+w/DtivKZCvAX1FRLR3/g/5A==}
+ '@tiptap/extension-code-block-lowlight@2.5.4':
+ resolution: {integrity: sha512-K+bDt6CY2IxGANtmVK32uD8lRY/DqFGJwDKhearpFTR7yAn8q2MpWZjH15eOqZIgXGNf1fK6VK6wfczjecrV3A==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/extension-code-block': ^2.0.0
- '@tiptap/pm': ^2.0.0
+ '@tiptap/core': ^2.5.4
+ '@tiptap/extension-code-block': ^2.5.4
+ '@tiptap/pm': ^2.5.4
- '@tiptap/extension-code-block@2.4.0':
- resolution: {integrity: sha512-QWGdv1D56TBGbbJSj2cIiXGJEKguPiAl9ONzJ/Ql1ZksiQsYwx0YHriXX6TOC//T4VIf6NSClHEtwtxWBQ/Csg==}
+ '@tiptap/extension-code-block@2.5.4':
+ resolution: {integrity: sha512-lZRz44ACSL0IC4syWkNsNSe90sZuLig0yidfV9rs2muSCLoS3PRcCIJv4GjdBHouangxxBZqzIqWgPBqe6pqwA==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/pm': ^2.0.0
+ '@tiptap/core': ^2.5.4
+ '@tiptap/pm': ^2.5.4
- '@tiptap/extension-code@2.4.0':
- resolution: {integrity: sha512-wjhBukuiyJMq4cTcK3RBTzUPV24k5n1eEPlpmzku6ThwwkMdwynnMGMAmSF3fErh3AOyOUPoTTjgMYN2d10SJA==}
+ '@tiptap/extension-code@2.5.4':
+ resolution: {integrity: sha512-PCP0VcWR0Jsj3rum3czp1jateR+kv1iuB9E+TieGLN4vFqhoiUwSv2UAuhvD8x66MGCYLA3btgnmPov1w/iNmA==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-collaboration-cursor@2.4.0':
- resolution: {integrity: sha512-BTVy9FCTGdHxYieJ4lteVLrRY5qAPQyfunhMwakVf1NT3iU9quE6CaeaIwt6wEDJPMPPKzOHg1/ltSz9nIDe4A==}
+ '@tiptap/extension-collaboration-cursor@2.5.4':
+ resolution: {integrity: sha512-M32JChnP5RVdr1n+Tf0gF9bxx0gHvc0uV4SDxCMN3uaNH5YpcofmvKElS60rDGVfCdRTId/aj7P3AtwrvRlYdQ==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- y-prosemirror: ^1.2.5
+ '@tiptap/core': ^2.5.4
+ y-prosemirror: ^1.2.6
- '@tiptap/extension-collaboration@2.4.0':
- resolution: {integrity: sha512-achU+GU9tqxn3zsU61CbwWrCausf0U23MJIpo8vnywOIx6E955by6okHEHoUazLIGVFXVc5DBzBP7bf+Snzk0Q==}
+ '@tiptap/extension-collaboration@2.5.4':
+ resolution: {integrity: sha512-CpQdbr7XpQaVqRFo/A1DchrQZMDb8vrkP+FcUIgvHN0b8hwKDmXRAHDtuk8yTTEatW1EqpX8lx8UxaUTcDNbIg==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/pm': ^2.0.0
- y-prosemirror: ^1.2.5
+ '@tiptap/core': ^2.5.4
+ '@tiptap/pm': ^2.5.4
+ y-prosemirror: ^1.2.6
- '@tiptap/extension-document@2.4.0':
- resolution: {integrity: sha512-3jRodQJZDGbXlRPERaloS+IERg/VwzpC1IO6YSJR9jVIsBO6xC29P3cKTQlg1XO7p6ZH/0ksK73VC5BzzTwoHg==}
+ '@tiptap/extension-document@2.5.4':
+ resolution: {integrity: sha512-4RDrhASxCTOZETYhIhEW1TfZqx3Tm+LQxouvBMFyODmT1PSgsg5Xz1FYpDPr+J49bGAK0Pr9ae0XcGW011L3sA==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-dropcursor@2.4.0':
- resolution: {integrity: sha512-c46HoG2PEEpSZv5rmS5UX/lJ6/kP1iVO0Ax+6JrNfLEIiDULUoi20NqdjolEa38La2VhWvs+o20OviiTOKEE9g==}
+ '@tiptap/extension-dropcursor@2.5.4':
+ resolution: {integrity: sha512-jzSnuuYhlc0SsHvAteWkE9TJy3eRwkxQs4MO2JxALOzJECN4G82nlX8vciihBD6xf7lVgVSBACejK9+rsTHqCg==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/pm': ^2.0.0
+ '@tiptap/core': ^2.5.4
+ '@tiptap/pm': ^2.5.4
- '@tiptap/extension-floating-menu@2.4.0':
- resolution: {integrity: sha512-vLb9v+htbHhXyty0oaXjT3VC8St4xuGSHWUB9GuAJAQ+NajIO6rBPbLUmm9qM0Eh2zico5mpSD1Qtn5FM6xYzg==}
+ '@tiptap/extension-floating-menu@2.5.4':
+ resolution: {integrity: sha512-EqD4rgi3UhnDcV3H1+ndAS4Ue2zpsU7hFKoevOIV6GS7xVnWN70AGt6swH24QzuHKKISFtWoLpKjrwRORNIxuA==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/pm': ^2.0.0
+ '@tiptap/core': ^2.5.4
+ '@tiptap/pm': ^2.5.4
- '@tiptap/extension-gapcursor@2.4.0':
- resolution: {integrity: sha512-F4y/0J2lseohkFUw9P2OpKhrJ6dHz69ZScABUvcHxjznJLd6+0Zt7014Lw5PA8/m2d/w0fX8LZQ88pZr4quZPQ==}
+ '@tiptap/extension-gapcursor@2.5.4':
+ resolution: {integrity: sha512-wzTh1piODZBS0wmuDgPjjg8PQwclYa5LssnxDIo9pDSnt4l3AfHSAJIJSGIfgt96KnzF1wqRTRpe08qNa1n7/g==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/pm': ^2.0.0
+ '@tiptap/core': ^2.5.4
+ '@tiptap/pm': ^2.5.4
- '@tiptap/extension-hard-break@2.4.0':
- resolution: {integrity: sha512-3+Z6zxevtHza5IsDBZ4lZqvNR3Kvdqwxq/QKCKu9UhJN1DUjsg/l1Jn2NilSQ3NYkBYh2yJjT8CMo9pQIu776g==}
+ '@tiptap/extension-hard-break@2.5.4':
+ resolution: {integrity: sha512-nLn6HP9tqgdGGwbMORXVtcY30DTGctYFaWADRthvBjVgacYSeKlhUcsSu3YgaxtbxZp6BhfRvD2kKrxyQsSjnQ==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-heading@2.4.0':
- resolution: {integrity: sha512-fYkyP/VMo7YHO76YVrUjd95Qeo0cubWn/Spavmwm1gLTHH/q7xMtbod2Z/F0wd6QHnc7+HGhO7XAjjKWDjldaw==}
+ '@tiptap/extension-heading@2.5.4':
+ resolution: {integrity: sha512-DuAB58/e7eho1rkyad0Z/SjW+EB+H2hRqHlswEeZZYhBTjzey5UmBwkMWTGC/SQiRisx1xYQYTd8T0fiABi5hw==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-history@2.4.0':
- resolution: {integrity: sha512-gr5qsKAXEVGr1Lyk1598F7drTaEtAxqZiuuSwTCzZzkiwgEQsWMWTWc9F8FlneCEaqe1aIYg6WKWlmYPaFwr0w==}
+ '@tiptap/extension-history@2.5.4':
+ resolution: {integrity: sha512-WB1fZYGIlpahAD6Ba+mj9vIb1tk8S3TsADXDFKxLVpZWZPQ+B7duGJP7g/vRH2XAXEs836JzC2oxjKeaop3k7A==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/pm': ^2.0.0
+ '@tiptap/core': ^2.5.4
+ '@tiptap/pm': ^2.5.4
- '@tiptap/extension-horizontal-rule@2.4.0':
- resolution: {integrity: sha512-yDgxy+YxagcEsBbdWvbQiXYxsv3noS1VTuGwc9G7ZK9xPmBHJ5y0agOkB7HskwsZvJHoaSqNRsh7oZTkf0VR3g==}
+ '@tiptap/extension-horizontal-rule@2.5.4':
+ resolution: {integrity: sha512-uXLDe/iyzQbyfDkJ8kE5XaAkY3EOcbTFLjbueqGlkbWtjJgy+3LysGvh8fQj8PAOaIBMaFRFhTq7GMbW2ebRog==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/pm': ^2.0.0
+ '@tiptap/core': ^2.5.4
+ '@tiptap/pm': ^2.5.4
- '@tiptap/extension-italic@2.4.0':
- resolution: {integrity: sha512-aaW/L9q+KNHHK+X73MPloHeIsT191n3VLd3xm6uUcFDnUNvzYJ/q65/1ZicdtCaOLvTutxdrEvhbkrVREX6a8g==}
+ '@tiptap/extension-italic@2.5.4':
+ resolution: {integrity: sha512-TAhtl/fNBgv1elzF3HWES8uwVdpKBSYrq1e6yeYfj74mQn//3ksvdhWQrLzc1e+zcoHbk1PeOp/5ODdPuZ6tkg==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-list-item@2.4.0':
- resolution: {integrity: sha512-reUVUx+2cI2NIAqMZhlJ9uK/+zvRzm1GTmlU2Wvzwc7AwLN4yemj6mBDsmBLEXAKPvitfLh6EkeHaruOGymQtg==}
+ '@tiptap/extension-list-item@2.5.4':
+ resolution: {integrity: sha512-bPxUCFt9HnAfoaZQgwqCfRAZ6L3QlYhIRDDbOvZag7IxCdQuZmeY4k5OZfQIGijNDTag7CN9cdL4fl9rnm6/sQ==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-ordered-list@2.4.0':
- resolution: {integrity: sha512-Zo0c9M0aowv+2+jExZiAvhCB83GZMjZsxywmuOrdUbq5EGYKb7q8hDyN3hkrktVHr9UPXdPAYTmLAHztTOHYRA==}
+ '@tiptap/extension-ordered-list@2.5.4':
+ resolution: {integrity: sha512-cl3cTJitY6yDUmxqgjDUtDWCyX1VVsZNJ6i9yiPeARcxvzFc81KmUJxTGl8WPT5TjqmM+TleRkZjsxgvXX57+Q==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-paragraph@2.4.0':
- resolution: {integrity: sha512-+yse0Ow67IRwcACd9K/CzBcxlpr9OFnmf0x9uqpaWt1eHck1sJnti6jrw5DVVkyEBHDh/cnkkV49gvctT/NyCw==}
+ '@tiptap/extension-paragraph@2.5.4':
+ resolution: {integrity: sha512-pC1YIkkRPXoU0eDrhfAf8ZrFJQzvw2ftP6KRhLnnSw/Ot1DOjT1r95l7zsFefS9oCDMT/L4HghTAiPZ4rcpPbg==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-strike@2.4.0':
- resolution: {integrity: sha512-pE1uN/fQPOMS3i+zxPYMmPmI3keubnR6ivwM+KdXWOMnBiHl9N4cNpJgq1n2eUUGKLurC2qrQHpnVyGAwBS6Vg==}
+ '@tiptap/extension-strike@2.5.4':
+ resolution: {integrity: sha512-OSN6ePbCwEhi3hYZZOPow/P9Ym2Kv3NhVbUvasjZCiqQuk8TGc33xirPWl9DTjb/BLfL66TtJ2tKUEVOKl5dKg==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-text@2.4.0':
- resolution: {integrity: sha512-LV0bvE+VowE8IgLca7pM8ll7quNH+AgEHRbSrsI3SHKDCYB9gTHMjWaAkgkUVaO1u0IfCrjnCLym/PqFKa+vvg==}
+ '@tiptap/extension-text@2.5.4':
+ resolution: {integrity: sha512-+3x/hYqhmCYbvedCcQzQHFtZ5MAcMOlKuczomZtygf8AfDfuQVrG1m4GoJyNzJdqxjN80/xq4e2vDVvqQxYTCw==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/extension-youtube@2.4.0':
- resolution: {integrity: sha512-Ew6Oik9DaqP0xgQSUIWwozqeToJVOY4nqjRoKExGRuLdzgZeS+SmEA22ITBMcnZSJj8XBMgGBLcCWi+A7x1KAg==}
+ '@tiptap/extension-youtube@2.5.4':
+ resolution: {integrity: sha512-iHcvXOA32MZsVJTT7mvZ1CWKUo2quQMQXfBniizLm0lUG1ftSioqnDuXy4kEjeCBR2cnZr3yph6tbG/pF0RcHg==}
peerDependencies:
- '@tiptap/core': ^2.0.0
+ '@tiptap/core': ^2.5.4
- '@tiptap/html@2.4.0':
- resolution: {integrity: sha512-iM0sa6t0Hb5GTXnjdKvMDtD3KZgA4Mwx3QADeqfR10EjfPNlkh/BHU83oIhss/2JVRBXiUUDnNxW9cfpHX37/g==}
+ '@tiptap/html@2.5.4':
+ resolution: {integrity: sha512-Fcvsa7kkO+Id7WBFimDN5zdHksVGVnyHnffaN/PaAgbKmzP53BC38Pd0XuHS+KL6btqQIFE2GlqNYnyIos7i+g==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/pm': ^2.0.0
+ '@tiptap/core': ^2.5.4
+ '@tiptap/pm': ^2.5.4
- '@tiptap/pm@2.4.0':
- resolution: {integrity: sha512-B1HMEqGS4MzIVXnpgRZDLm30mxDWj51LkBT/if1XD+hj5gm8B9Q0c84bhvODX6KIs+c6z+zsY9VkVu8w9Yfgxg==}
+ '@tiptap/pm@2.5.4':
+ resolution: {integrity: sha512-oFIsuniptdUXn93x4aM2sVN3hYKo9Fj55zAkYrWhwxFYUYcPxd5ibra2we+wRK5TaiPu098wpC+yMSTZ/KKMpA==}
- '@tiptap/react@2.4.0':
- resolution: {integrity: sha512-baxnIr6Dy+5iGagOEIKFeHzdl1ZRa6Cg+SJ3GDL/BVLpO6KiCM3Mm5ymB726UKP1w7icrBiQD2fGY3Bx8KaiSA==}
+ '@tiptap/react@2.5.4':
+ resolution: {integrity: sha512-2HPHt2lEK6Z4jOV3HHVTee8hD4NS6eEj0zRZWSFjt1zDzXtFqX8VIv7qC1iDYsQgyiFnFnOucOQtAlDewBb23A==}
peerDependencies:
- '@tiptap/core': ^2.0.0
- '@tiptap/pm': ^2.0.0
+ '@tiptap/core': ^2.5.4
+ '@tiptap/pm': ^2.5.4
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
- '@tiptap/starter-kit@2.4.0':
- resolution: {integrity: sha512-DYYzMZdTEnRn9oZhKOeRCcB+TjhNz5icLlvJKoHoOGL9kCbuUyEf8WRR2OSPckI0+KUIPJL3oHRqO4SqSdTjfg==}
+ '@tiptap/starter-kit@2.5.4':
+ resolution: {integrity: sha512-IYnSETtBUSsy+Ece4kfVyzew+zyj7W9rP2Ronx0CbjeWQarfCAGxjuZ6uGLPB+tC5ZuMVt68Gyqb2y8GFes2Yw==}
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
@@ -1035,6 +1098,9 @@ packages:
'@types/unist@3.0.2':
resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
+ '@types/use-sync-external-store@0.0.6':
+ resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==}
+
'@types/uuid@9.0.8':
resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
@@ -1077,8 +1143,8 @@ packages:
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
- acorn@8.11.3:
- resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
+ acorn@8.12.1:
+ resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==}
engines: {node: '>=0.4.0'}
hasBin: true
@@ -1118,8 +1184,8 @@ packages:
resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==}
engines: {node: '>=10'}
- aria-query@5.3.0:
- resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+ aria-query@5.1.3:
+ resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==}
array-buffer-byte-length@1.0.1:
resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
@@ -1180,12 +1246,12 @@ packages:
react: '>= 16'
react-dom: '>= 16'
- axe-core@4.7.0:
- resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==}
+ axe-core@4.9.1:
+ resolution: {integrity: sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==}
engines: {node: '>=4'}
- axobject-query@3.2.1:
- resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
+ axobject-query@3.1.1:
+ resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -1207,8 +1273,8 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
- browserslist@4.23.1:
- resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==}
+ browserslist@4.23.2:
+ resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
@@ -1234,8 +1300,8 @@ packages:
camelize@1.0.1:
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
- caniuse-lite@1.0.30001632:
- resolution: {integrity: sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg==}
+ caniuse-lite@1.0.30001642:
+ resolution: {integrity: sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==}
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
@@ -1349,6 +1415,10 @@ packages:
supports-color:
optional: true
+ deep-equal@2.2.3:
+ resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==}
+ engines: {node: '>= 0.4'}
+
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -1399,8 +1469,8 @@ packages:
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
- electron-to-chromium@1.4.796:
- resolution: {integrity: sha512-NglN/xprcM+SHD2XCli4oC6bWe6kHoytcyLKCWXmRL854F0qhPhaYgUswUsglnPxYaNQIg2uMY4BvaomIf3kLA==}
+ electron-to-chromium@1.4.829:
+ resolution: {integrity: sha512-5qp1N2POAfW0u1qGAxXEtz6P7bO1m6gpZr5hdf5ve6lxpLM7MpiM4jIPz7xcrNlClQMafbyUDDWjlIQZ1Mw0Rw==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -1431,6 +1501,9 @@ packages:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
+ es-get-iterator@1.1.3:
+ resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==}
+
es-iterator-helpers@1.0.19:
resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==}
engines: {node: '>= 0.4'}
@@ -1458,8 +1531,8 @@ packages:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
- eslint-config-next@14.2.3:
- resolution: {integrity: sha512-ZkNztm3Q7hjqvB1rRlOX8P9E/cXRL9ajRcs8jufEtwMfTVYRqnmtnaSu57QqHyBlovMuiB8LEzfLBkh5RYV6Fg==}
+ eslint-config-next@14.2.5:
+ resolution: {integrity: sha512-zogs9zlOiZ7ka+wgUnmcM0KBEDjo4Jis7kxN1jvC0N4wynQ2MIx/KBkg4mVF63J5EK4W0QMCn7xO3vNisjaAoA==}
peerDependencies:
eslint: ^7.23.0 || ^8.0.0
typescript: '>=3.3.1'
@@ -1508,8 +1581,8 @@ packages:
'@typescript-eslint/parser':
optional: true
- eslint-plugin-jsx-a11y@6.8.0:
- resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==}
+ eslint-plugin-jsx-a11y@6.9.0:
+ resolution: {integrity: sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==}
engines: {node: '>=4.0'}
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
@@ -1520,8 +1593,8 @@ packages:
peerDependencies:
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
- eslint-plugin-react@7.34.2:
- resolution: {integrity: sha512-2HCmrU+/JNigDN6tg55cRDKCQWicYAPB38JGSFDQt95jDm8rrvSUo7YPkOIm5l6ts1j1zCvysNcasvfTMQzUOw==}
+ eslint-plugin-react@7.34.4:
+ resolution: {integrity: sha512-Np+jo9bUwJNxCsT12pXtrGhJgT3T44T1sHhn1Ssr42XFn8TES0267wPGo5nNrMHi8qkyimDAX2BUmkf9pSaVzA==}
engines: {node: '>=4'}
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
@@ -1557,8 +1630,8 @@ packages:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- esquery@1.5.0:
- resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+ esquery@1.6.0:
+ resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
engines: {node: '>=0.10'}
esrecurse@4.3.0:
@@ -1611,8 +1684,8 @@ packages:
for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
- foreground-child@3.1.1:
- resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
+ foreground-child@3.2.1:
+ resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==}
engines: {node: '>=14'}
formik@2.4.6:
@@ -1686,9 +1759,8 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
- glob@10.4.1:
- resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==}
- engines: {node: '>=16 || 14 >=14.18'}
+ glob@10.4.5:
+ resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
hasBin: true
glob@7.2.3:
@@ -1747,6 +1819,10 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
+ highlight.js@11.10.0:
+ resolution: {integrity: sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==}
+ engines: {node: '>=12.0.0'}
+
highlight.js@11.9.0:
resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==}
engines: {node: '>=12.0.0'}
@@ -1783,6 +1859,10 @@ packages:
invariant@2.2.4:
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
+ is-arguments@1.1.1:
+ resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
+ engines: {node: '>= 0.4'}
+
is-array-buffer@3.0.4:
resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
engines: {node: '>= 0.4'}
@@ -1809,8 +1889,9 @@ packages:
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
engines: {node: '>= 0.4'}
- is-core-module@2.13.1:
- resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
+ is-core-module@2.15.0:
+ resolution: {integrity: sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==}
+ engines: {node: '>= 0.4'}
is-data-view@1.0.1:
resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==}
@@ -1910,16 +1991,15 @@ packages:
resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
engines: {node: '>=14'}
- jackspeak@3.4.0:
- resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==}
- engines: {node: '>=14'}
+ jackspeak@3.4.3:
+ resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
- jiti@1.21.3:
- resolution: {integrity: sha512-uy2bNX5zQ+tESe+TiC7ilGRz8AtRGmnJH55NC5S0nSUjvvvM2hJHmefHErugGXN4pNv4Qx7vLsnNw9qJ9mtIsw==}
+ jiti@1.21.6:
+ resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
hasBin: true
- jose@4.15.5:
- resolution: {integrity: sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==}
+ jose@4.15.9:
+ resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==}
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -1945,8 +2025,8 @@ packages:
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
engines: {node: '>=4.0'}
- katex@0.16.10:
- resolution: {integrity: sha512-ZiqaC04tp2O5utMsl2TEZTXxa6WSC4yo0fv5ML++D3QZv/vx2Mct0mTlRx3O+uUkjfuAgOkzsCmq5MiUEsDDdA==}
+ katex@0.16.11:
+ resolution: {integrity: sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==}
hasBin: true
keyv@4.5.4:
@@ -2005,18 +2085,17 @@ packages:
lowlight@3.1.0:
resolution: {integrity: sha512-CEbNVoSikAxwDMDPjXlqlFYiZLkDJHwyGu/MfOsJnF3d7f3tds5J3z8s/l9TMXhzfsJCCJEAsD78842mwmg0PQ==}
- lru-cache@10.2.2:
- resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==}
- engines: {node: 14 || >=16.14}
+ lru-cache@10.4.3:
+ resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
- lucide-react@0.363.0:
- resolution: {integrity: sha512-AlsfPCsXQyQx7wwsIgzcKOL9LwC498LIMAo+c0Es5PkHJa33xwmYAkkSoKoJWWWSYQEStqu58/jT4tL2gi32uQ==}
+ lucide-react@0.408.0:
+ resolution: {integrity: sha512-8kETAAeWmOvtGIr7HPHm51DXoxlfkNncQ5FZWXR+abX8saQwMYXANWIkUstaYtcKSo/imOe/q+tVFA8ANzdSVA==}
peerDependencies:
- react: ^16.5.1 || ^17.0.0 || ^18.0.0
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
markdown-it@14.1.0:
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
@@ -2043,8 +2122,8 @@ packages:
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
engines: {node: '>=16 || 14 >=14.17'}
- minimatch@9.0.4:
- resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
+ minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
minimist@1.2.8:
@@ -2085,8 +2164,8 @@ packages:
nodemailer:
optional: true
- next@14.2.4:
- resolution: {integrity: sha512-R8/V7vugY+822rsQGQCjoLhMuC9oFj9SOi4Cl4b2wjDrseD0LRZ10W7R6Czo4w9ZznVSshKjuIomsRjvm9EKJQ==}
+ next@14.2.5:
+ resolution: {integrity: sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==}
engines: {node: '>=18.17.0'}
hasBin: true
peerDependencies:
@@ -2110,8 +2189,8 @@ packages:
react: '>= 16.0.0'
react-dom: '>= 16.0.0'
- node-releases@2.0.14:
- resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
+ node-releases@2.0.17:
+ resolution: {integrity: sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==}
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
@@ -2139,8 +2218,13 @@ packages:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
- object-inspect@1.13.1:
- resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
+ object-inspect@1.13.2:
+ resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==}
+ engines: {node: '>= 0.4'}
+
+ object-is@1.1.6:
+ resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==}
+ engines: {node: '>= 0.4'}
object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
@@ -2162,10 +2246,6 @@ packages:
resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==}
engines: {node: '>= 0.4'}
- object.hasown@1.1.4:
- resolution: {integrity: sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==}
- engines: {node: '>= 0.4'}
-
object.values@1.2.0:
resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==}
engines: {node: '>= 0.4'}
@@ -2195,6 +2275,9 @@ packages:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
+ package-json-from-dist@1.0.0:
+ resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==}
+
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@@ -2271,8 +2354,8 @@ packages:
peerDependencies:
postcss: ^8.2.14
- postcss-selector-parser@6.1.0:
- resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==}
+ postcss-selector-parser@6.1.1:
+ resolution: {integrity: sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==}
engines: {node: '>=4'}
postcss-value-parser@4.2.0:
@@ -2286,13 +2369,17 @@ packages:
resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
engines: {node: ^10 || ^12 || >=14}
+ postcss@8.4.39:
+ resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==}
+ engines: {node: ^10 || ^12 || >=14}
+
preact-render-to-string@5.2.6:
resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==}
peerDependencies:
preact: '>=10'
- preact@10.22.0:
- resolution: {integrity: sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw==}
+ preact@10.22.1:
+ resolution: {integrity: sha512-jRYbDDgMpIb5LHq3hkI0bbl+l/TQ9UnkdQ0ww+lp+4MMOdqaUYdFc5qeyP+IV8FAd/2Em7drVPeKdQxsiWCf/A==}
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
@@ -2319,8 +2406,8 @@ packages:
prosemirror-gapcursor@1.3.2:
resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==}
- prosemirror-history@1.4.0:
- resolution: {integrity: sha512-UUiGzDVcqo1lovOPdi9YxxUps3oBFWAIYkXLu3Ot+JPv1qzVogRbcizxK3LhHmtaUxclohgiOVesRw5QSlMnbQ==}
+ prosemirror-history@1.4.1:
+ resolution: {integrity: sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==}
prosemirror-inputrules@1.4.0:
resolution: {integrity: sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==}
@@ -2334,14 +2421,14 @@ packages:
prosemirror-menu@1.2.4:
resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==}
- prosemirror-model@1.21.1:
- resolution: {integrity: sha512-IVBAuMqOfltTr7yPypwpfdGT+6rGAteVOw2FO6GEvCGGa1ZwxLseqC1Eax/EChDvG/xGquB2d/hLdgh3THpsYg==}
+ prosemirror-model@1.22.1:
+ resolution: {integrity: sha512-gMrxal+F3higDFxCkBK5iQXckRVYvIu/3dopERJ6b20xfwZ9cbYvQvuldqaN+v/XytNPGyURYUpUU23kBRxWCQ==}
- prosemirror-schema-basic@1.2.2:
- resolution: {integrity: sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw==}
+ prosemirror-schema-basic@1.2.3:
+ resolution: {integrity: sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==}
- prosemirror-schema-list@1.4.0:
- resolution: {integrity: sha512-nZOIq/AkBSzCENxUyLm5ltWE53e2PLk65ghMN8qLQptOmDVixZlPqtMeQdiNw0odL9vNpalEjl3upgRkuJ/Jyw==}
+ prosemirror-schema-list@1.4.1:
+ resolution: {integrity: sha512-jbDyaP/6AFfDfu70VzySsD75Om2t3sXTOdl5+31Wlxlg62td1haUpty/ybajSfJ1pkGadlOfwQq9kgW5IMo1Rg==}
prosemirror-state@1.4.3:
resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==}
@@ -2349,18 +2436,18 @@ packages:
prosemirror-tables@1.3.7:
resolution: {integrity: sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA==}
- prosemirror-trailing-node@2.0.8:
- resolution: {integrity: sha512-ujRYhSuhQb1Jsarh1IHqb2KoSnRiD7wAMDGucP35DN7j5af6X7B18PfdPIrbwsPTqIAj0fyOvxbuPsWhNvylmA==}
+ prosemirror-trailing-node@2.0.9:
+ resolution: {integrity: sha512-YvyIn3/UaLFlFKrlJB6cObvUhmwFNZVhy1Q8OpW/avoTbD/Y7H5EcjK4AZFKhmuS6/N6WkGgt7gWtBWDnmFvHg==}
peerDependencies:
- prosemirror-model: ^1.19.0
+ prosemirror-model: ^1.22.1
prosemirror-state: ^1.4.2
- prosemirror-view: ^1.31.2
+ prosemirror-view: ^1.33.8
prosemirror-transform@1.9.0:
resolution: {integrity: sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg==}
- prosemirror-view@1.33.7:
- resolution: {integrity: sha512-jo6eMQCtPRwcrA2jISBCnm0Dd2B+szS08BU1Ay+XGiozHo5EZMHfLQE8R5nO4vb1spTH2RW1woZIYXRiQsuP8g==}
+ prosemirror-view@1.33.8:
+ resolution: {integrity: sha512-4PhMr/ufz2cdvFgpUAnZfs+0xij3RsFysreeG9V/utpwX7AJtYCDVyuRxzWoMJIEf4C7wVihuBNMPpFLPCiLQw==}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
@@ -2449,8 +2536,8 @@ packages:
'@types/react':
optional: true
- react-remove-scroll@2.5.5:
- resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==}
+ react-remove-scroll@2.5.7:
+ resolution: {integrity: sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==}
engines: {node: '>=10'}
peerDependencies:
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -2558,8 +2645,8 @@ packages:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
- semver@7.6.2:
- resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
+ semver@7.6.3:
+ resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
engines: {node: '>=10'}
hasBin: true
@@ -2611,6 +2698,10 @@ packages:
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
engines: {node: '>=0.10.0'}
+ stop-iteration-iterator@1.0.0:
+ resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==}
+ engines: {node: '>= 0.4'}
+
streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
@@ -2623,10 +2714,16 @@ packages:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
+ string.prototype.includes@2.0.0:
+ resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==}
+
string.prototype.matchall@4.0.11:
resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==}
engines: {node: '>= 0.4'}
+ string.prototype.repeat@1.0.0:
+ resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==}
+
string.prototype.trim@1.2.9:
resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
engines: {node: '>= 0.4'}
@@ -2657,8 +2754,8 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
- styled-components@6.1.11:
- resolution: {integrity: sha512-Ui0jXPzbp1phYij90h12ksljKGqF8ncGx+pjrNPsSPhbUUjWT2tD1FwGo2LF6USCnbrsIhNngDfodhxbegfEOA==}
+ styled-components@6.1.12:
+ resolution: {integrity: sha512-n/O4PzRPhbYI0k1vKKayfti3C/IGcPf+DqcrOB7O/ab9x4u/zjqraneT5N45+sIe87cxrCApXM8Bna7NYxwoTA==}
engines: {node: '>= 16'}
peerDependencies:
react: '>= 16.8.0'
@@ -2698,8 +2795,8 @@ packages:
peerDependencies:
react: ^16.11.0 || ^17.0.0 || ^18.0.0
- tailwind-merge@2.3.0:
- resolution: {integrity: sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==}
+ tailwind-merge@2.4.0:
+ resolution: {integrity: sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==}
tailwind-scrollbar@3.1.0:
resolution: {integrity: sha512-pmrtDIZeHyu2idTejfV59SbaJyvp1VRjYxAjZBH0jnyrPRo6HL1kD5Glz8VPagasqr6oAx6M05+Tuw429Z8jxg==}
@@ -2707,8 +2804,8 @@ packages:
peerDependencies:
tailwindcss: 3.x
- tailwindcss@3.4.4:
- resolution: {integrity: sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==}
+ tailwindcss@3.4.6:
+ resolution: {integrity: sha512-1uRHzPB+Vzu57ocybfZ4jh5Q3SdlH7XW23J5sQoM9LhE9eIOlzxer/3XPSsycvih3rboRsvt0QCmzSrqyOYUIA==}
engines: {node: '>=14.0.0'}
hasBin: true
@@ -2798,8 +2895,8 @@ packages:
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
- update-browserslist-db@1.0.16:
- resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==}
+ update-browserslist-db@1.1.0:
+ resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
@@ -2886,8 +2983,8 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- ws@8.17.0:
- resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==}
+ ws@8.18.0:
+ resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@@ -2904,8 +3001,8 @@ packages:
peerDependencies:
yjs: ^13.0.0
- y-prosemirror@1.2.8:
- resolution: {integrity: sha512-xNDOEe9ViBXck0qwcTvzGgj832ecoz8GQSppoh6PwUokbXoEBDbAH76Qs15HOiatjZkSODHRGdpYlLBBkJPiGA==}
+ y-prosemirror@1.2.9:
+ resolution: {integrity: sha512-fThGIVmSqrqnG/ckywEGlHM9ElfILC4TcMZd5zxWPe/i+UuP97TEr4swsopRKG3Y+KHBVt4Y/5NVBC3AAsUoUg==}
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
peerDependencies:
prosemirror-model: ^1.7.1
@@ -2935,8 +3032,8 @@ packages:
engines: {node: '>= 14'}
hasBin: true
- yjs@13.6.16:
- resolution: {integrity: sha512-uEq+n/dFIecBElEdeQea8nDnltScBfuhCSyAxDw4CosveP9Ag0eW6iZi2mdpW7EgxSFT7VXK2MJl3tKaLTmhAQ==}
+ yjs@13.6.18:
+ resolution: {integrity: sha512-GBTjO4QCmv2HFKFkYIJl7U77hIB1o22vSCSQD1Ge8ZxWbIbn8AltI4gyXbtL+g5/GJep67HCMq3Y5AmNwDSyEg==}
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
yocto-queue@0.1.0:
@@ -2954,7 +3051,7 @@ snapshots:
'@alloc/quick-lru@5.2.0': {}
- '@babel/runtime@7.24.7':
+ '@babel/runtime@7.24.8':
dependencies:
regenerator-runtime: 0.14.1
@@ -2984,7 +3081,7 @@ snapshots:
eslint: 8.57.0
eslint-visitor-keys: 3.4.3
- '@eslint-community/regexpp@4.10.1': {}
+ '@eslint-community/regexpp@4.11.0': {}
'@eslint/eslintrc@2.1.4':
dependencies:
@@ -3002,35 +3099,35 @@ snapshots:
'@eslint/js@8.57.0': {}
- '@floating-ui/core@1.6.2':
+ '@floating-ui/core@1.6.4':
dependencies:
- '@floating-ui/utils': 0.2.2
+ '@floating-ui/utils': 0.2.4
- '@floating-ui/dom@1.6.5':
+ '@floating-ui/dom@1.6.7':
dependencies:
- '@floating-ui/core': 1.6.2
- '@floating-ui/utils': 0.2.2
+ '@floating-ui/core': 1.6.4
+ '@floating-ui/utils': 0.2.4
- '@floating-ui/react-dom@2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@floating-ui/react-dom@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@floating-ui/dom': 1.6.5
+ '@floating-ui/dom': 1.6.7
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- '@floating-ui/utils@0.2.2': {}
+ '@floating-ui/utils@0.2.4': {}
- '@hocuspocus/common@2.13.1':
+ '@hocuspocus/common@2.13.5':
dependencies:
lib0: 0.2.94
- '@hocuspocus/provider@2.13.1(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)':
+ '@hocuspocus/provider@2.13.5(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)':
dependencies:
- '@hocuspocus/common': 2.13.1
+ '@hocuspocus/common': 2.13.5
'@lifeomic/attempt': 3.1.0
lib0: 0.2.94
- ws: 8.17.0
- y-protocols: 1.0.6(yjs@13.6.16)
- yjs: 13.6.16
+ ws: 8.18.0
+ y-protocols: 1.0.6(yjs@13.6.18)
+ yjs: 13.6.18
transitivePeerDependencies:
- bufferutil
- utf-8-validate
@@ -3134,53 +3231,53 @@ snapshots:
'@jridgewell/gen-mapping@0.3.5':
dependencies:
'@jridgewell/set-array': 1.2.1
- '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping': 0.3.25
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/set-array@1.2.1': {}
- '@jridgewell/sourcemap-codec@1.4.15': {}
+ '@jridgewell/sourcemap-codec@1.5.0': {}
'@jridgewell/trace-mapping@0.3.25':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/sourcemap-codec': 1.5.0
'@lifeomic/attempt@3.1.0': {}
- '@next/env@14.2.4': {}
+ '@next/env@14.2.5': {}
- '@next/eslint-plugin-next@14.2.3':
+ '@next/eslint-plugin-next@14.2.5':
dependencies:
glob: 10.3.10
- '@next/swc-darwin-arm64@14.2.4':
+ '@next/swc-darwin-arm64@14.2.5':
optional: true
- '@next/swc-darwin-x64@14.2.4':
+ '@next/swc-darwin-x64@14.2.5':
optional: true
- '@next/swc-linux-arm64-gnu@14.2.4':
+ '@next/swc-linux-arm64-gnu@14.2.5':
optional: true
- '@next/swc-linux-arm64-musl@14.2.4':
+ '@next/swc-linux-arm64-musl@14.2.5':
optional: true
- '@next/swc-linux-x64-gnu@14.2.4':
+ '@next/swc-linux-x64-gnu@14.2.5':
optional: true
- '@next/swc-linux-x64-musl@14.2.4':
+ '@next/swc-linux-x64-musl@14.2.5':
optional: true
- '@next/swc-win32-arm64-msvc@14.2.4':
+ '@next/swc-win32-arm64-msvc@14.2.5':
optional: true
- '@next/swc-win32-ia32-msvc@14.2.4':
+ '@next/swc-win32-ia32-msvc@14.2.5':
optional: true
- '@next/swc-win32-x64-msvc@14.2.4':
+ '@next/swc-win32-x64-msvc@14.2.5':
optional: true
'@nodelib/fs.scandir@2.1.5':
@@ -3195,7 +3292,7 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
- '@panva/hkdf@1.1.1': {}
+ '@panva/hkdf@1.2.1': {}
'@pkgjs/parseargs@0.11.0':
optional: true
@@ -3206,22 +3303,22 @@ snapshots:
'@radix-ui/primitive@1.0.1':
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
- '@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/primitive@1.1.0': {}
+
+ '@radix-ui/react-arrow@1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.74
'@types/react-dom': 18.2.23
- '@radix-ui/react-aspect-ratio@1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-aspect-ratio@1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
@@ -3230,68 +3327,76 @@ snapshots:
'@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.2.74
+
+ '@radix-ui/react-compose-refs@1.1.0(@types/react@18.2.74)(react@18.3.1)':
+ dependencies:
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
'@radix-ui/react-context@1.0.1(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
- '@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-context@1.1.0(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/primitive': 1.0.1
- '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-context': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-id': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-slot': 1.0.2(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.74)(react@18.3.1)
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.2.74
+
+ '@radix-ui/react-dialog@1.1.1(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.0
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-slot': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.74)(react@18.3.1)
aria-hidden: 1.2.4
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- react-remove-scroll: 2.5.5(@types/react@18.2.74)(react@18.3.1)
+ react-remove-scroll: 2.5.7(@types/react@18.2.74)(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.74
'@types/react-dom': 18.2.23
- '@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/primitive': 1.0.1
- '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/primitive': 1.1.0
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.74
'@types/react-dom': 18.2.23
- '@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.74)(react@18.3.1)':
+ '@radix-ui/react-focus-guards@1.1.0(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
- '@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
@@ -3300,7 +3405,7 @@ snapshots:
'@radix-ui/react-form@0.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
'@radix-ui/react-context': 1.0.1(@types/react@18.2.74)(react@18.3.1)
@@ -3319,15 +3424,22 @@ snapshots:
'@radix-ui/react-id@1.0.1(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
+ '@radix-ui/react-id@1.1.0(@types/react@18.2.74)(react@18.3.1)':
+ dependencies:
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.2.74
+
'@radix-ui/react-label@2.0.2(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
@@ -3335,40 +3447,38 @@ snapshots:
'@types/react': 18.2.74
'@types/react-dom': 18.2.23
- '@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-popper@1.2.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@floating-ui/react-dom': 2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-context': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/rect': 1.0.1
+ '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-arrow': 1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-rect': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-size': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/rect': 1.1.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.74
'@types/react-dom': 18.2.23
- '@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-portal@1.1.1(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.74
'@types/react-dom': 18.2.23
- '@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-presence@1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
@@ -3377,7 +3487,7 @@ snapshots:
'@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
@@ -3385,117 +3495,128 @@ snapshots:
'@types/react': 18.2.74
'@types/react-dom': 18.2.23
+ '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/react-slot': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.2.74
+ '@types/react-dom': 18.2.23
+
'@radix-ui/react-slot@1.0.2(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
- '@radix-ui/react-switch@1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-slot@1.1.0(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/primitive': 1.0.1
- '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-context': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.2.74
+
+ '@radix-ui/react-switch@1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.0
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-previous': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-size': 1.1.0(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.74
'@types/react-dom': 18.2.23
- '@radix-ui/react-tooltip@1.0.7(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-tooltip@1.1.2(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/primitive': 1.0.1
- '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-context': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-id': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-slot': 1.0.2(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.74)(react@18.3.1)
- '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/primitive': 1.1.0
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-slot': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.74
'@types/react-dom': 18.2.23
- '@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.74)(react@18.3.1)':
+ '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
- '@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.74)(react@18.3.1)':
+ '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
- '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.74)(react@18.3.1)':
+ '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
'@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
- '@radix-ui/react-use-previous@1.0.1(@types/react@18.2.74)(react@18.3.1)':
+ '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
- '@radix-ui/react-use-rect@1.0.1(@types/react@18.2.74)(react@18.3.1)':
+ '@radix-ui/react-use-previous@1.1.0(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/rect': 1.0.1
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
- '@radix-ui/react-use-size@1.0.1(@types/react@18.2.74)(react@18.3.1)':
+ '@radix-ui/react-use-rect@1.1.0(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.74)(react@18.3.1)
+ '@radix-ui/rect': 1.1.0
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
- '@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-use-size@1.1.0(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.7
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.74)(react@18.3.1)
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.2.74
+
+ '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.74
'@types/react-dom': 18.2.23
- '@radix-ui/rect@1.0.1':
- dependencies:
- '@babel/runtime': 7.24.7
+ '@radix-ui/rect@1.1.0': {}
'@remirror/core-constants@2.0.2': {}
@@ -3512,177 +3633,179 @@ snapshots:
'@swc/counter': 0.1.3
tslib: 2.6.3
- '@tiptap/core@2.4.0(@tiptap/pm@2.4.0)':
+ '@tiptap/core@2.5.4(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/pm': 2.4.0
+ '@tiptap/pm': 2.5.4
- '@tiptap/extension-blockquote@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-blockquote@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-bold@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-bold@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-bubble-menu@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)':
+ '@tiptap/extension-bubble-menu@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
tippy.js: 6.3.7
- '@tiptap/extension-bullet-list@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-bullet-list@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-code-block-lowlight@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/extension-code-block@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)':
+ '@tiptap/extension-code-block-lowlight@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/extension-code-block@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/extension-code-block': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/extension-code-block': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
- '@tiptap/extension-code-block@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)':
+ '@tiptap/extension-code-block@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
- '@tiptap/extension-code@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-code@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-collaboration-cursor@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(y-prosemirror@1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))':
+ '@tiptap/extension-collaboration-cursor@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(y-prosemirror@1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- y-prosemirror: 1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ y-prosemirror: 1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
- '@tiptap/extension-collaboration@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)(y-prosemirror@1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))':
+ '@tiptap/extension-collaboration@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)(y-prosemirror@1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
- y-prosemirror: 1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
+ y-prosemirror: 1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
- '@tiptap/extension-document@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-document@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-dropcursor@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)':
+ '@tiptap/extension-dropcursor@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
- '@tiptap/extension-floating-menu@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)':
+ '@tiptap/extension-floating-menu@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
tippy.js: 6.3.7
- '@tiptap/extension-gapcursor@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)':
+ '@tiptap/extension-gapcursor@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
- '@tiptap/extension-hard-break@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-hard-break@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-heading@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-heading@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-history@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)':
+ '@tiptap/extension-history@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
- '@tiptap/extension-horizontal-rule@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)':
+ '@tiptap/extension-horizontal-rule@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
- '@tiptap/extension-italic@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-italic@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-list-item@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-list-item@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-ordered-list@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-ordered-list@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-paragraph@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-paragraph@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-strike@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-strike@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-text@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-text@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-youtube@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
+ '@tiptap/extension-youtube@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/html@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)':
+ '@tiptap/html@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
zeed-dom: 0.10.11
- '@tiptap/pm@2.4.0':
+ '@tiptap/pm@2.5.4':
dependencies:
prosemirror-changeset: 2.2.1
prosemirror-collab: 1.3.1
prosemirror-commands: 1.5.2
prosemirror-dropcursor: 1.8.1
prosemirror-gapcursor: 1.3.2
- prosemirror-history: 1.4.0
+ prosemirror-history: 1.4.1
prosemirror-inputrules: 1.4.0
prosemirror-keymap: 1.2.2
prosemirror-markdown: 1.13.0
prosemirror-menu: 1.2.4
- prosemirror-model: 1.21.1
- prosemirror-schema-basic: 1.2.2
- prosemirror-schema-list: 1.4.0
+ prosemirror-model: 1.22.1
+ prosemirror-schema-basic: 1.2.3
+ prosemirror-schema-list: 1.4.1
prosemirror-state: 1.4.3
prosemirror-tables: 1.3.7
- prosemirror-trailing-node: 2.0.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)
+ prosemirror-trailing-node: 2.0.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)
prosemirror-transform: 1.9.0
- prosemirror-view: 1.33.7
+ prosemirror-view: 1.33.8
- '@tiptap/react@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@tiptap/react@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/extension-bubble-menu': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
- '@tiptap/extension-floating-menu': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
- '@tiptap/pm': 2.4.0
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/extension-bubble-menu': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
+ '@tiptap/extension-floating-menu': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
+ '@tiptap/pm': 2.5.4
+ '@types/use-sync-external-store': 0.0.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
+ use-sync-external-store: 1.2.2(react@18.3.1)
- '@tiptap/starter-kit@2.4.0(@tiptap/pm@2.4.0)':
+ '@tiptap/starter-kit@2.5.4(@tiptap/pm@2.5.4)':
dependencies:
- '@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/extension-blockquote': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-bold': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-bullet-list': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-code': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-code-block': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
- '@tiptap/extension-document': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-dropcursor': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
- '@tiptap/extension-gapcursor': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
- '@tiptap/extension-hard-break': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-heading': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-history': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
- '@tiptap/extension-horizontal-rule': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
- '@tiptap/extension-italic': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-list-item': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-ordered-list': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-paragraph': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-strike': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
- '@tiptap/extension-text': 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
+ '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/extension-blockquote': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-bold': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-bullet-list': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-code': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-code-block': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
+ '@tiptap/extension-document': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-dropcursor': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
+ '@tiptap/extension-gapcursor': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
+ '@tiptap/extension-hard-break': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-heading': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-history': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
+ '@tiptap/extension-horizontal-rule': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
+ '@tiptap/extension-italic': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-list-item': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-ordered-list': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-paragraph': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-strike': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/extension-text': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
transitivePeerDependencies:
- '@tiptap/pm'
@@ -3743,6 +3866,8 @@ snapshots:
'@types/unist@3.0.2': {}
+ '@types/use-sync-external-store@0.0.6': {}
+
'@types/uuid@9.0.8': {}
'@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4)':
@@ -3773,7 +3898,7 @@ snapshots:
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.3
- semver: 7.6.2
+ semver: 7.6.3
ts-api-utils: 1.3.0(typescript@5.4.4)
optionalDependencies:
typescript: 5.4.4
@@ -3787,11 +3912,11 @@ snapshots:
'@ungap/structured-clone@1.2.0': {}
- acorn-jsx@5.3.2(acorn@8.11.3):
+ acorn-jsx@5.3.2(acorn@8.12.1):
dependencies:
- acorn: 8.11.3
+ acorn: 8.12.1
- acorn@8.11.3: {}
+ acorn@8.12.1: {}
ajv@6.12.6:
dependencies:
@@ -3825,9 +3950,9 @@ snapshots:
dependencies:
tslib: 2.6.3
- aria-query@5.3.0:
+ aria-query@5.1.3:
dependencies:
- dequal: 2.0.3
+ deep-equal: 2.2.3
array-buffer-byte-length@1.0.1:
dependencies:
@@ -3905,14 +4030,14 @@ snapshots:
ast-types-flow@0.0.8: {}
- autoprefixer@10.4.19(postcss@8.4.38):
+ autoprefixer@10.4.19(postcss@8.4.39):
dependencies:
- browserslist: 4.23.1
- caniuse-lite: 1.0.30001632
+ browserslist: 4.23.2
+ caniuse-lite: 1.0.30001642
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.0.1
- postcss: 8.4.38
+ postcss: 8.4.39
postcss-value-parser: 4.2.0
available-typed-arrays@1.0.7:
@@ -3927,11 +4052,11 @@ snapshots:
transitivePeerDependencies:
- csstype
- axe-core@4.7.0: {}
+ axe-core@4.9.1: {}
- axobject-query@3.2.1:
+ axobject-query@3.1.1:
dependencies:
- dequal: 2.0.3
+ deep-equal: 2.2.3
balanced-match@1.0.2: {}
@@ -3952,12 +4077,12 @@ snapshots:
dependencies:
fill-range: 7.1.1
- browserslist@4.23.1:
+ browserslist@4.23.2:
dependencies:
- caniuse-lite: 1.0.30001632
- electron-to-chromium: 1.4.796
- node-releases: 2.0.14
- update-browserslist-db: 1.0.16(browserslist@4.23.1)
+ caniuse-lite: 1.0.30001642
+ electron-to-chromium: 1.4.829
+ node-releases: 2.0.17
+ update-browserslist-db: 1.1.0(browserslist@4.23.2)
buffer@6.0.3:
dependencies:
@@ -3982,7 +4107,7 @@ snapshots:
camelize@1.0.1: {}
- caniuse-lite@1.0.30001632: {}
+ caniuse-lite@1.0.30001642: {}
chalk@4.1.2:
dependencies:
@@ -4087,6 +4212,27 @@ snapshots:
dependencies:
ms: 2.1.2
+ deep-equal@2.2.3:
+ dependencies:
+ array-buffer-byte-length: 1.0.1
+ call-bind: 1.0.7
+ es-get-iterator: 1.1.3
+ get-intrinsic: 1.2.4
+ is-arguments: 1.1.1
+ is-array-buffer: 3.0.4
+ is-date-object: 1.0.5
+ is-regex: 1.1.4
+ is-shared-array-buffer: 1.0.3
+ isarray: 2.0.5
+ object-is: 1.1.6
+ object-keys: 1.1.1
+ object.assign: 4.1.5
+ regexp.prototype.flags: 1.5.2
+ side-channel: 1.0.6
+ which-boxed-primitive: 1.0.2
+ which-collection: 1.0.2
+ which-typed-array: 1.1.15
+
deep-is@0.1.4: {}
deepmerge@2.2.1: {}
@@ -4131,7 +4277,7 @@ snapshots:
eastasianwidth@0.2.0: {}
- electron-to-chromium@1.4.796: {}
+ electron-to-chromium@1.4.829: {}
emoji-regex@8.0.0: {}
@@ -4179,7 +4325,7 @@ snapshots:
is-string: 1.0.7
is-typed-array: 1.1.13
is-weakref: 1.0.2
- object-inspect: 1.13.1
+ object-inspect: 1.13.2
object-keys: 1.1.1
object.assign: 4.1.5
regexp.prototype.flags: 1.5.2
@@ -4201,6 +4347,18 @@ snapshots:
es-errors@1.3.0: {}
+ es-get-iterator@1.1.3:
+ dependencies:
+ call-bind: 1.0.7
+ get-intrinsic: 1.2.4
+ has-symbols: 1.0.3
+ is-arguments: 1.1.1
+ is-map: 2.0.3
+ is-set: 2.0.3
+ is-string: 1.0.7
+ isarray: 2.0.5
+ stop-iteration-iterator: 1.0.0
+
es-iterator-helpers@1.0.19:
dependencies:
call-bind: 1.0.7
@@ -4242,17 +4400,17 @@ snapshots:
escape-string-regexp@4.0.0: {}
- eslint-config-next@14.2.3(eslint@8.57.0)(typescript@5.4.4):
+ eslint-config-next@14.2.5(eslint@8.57.0)(typescript@5.4.4):
dependencies:
- '@next/eslint-plugin-next': 14.2.3
+ '@next/eslint-plugin-next': 14.2.5
'@rushstack/eslint-patch': 1.10.3
'@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.4)
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
- eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
- eslint-plugin-react: 7.34.2(eslint@8.57.0)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+ eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0)
+ eslint-plugin-react: 7.34.4(eslint@8.57.0)
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0)
optionalDependencies:
typescript: 5.4.4
@@ -4263,7 +4421,7 @@ snapshots:
eslint-import-resolver-node@0.3.9:
dependencies:
debug: 3.2.7
- is-core-module: 2.13.1
+ is-core-module: 2.15.0
resolve: 1.22.8
transitivePeerDependencies:
- supports-color
@@ -4274,10 +4432,10 @@ snapshots:
enhanced-resolve: 5.17.0
eslint: 8.57.0
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.5
- is-core-module: 2.13.1
+ is-core-module: 2.15.0
is-glob: 4.0.3
transitivePeerDependencies:
- '@typescript-eslint/parser'
@@ -4296,7 +4454,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0):
+ eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
dependencies:
array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5
@@ -4308,7 +4466,7 @@ snapshots:
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
hasown: 2.0.2
- is-core-module: 2.13.1
+ is-core-module: 2.15.0
is-glob: 4.0.3
minimatch: 3.1.2
object.fromentries: 2.0.8
@@ -4323,15 +4481,14 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
- eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0):
+ eslint-plugin-jsx-a11y@6.9.0(eslint@8.57.0):
dependencies:
- '@babel/runtime': 7.24.7
- aria-query: 5.3.0
+ aria-query: 5.1.3
array-includes: 3.1.8
array.prototype.flatmap: 1.3.2
ast-types-flow: 0.0.8
- axe-core: 4.7.0
- axobject-query: 3.2.1
+ axe-core: 4.9.1
+ axobject-query: 3.1.1
damerau-levenshtein: 1.0.8
emoji-regex: 9.2.2
es-iterator-helpers: 1.0.19
@@ -4340,14 +4497,15 @@ snapshots:
jsx-ast-utils: 3.3.5
language-tags: 1.0.9
minimatch: 3.1.2
- object.entries: 1.1.8
object.fromentries: 2.0.8
+ safe-regex-test: 1.0.3
+ string.prototype.includes: 2.0.0
eslint-plugin-react-hooks@4.6.2(eslint@8.57.0):
dependencies:
eslint: 8.57.0
- eslint-plugin-react@7.34.2(eslint@8.57.0):
+ eslint-plugin-react@7.34.4(eslint@8.57.0):
dependencies:
array-includes: 3.1.8
array.prototype.findlast: 1.2.5
@@ -4358,16 +4516,17 @@ snapshots:
es-iterator-helpers: 1.0.19
eslint: 8.57.0
estraverse: 5.3.0
+ hasown: 2.0.2
jsx-ast-utils: 3.3.5
minimatch: 3.1.2
object.entries: 1.1.8
object.fromentries: 2.0.8
- object.hasown: 1.1.4
object.values: 1.2.0
prop-types: 15.8.1
resolve: 2.0.0-next.5
semver: 6.3.1
string.prototype.matchall: 4.0.11
+ string.prototype.repeat: 1.0.0
eslint-plugin-unused-imports@3.2.0(eslint@8.57.0):
dependencies:
@@ -4386,7 +4545,7 @@ snapshots:
eslint@8.57.0:
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
- '@eslint-community/regexpp': 4.10.1
+ '@eslint-community/regexpp': 4.11.0
'@eslint/eslintrc': 2.1.4
'@eslint/js': 8.57.0
'@humanwhocodes/config-array': 0.11.14
@@ -4402,7 +4561,7 @@ snapshots:
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3
espree: 9.6.1
- esquery: 1.5.0
+ esquery: 1.6.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 6.0.1
@@ -4428,11 +4587,11 @@ snapshots:
espree@9.6.1:
dependencies:
- acorn: 8.11.3
- acorn-jsx: 5.3.2(acorn@8.11.3)
+ acorn: 8.12.1
+ acorn-jsx: 5.3.2(acorn@8.12.1)
eslint-visitor-keys: 3.4.3
- esquery@1.5.0:
+ esquery@1.6.0:
dependencies:
estraverse: 5.3.0
@@ -4487,7 +4646,7 @@ snapshots:
dependencies:
is-callable: 1.2.7
- foreground-child@3.1.1:
+ foreground-child@3.2.1:
dependencies:
cross-spawn: 7.0.3
signal-exit: 4.1.0
@@ -4564,18 +4723,19 @@ snapshots:
glob@10.3.10:
dependencies:
- foreground-child: 3.1.1
+ foreground-child: 3.2.1
jackspeak: 2.3.6
- minimatch: 9.0.4
+ minimatch: 9.0.5
minipass: 7.1.2
path-scurry: 1.11.1
- glob@10.4.1:
+ glob@10.4.5:
dependencies:
- foreground-child: 3.1.1
- jackspeak: 3.4.0
- minimatch: 9.0.4
+ foreground-child: 3.2.1
+ jackspeak: 3.4.3
+ minimatch: 9.0.5
minipass: 7.1.2
+ package-json-from-dist: 1.0.0
path-scurry: 1.11.1
glob@7.2.3:
@@ -4637,6 +4797,8 @@ snapshots:
dependencies:
function-bind: 1.1.2
+ highlight.js@11.10.0: {}
+
highlight.js@11.9.0: {}
hoist-non-react-statics@3.3.2:
@@ -4671,6 +4833,11 @@ snapshots:
dependencies:
loose-envify: 1.4.0
+ is-arguments@1.1.1:
+ dependencies:
+ call-bind: 1.0.7
+ has-tostringtag: 1.0.2
+
is-array-buffer@3.0.4:
dependencies:
call-bind: 1.0.7
@@ -4697,7 +4864,7 @@ snapshots:
is-callable@1.2.7: {}
- is-core-module@2.13.1:
+ is-core-module@2.15.0:
dependencies:
hasown: 2.0.2
@@ -4791,15 +4958,15 @@ snapshots:
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
- jackspeak@3.4.0:
+ jackspeak@3.4.3:
dependencies:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
- jiti@1.21.3: {}
+ jiti@1.21.6: {}
- jose@4.15.5: {}
+ jose@4.15.9: {}
js-tokens@4.0.0: {}
@@ -4824,7 +4991,7 @@ snapshots:
object.assign: 4.1.5
object.values: 1.2.0
- katex@0.16.10:
+ katex@0.16.11:
dependencies:
commander: 8.3.0
@@ -4879,13 +5046,13 @@ snapshots:
devlop: 1.1.0
highlight.js: 11.9.0
- lru-cache@10.2.2: {}
+ lru-cache@10.4.3: {}
lru-cache@6.0.0:
dependencies:
yallist: 4.0.0
- lucide-react@0.363.0(react@18.3.1):
+ lucide-react@0.408.0(react@18.3.1):
dependencies:
react: 18.3.1
@@ -4917,7 +5084,7 @@ snapshots:
dependencies:
brace-expansion: 2.0.1
- minimatch@9.0.4:
+ minimatch@9.0.5:
dependencies:
brace-expansion: 2.0.1
@@ -4941,55 +5108,55 @@ snapshots:
natural-compare@1.4.0: {}
- next-auth@4.24.7(next@14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ next-auth@4.24.7(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.7
- '@panva/hkdf': 1.1.1
+ '@babel/runtime': 7.24.8
+ '@panva/hkdf': 1.2.1
cookie: 0.5.0
- jose: 4.15.5
- next: 14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ jose: 4.15.9
+ next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
oauth: 0.9.15
openid-client: 5.6.5
- preact: 10.22.0
- preact-render-to-string: 5.2.6(preact@10.22.0)
+ preact: 10.22.1
+ preact-render-to-string: 5.2.6(preact@10.22.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
uuid: 8.3.2
- next@14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- '@next/env': 14.2.4
+ '@next/env': 14.2.5
'@swc/helpers': 0.5.5
busboy: 1.6.0
- caniuse-lite: 1.0.30001632
+ caniuse-lite: 1.0.30001642
graceful-fs: 4.2.11
postcss: 8.4.31
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
styled-jsx: 5.1.1(react@18.3.1)
optionalDependencies:
- '@next/swc-darwin-arm64': 14.2.4
- '@next/swc-darwin-x64': 14.2.4
- '@next/swc-linux-arm64-gnu': 14.2.4
- '@next/swc-linux-arm64-musl': 14.2.4
- '@next/swc-linux-x64-gnu': 14.2.4
- '@next/swc-linux-x64-musl': 14.2.4
- '@next/swc-win32-arm64-msvc': 14.2.4
- '@next/swc-win32-ia32-msvc': 14.2.4
- '@next/swc-win32-x64-msvc': 14.2.4
+ '@next/swc-darwin-arm64': 14.2.5
+ '@next/swc-darwin-x64': 14.2.5
+ '@next/swc-linux-arm64-gnu': 14.2.5
+ '@next/swc-linux-arm64-musl': 14.2.5
+ '@next/swc-linux-x64-gnu': 14.2.5
+ '@next/swc-linux-x64-musl': 14.2.5
+ '@next/swc-win32-arm64-msvc': 14.2.5
+ '@next/swc-win32-ia32-msvc': 14.2.5
+ '@next/swc-win32-x64-msvc': 14.2.5
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
- nextjs-toploader@1.6.12(next@14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ nextjs-toploader@1.6.12(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- next: 14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
nprogress: 0.2.0
prop-types: 15.8.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- node-releases@2.0.14: {}
+ node-releases@2.0.17: {}
normalize-path@3.0.0: {}
@@ -5005,7 +5172,12 @@ snapshots:
object-hash@3.0.0: {}
- object-inspect@1.13.1: {}
+ object-inspect@1.13.2: {}
+
+ object-is@1.1.6:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
object-keys@1.1.1: {}
@@ -5035,12 +5207,6 @@ snapshots:
define-properties: 1.2.1
es-abstract: 1.23.3
- object.hasown@1.1.4:
- dependencies:
- define-properties: 1.2.1
- es-abstract: 1.23.3
- es-object-atoms: 1.0.0
-
object.values@1.2.0:
dependencies:
call-bind: 1.0.7
@@ -5055,7 +5221,7 @@ snapshots:
openid-client@5.6.5:
dependencies:
- jose: 4.15.5
+ jose: 4.15.9
lru-cache: 6.0.0
object-hash: 2.2.0
oidc-token-hash: 5.0.3
@@ -5079,6 +5245,8 @@ snapshots:
dependencies:
p-limit: 3.1.0
+ package-json-from-dist@1.0.0: {}
+
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
@@ -5093,7 +5261,7 @@ snapshots:
path-scurry@1.11.1:
dependencies:
- lru-cache: 10.2.2
+ lru-cache: 10.4.3
minipass: 7.1.2
path-type@4.0.0: {}
@@ -5108,31 +5276,31 @@ snapshots:
possible-typed-array-names@1.0.0: {}
- postcss-import@15.1.0(postcss@8.4.38):
+ postcss-import@15.1.0(postcss@8.4.39):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.39
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.8
- postcss-js@4.0.1(postcss@8.4.38):
+ postcss-js@4.0.1(postcss@8.4.39):
dependencies:
camelcase-css: 2.0.1
- postcss: 8.4.38
+ postcss: 8.4.39
- postcss-load-config@4.0.2(postcss@8.4.38):
+ postcss-load-config@4.0.2(postcss@8.4.39):
dependencies:
lilconfig: 3.1.2
yaml: 2.4.5
optionalDependencies:
- postcss: 8.4.38
+ postcss: 8.4.39
- postcss-nested@6.0.1(postcss@8.4.38):
+ postcss-nested@6.0.1(postcss@8.4.39):
dependencies:
- postcss: 8.4.38
- postcss-selector-parser: 6.1.0
+ postcss: 8.4.39
+ postcss-selector-parser: 6.1.1
- postcss-selector-parser@6.1.0:
+ postcss-selector-parser@6.1.1:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
@@ -5151,12 +5319,18 @@ snapshots:
picocolors: 1.0.1
source-map-js: 1.2.0
- preact-render-to-string@5.2.6(preact@10.22.0):
+ postcss@8.4.39:
dependencies:
- preact: 10.22.0
+ nanoid: 3.3.7
+ picocolors: 1.0.1
+ source-map-js: 1.2.0
+
+ preact-render-to-string@5.2.6(preact@10.22.1):
+ dependencies:
+ preact: 10.22.1
pretty-format: 3.8.0
- preact@10.22.0: {}
+ preact@10.22.1: {}
prelude-ls@1.2.1: {}
@@ -5178,7 +5352,7 @@ snapshots:
prosemirror-commands@1.5.2:
dependencies:
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
@@ -5186,20 +5360,20 @@ snapshots:
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
- prosemirror-view: 1.33.7
+ prosemirror-view: 1.33.8
prosemirror-gapcursor@1.3.2:
dependencies:
prosemirror-keymap: 1.2.2
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
prosemirror-state: 1.4.3
- prosemirror-view: 1.33.7
+ prosemirror-view: 1.33.8
- prosemirror-history@1.4.0:
+ prosemirror-history@1.4.1:
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
- prosemirror-view: 1.33.7
+ prosemirror-view: 1.33.8
rope-sequence: 1.3.4
prosemirror-inputrules@1.4.0:
@@ -5215,58 +5389,58 @@ snapshots:
prosemirror-markdown@1.13.0:
dependencies:
markdown-it: 14.1.0
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
prosemirror-menu@1.2.4:
dependencies:
crelt: 1.0.6
prosemirror-commands: 1.5.2
- prosemirror-history: 1.4.0
+ prosemirror-history: 1.4.1
prosemirror-state: 1.4.3
- prosemirror-model@1.21.1:
+ prosemirror-model@1.22.1:
dependencies:
orderedmap: 2.1.1
- prosemirror-schema-basic@1.2.2:
+ prosemirror-schema-basic@1.2.3:
dependencies:
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
- prosemirror-schema-list@1.4.0:
+ prosemirror-schema-list@1.4.1:
dependencies:
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
prosemirror-state@1.4.3:
dependencies:
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
prosemirror-transform: 1.9.0
- prosemirror-view: 1.33.7
+ prosemirror-view: 1.33.8
prosemirror-tables@1.3.7:
dependencies:
prosemirror-keymap: 1.2.2
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
- prosemirror-view: 1.33.7
+ prosemirror-view: 1.33.8
- prosemirror-trailing-node@2.0.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7):
+ prosemirror-trailing-node@2.0.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8):
dependencies:
'@remirror/core-constants': 2.0.2
escape-string-regexp: 4.0.0
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
prosemirror-state: 1.4.3
- prosemirror-view: 1.33.7
+ prosemirror-view: 1.33.8
prosemirror-transform@1.9.0:
dependencies:
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
- prosemirror-view@1.33.7:
+ prosemirror-view@1.33.8:
dependencies:
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
@@ -5291,7 +5465,7 @@ snapshots:
react-beautiful-dnd@13.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
css-box-model: 1.2.1
memoize-one: 5.2.1
raf-schd: 4.0.3
@@ -5330,13 +5504,13 @@ snapshots:
react-katex@3.0.1(prop-types@15.8.1)(react@18.3.1):
dependencies:
- katex: 0.16.10
+ katex: 0.16.11
prop-types: 15.8.1
react: 18.3.1
react-redux@7.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
'@types/react-redux': 7.1.33
hoist-non-react-statics: 3.3.2
loose-envify: 1.4.0
@@ -5354,7 +5528,7 @@ snapshots:
optionalDependencies:
'@types/react': 18.2.74
- react-remove-scroll@2.5.5(@types/react@18.2.74)(react@18.3.1):
+ react-remove-scroll@2.5.7(@types/react@18.2.74)(react@18.3.1):
dependencies:
react: 18.3.1
react-remove-scroll-bar: 2.3.6(@types/react@18.2.74)(react@18.3.1)
@@ -5408,7 +5582,7 @@ snapshots:
redux@4.2.1:
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.24.8
reflect.getprototypeof@1.0.6:
dependencies:
@@ -5435,13 +5609,13 @@ snapshots:
resolve@1.22.8:
dependencies:
- is-core-module: 2.13.1
+ is-core-module: 2.15.0
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
resolve@2.0.0-next.5:
dependencies:
- is-core-module: 2.13.1
+ is-core-module: 2.15.0
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
@@ -5478,7 +5652,7 @@ snapshots:
semver@6.3.1: {}
- semver@7.6.2: {}
+ semver@7.6.3: {}
set-function-length@1.2.2:
dependencies:
@@ -5502,7 +5676,7 @@ snapshots:
dependencies:
color: 4.2.3
detect-libc: 2.0.3
- semver: 7.6.2
+ semver: 7.6.3
optionalDependencies:
'@img/sharp-darwin-arm64': 0.33.4
'@img/sharp-darwin-x64': 0.33.4
@@ -5535,7 +5709,7 @@ snapshots:
call-bind: 1.0.7
es-errors: 1.3.0
get-intrinsic: 1.2.4
- object-inspect: 1.13.1
+ object-inspect: 1.13.2
signal-exit@4.1.0: {}
@@ -5561,6 +5735,10 @@ snapshots:
source-map-js@1.2.0: {}
+ stop-iteration-iterator@1.0.0:
+ dependencies:
+ internal-slot: 1.0.7
+
streamsearch@1.1.0: {}
string-width@4.2.3:
@@ -5575,6 +5753,11 @@ snapshots:
emoji-regex: 9.2.2
strip-ansi: 7.1.0
+ string.prototype.includes@2.0.0:
+ dependencies:
+ define-properties: 1.2.1
+ es-abstract: 1.23.3
+
string.prototype.matchall@4.0.11:
dependencies:
call-bind: 1.0.7
@@ -5590,6 +5773,11 @@ snapshots:
set-function-name: 2.0.2
side-channel: 1.0.6
+ string.prototype.repeat@1.0.0:
+ dependencies:
+ define-properties: 1.2.1
+ es-abstract: 1.23.3
+
string.prototype.trim@1.2.9:
dependencies:
call-bind: 1.0.7
@@ -5625,7 +5813,7 @@ snapshots:
strip-json-comments@3.1.1: {}
- styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@emotion/is-prop-valid': 1.2.2
'@emotion/unitless': 0.8.1
@@ -5650,7 +5838,7 @@ snapshots:
dependencies:
'@jridgewell/gen-mapping': 0.3.5
commander: 4.1.1
- glob: 10.4.1
+ glob: 10.4.5
lines-and-columns: 1.2.4
mz: 2.7.0
pirates: 4.0.6
@@ -5668,15 +5856,13 @@ snapshots:
react: 18.3.1
use-sync-external-store: 1.2.2(react@18.3.1)
- tailwind-merge@2.3.0:
- dependencies:
- '@babel/runtime': 7.24.7
+ tailwind-merge@2.4.0: {}
- tailwind-scrollbar@3.1.0(tailwindcss@3.4.4):
+ tailwind-scrollbar@3.1.0(tailwindcss@3.4.6):
dependencies:
- tailwindcss: 3.4.4
+ tailwindcss: 3.4.6
- tailwindcss@3.4.4:
+ tailwindcss@3.4.6:
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -5686,18 +5872,18 @@ snapshots:
fast-glob: 3.3.2
glob-parent: 6.0.2
is-glob: 4.0.3
- jiti: 1.21.3
+ jiti: 1.21.6
lilconfig: 2.1.0
micromatch: 4.0.7
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.0.1
- postcss: 8.4.38
- postcss-import: 15.1.0(postcss@8.4.38)
- postcss-js: 4.0.1(postcss@8.4.38)
- postcss-load-config: 4.0.2(postcss@8.4.38)
- postcss-nested: 6.0.1(postcss@8.4.38)
- postcss-selector-parser: 6.1.0
+ postcss: 8.4.39
+ postcss-import: 15.1.0(postcss@8.4.39)
+ postcss-js: 4.0.1(postcss@8.4.39)
+ postcss-load-config: 4.0.2(postcss@8.4.39)
+ postcss-nested: 6.0.1(postcss@8.4.39)
+ postcss-selector-parser: 6.1.1
resolve: 1.22.8
sucrase: 3.35.0
transitivePeerDependencies:
@@ -5797,9 +5983,9 @@ snapshots:
undici-types@5.26.5: {}
- update-browserslist-db@1.0.16(browserslist@4.23.1):
+ update-browserslist-db@1.1.0(browserslist@4.23.2):
dependencies:
- browserslist: 4.23.1
+ browserslist: 4.23.2
escalade: 3.1.2
picocolors: 1.0.1
@@ -5896,35 +6082,35 @@ snapshots:
wrappy@1.0.2: {}
- ws@8.17.0: {}
+ ws@8.18.0: {}
- y-indexeddb@9.0.12(yjs@13.6.16):
+ y-indexeddb@9.0.12(yjs@13.6.18):
dependencies:
lib0: 0.2.94
- yjs: 13.6.16
+ yjs: 13.6.18
- y-prosemirror@1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16):
+ y-prosemirror@1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18):
dependencies:
lib0: 0.2.94
- prosemirror-model: 1.21.1
+ prosemirror-model: 1.22.1
prosemirror-state: 1.4.3
- prosemirror-view: 1.33.7
- y-protocols: 1.0.6(yjs@13.6.16)
- yjs: 13.6.16
+ prosemirror-view: 1.33.8
+ y-protocols: 1.0.6(yjs@13.6.18)
+ yjs: 13.6.18
- y-protocols@1.0.6(yjs@13.6.16):
+ y-protocols@1.0.6(yjs@13.6.18):
dependencies:
lib0: 0.2.94
- yjs: 13.6.16
+ yjs: 13.6.18
- y-webrtc@10.3.0(yjs@13.6.16):
+ y-webrtc@10.3.0(yjs@13.6.18):
dependencies:
lib0: 0.2.94
simple-peer: 9.11.1
- y-protocols: 1.0.6(yjs@13.6.16)
- yjs: 13.6.16
+ y-protocols: 1.0.6(yjs@13.6.18)
+ yjs: 13.6.18
optionalDependencies:
- ws: 8.17.0
+ ws: 8.18.0
transitivePeerDependencies:
- bufferutil
- supports-color
@@ -5934,7 +6120,7 @@ snapshots:
yaml@2.4.5: {}
- yjs@13.6.16:
+ yjs@13.6.18:
dependencies:
lib0: 0.2.94
From 29600d9b6c4f93968397023fc461bdeb2561a5a3 Mon Sep 17 00:00:00 2001
From: swve
Date: Thu, 18 Jul 2024 21:05:32 +0200
Subject: [PATCH 13/25] feat: assignments activity page init
---
apps/api/src/routers/courses/assignments.py | 16 ++
.../courses/activities/assignments.py | 63 +++++++
.../courses/activities/uploads/sub_file.py | 24 +++
.../activity/[activityid]/activity.tsx | 69 +++++--
.../Subs/AssignmentTaskContentEdit.tsx | 2 +-
.../Subs/TaskTypes/TaskFileObject.tsx | 148 ++++++++++++++-
.../Subs/TaskTypes/TaskQuizObject.tsx | 172 +++++++++++-------
.../assignments/[assignmentuuid]/page.tsx | 20 +-
.../Assignments/AssignmentContext.tsx | 11 +-
.../Assignment}/AssignmentBoxUI.tsx | 33 ++--
.../Assignment/AssignmentStudentActivity.tsx | 89 +++++++++
apps/web/services/courses/assignments.ts | 22 +++
12 files changed, 564 insertions(+), 105 deletions(-)
create mode 100644 apps/api/src/services/courses/activities/uploads/sub_file.py
rename apps/web/components/Objects/{Assignments => Activities/Assignment}/AssignmentBoxUI.tsx (55%)
create mode 100644 apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index 8f564915..6f4c4aa8 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -22,6 +22,7 @@ from src.services.courses.activities.assignments import (
delete_assignment_task,
delete_assignment_task_submission,
put_assignment_task_reference_file,
+ put_assignment_task_submission_file,
read_assignment,
read_assignment_from_activity_uuid,
read_assignment_submissions,
@@ -205,6 +206,21 @@ async def api_put_assignment_task_ref_file(
request, db_session, assignment_task_uuid, current_user, reference_file
)
+@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/sub_file")
+async def api_put_assignment_task_sub_file(
+ request: Request,
+ assignment_task_uuid: str,
+ sub_file: UploadFile | None = None,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Update tasks for an assignment
+ """
+ return await put_assignment_task_submission_file(
+ request, db_session, assignment_task_uuid, current_user, sub_file
+ )
+
@router.delete("/{assignment_uuid}/tasks/{assignment_task_uuid}")
async def api_delete_assignment_tasks(
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index 4d58e196..f8f196d6 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -33,6 +33,7 @@ from src.security.rbac.rbac import (
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_anon,
)
+from src.services.courses.activities.uploads.sub_file import upload_submission_file
from src.services.courses.activities.uploads.tasks_ref_files import (
upload_reference_file,
)
@@ -493,6 +494,68 @@ async def put_assignment_task_reference_file(
# return assignment task read
return AssignmentTaskRead.model_validate(assignment_task)
+async def put_assignment_task_submission_file(
+ request: Request,
+ db_session: Session,
+ assignment_task_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ sub_file: UploadFile | None = None,
+):
+ # Check if assignment task exists
+ statement = select(AssignmentTask).where(
+ AssignmentTask.assignment_task_uuid == assignment_task_uuid
+ )
+ assignment_task = db_session.exec(statement).first()
+
+ if not assignment_task:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check for activity
+ statement = select(Activity).where(Activity.id == assignment.activity_id)
+ activity = db_session.exec(statement).first()
+
+ # Check if course exists
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # Get org uuid
+ org_statement = select(Organization).where(Organization.id == course.org_id)
+ org = db_session.exec(org_statement).first()
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # Upload reference file
+ if sub_file and sub_file.filename and activity and org:
+ name_in_disk = (
+ f"{assignment_task_uuid}_sub_{current_user.email}_{uuid4()}.{sub_file.filename.split('.')[-1]}"
+ )
+ await upload_submission_file(
+ sub_file, name_in_disk, activity.activity_uuid, org.org_uuid, course.course_uuid, assignment.assignment_uuid, assignment_task_uuid
+ )
+
+ return {"message": "Assignment Task Submission File uploaded"}
+
+
async def update_assignment_task(
request: Request,
diff --git a/apps/api/src/services/courses/activities/uploads/sub_file.py b/apps/api/src/services/courses/activities/uploads/sub_file.py
new file mode 100644
index 00000000..48df3cc5
--- /dev/null
+++ b/apps/api/src/services/courses/activities/uploads/sub_file.py
@@ -0,0 +1,24 @@
+from uuid import uuid4
+from src.services.utils.upload_content import upload_content
+
+
+async def upload_submission_file(
+ file,
+ name_in_disk,
+ activity_uuid,
+ org_uuid,
+ course_uuid,
+ assignment_uuid,
+ assignment_task_uuid,
+):
+ contents = file.file.read()
+ file_format = file.filename.split(".")[-1]
+
+ await upload_content(
+ f"courses/{course_uuid}/activities/{activity_uuid}/assignments/{assignment_uuid}/tasks/{assignment_task_uuid}/subs",
+ "orgs",
+ org_uuid,
+ contents,
+ f"{name_in_disk}",
+ ["pdf", "docx", "mp4", "jpg", "jpeg", "png", "pptx"],
+ )
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
index 9bc369cd..a00aa3ae 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
@@ -16,6 +16,11 @@ import { CourseProvider } from '@components/Contexts/CourseContext'
import AIActivityAsk from '@components/Objects/Activities/AI/AIActivityAsk'
import AIChatBotProvider from '@components/Contexts/AI/AIChatBotContext'
import { useLHSession } from '@components/Contexts/LHSessionContext'
+import React, { useEffect } from 'react'
+import { getAssignmentFromActivityUUID } from '@services/courses/assignments'
+import AssignmentStudentActivity from '@components/Objects/Activities/Assignment/AssignmentStudentActivity'
+import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext'
+import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext'
interface ActivityClientProps {
activityid: string
@@ -32,6 +37,11 @@ function ActivityClient(props: ActivityClientProps) {
const activity = props.activity
const course = props.course
const org = useOrg() as any
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const [bgColor, setBgColor] = React.useState('bg-white')
+ const [assignment, setAssignment] = React.useState(null) as any;
+ const [markStatusButtonActive, setMarkStatusButtonActive] = React.useState(false);
function getChapterNameByActivityId(course: any, activity_id: any) {
for (let i = 0; i < course.chapters.length; i++) {
@@ -46,6 +56,26 @@ function ActivityClient(props: ActivityClientProps) {
return null // return null if no matching activity is found
}
+ async function getAssignmentUI() {
+ const assignment = await getAssignmentFromActivityUUID(activity.activity_uuid, access_token)
+ setAssignment(assignment.data)
+ }
+
+ useEffect(() => {
+ if (activity.activity_type == 'TYPE_DYNAMIC') {
+ setBgColor('bg-white nice-shadow');
+ }
+ else if (activity.activity_type == 'TYPE_ASSIGNMENT') {
+ setMarkStatusButtonActive(false);
+ setBgColor('bg-white nice-shadow');
+ getAssignmentUI();
+ }
+ else {
+ setBgColor('bg-zinc-950');
+ }
+ }
+ , [activity])
+
return (
<>
@@ -93,24 +123,26 @@ function ActivityClient(props: ActivityClientProps) {
-
-
-
+ {activity.activity_type != 'TYPE_ASSIGNMENT' &&
+ <>
+
+
+
+ >
+ }
+
{activity ? (
{activity.activity_type == 'TYPE_DYNAMIC' && (
@@ -126,6 +158,19 @@ function ActivityClient(props: ActivityClientProps) {
activity={activity}
/>
)}
+ {activity.activity_type == 'TYPE_ASSIGNMENT' && (
+
+ {assignment ? (
+
+
+
+
+
+ ) : (
+
+ )}
+
+ )}
) : (
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
index ee38744a..afddc310 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx
@@ -16,7 +16,7 @@ function AssignmentTaskContentEdit() {
return (
- {assignment_task?.assignmentTask.assignment_type === 'QUIZ' && }
+ {assignment_task?.assignmentTask.assignment_type === 'QUIZ' && }
{assignment_task?.assignmentTask.assignment_type === 'FILE_SUBMISSION' && }
)
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
index ed7bd2e8..4aafcee3 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
@@ -1,14 +1,146 @@
-import AssignmentBoxUI from '@components/Objects/Assignments/AssignmentBoxUI'
-import { Info } from 'lucide-react'
-import React from 'react'
+import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
+import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import AssignmentBoxUI from '@components/Objects/Activities/Assignment/AssignmentBoxUI'
+import { getAssignmentTask, updateSubFile } from '@services/courses/assignments';
+import { Cloud, File, Info, Loader, UploadCloud } from 'lucide-react'
+import React, { useEffect } from 'react'
+import toast from 'react-hot-toast';
+
+type FileSchema = {
+ fileID: string;
+};
+
+type TaskFileObjectProps = {
+ view: 'teacher' | 'student';
+ assignmentTaskUUID?: string;
+};
+
+export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObjectProps) {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const [isLoading, setIsLoading] = React.useState(false);
+ const [localUploadFile, setLocalUploadFile] = React.useState
(null);
+ const [error, setError] = React.useState(null);
+ const [assignmentTask, setAssignmentTask] = React.useState(null);
+ const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any;
+ const assignment = useAssignments() as any;
+
+ const handleFileChange = async (event: any) => {
+ const file = event.target.files[0]
+
+ setLocalUploadFile(file)
+ setIsLoading(true)
+ const res = await updateSubFile(
+ file,
+ assignmentTask.assignment_task_uuid,
+ assignment.assignment_object.assignment_uuid,
+ access_token
+ )
+ assignmentTaskStateHook({ type: 'reload' })
+ // wait for 1 second to show loading animation
+ await new Promise((r) => setTimeout(r, 1500))
+ if (res.success === false) {
+ setError(res.data.detail)
+ setIsLoading(false)
+ } else {
+ setIsLoading(false)
+ setError('')
+ }
+
+ }
+
+ async function getAssignmentTaskUI() {
+ if (assignmentTaskUUID) {
+ const res = await getAssignmentTask(assignmentTaskUUID, access_token);
+ if (res.success) {
+ setAssignmentTask(res.data);
+ }
+
+ }
+ }
+
+ useEffect(() => {
+ getAssignmentTaskUI()
+ }
+ , [assignmentTaskUUID])
-export default function TaskFileObject({ view }: any) {
return (
-
-
-
User will be able to submit a file for this task, you'll be able to review it in the Submissions Tab
-
+ {view === 'teacher' && (
+
+
+
User will be able to submit a file for this task, you'll be able to review it in the Submissions Tab
+
+ )}
+ {view === 'student' && (
+ <>
+
+
+
+
+ {localUploadFile && !isLoading && (
+
+
+
+
+
+
+
+
+
+ {localUploadFile.name}
+
+
+
+ )}
+
+
+
Allowed formats : pdf, docx, mp4, jpg, jpeg, pptx
+
+ {isLoading ? (
+
+ ) : (
+
+
+
+
+ )}
+
+
+
+
+ >
+ )}
)
}
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
index 1b53c085..69ab4d0b 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
@@ -1,8 +1,8 @@
import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import { useLHSession } from '@components/Contexts/LHSessionContext';
-import AssignmentBoxUI from '@components/Objects/Assignments/AssignmentBoxUI';
-import { updateAssignmentTask } from '@services/courses/assignments';
+import AssignmentBoxUI from '@components/Objects/Activities/Assignment/AssignmentBoxUI';
+import { getAssignmentTask, updateAssignmentTask } from '@services/courses/assignments';
import { Check, Minus, Plus, PlusCircle, X } from 'lucide-react';
import React, { useEffect, useState } from 'react';
import toast from 'react-hot-toast';
@@ -20,14 +20,19 @@ type QuizSchema = {
}[];
};
-function TaskQuizObject() {
+type TaskQuizObjectProps = {
+ view: 'teacher' | 'student';
+ assignmentTaskUUID?: string;
+};
+
+function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
const session = useLHSession() as any;
const access_token = session?.data?.tokens?.access_token;
const assignmentTaskState = useAssignmentsTask() as any;
const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any;
const assignment = useAssignments() as any;
- // Teacher area
+ /* TEACHER VIEW CODE */
const [questions, setQuestions] = useState([
{ questionText: '', questionUUID: 'question_' + uuidv4(), options: [{ text: '', fileID: '', type: 'text', correct: false, optionUUID: 'option_' + uuidv4() }] },
]);
@@ -92,99 +97,136 @@ function TaskQuizObject() {
toast.error('Error saving task, please retry later.');
}
};
+ /* TEACHER VIEW CODE */
+
+ /* STUDENT VIEW CODE */
+ async function getAssignmentTaskUI() {
+ if (assignmentTaskUUID) {
+ const res = await getAssignmentTask(assignmentTaskUUID, access_token);
+ if (res.success) {
+ setQuestions(res.data.contents.questions);
+ }
+
+ }
+ }
+
+ /* STUDENT VIEW CODE */
useEffect(() => {
- if (assignmentTaskState.assignmentTask.contents?.questions) {
+ assignmentTaskStateHook({
+ setSelectedAssignmentTaskUUID: assignmentTaskUUID,
+ });
+ // Teacher area
+ if (view == 'teacher' && assignmentTaskState.assignmentTask.contents?.questions) {
setQuestions(assignmentTaskState.assignmentTask.contents.questions);
}
- }, [assignmentTaskState,assignment,assignmentTaskStateHook,access_token]);
+ // Student area
+ else if (view == 'student') {
+ getAssignmentTaskUI();
+ }
+ }, [assignmentTaskState, assignment, assignmentTaskStateHook, access_token]);
- // Teacher area end
return (
-
+
- {questions.map((question, qIndex) => (
+ {questions && questions.map((question, qIndex) => (
-
handleQuestionChange(qIndex, e.target.value)}
- placeholder="Question"
- className="w-full px-3 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold"
- />
-
removeQuestion(qIndex)}
- >
-
-
+ {view === 'teacher' ? (
+
handleQuestionChange(qIndex, e.target.value)}
+ placeholder="Question"
+ className="w-full px-3 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold"
+ />
+ ) : (
+
+ {question.questionText}
+
+ )}
+ {view === 'teacher' && (
+
removeQuestion(qIndex)}
+ >
+
+
+ )}
{question.options.map((option, oIndex) => (
{String.fromCharCode(65 + oIndex)}
-
handleOptionChange(qIndex, oIndex, e.target.value)}
- placeholder="Option"
- className="w-full mx-2 px-3 pr-6 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold"
- />
-
toggleCorrectOption(qIndex, oIndex)}
- >
- {option.correct ?
:
}
- {option.correct ? (
-
Correct
- ) : (
-
Incorrect
- )}
-
-
removeOption(qIndex, oIndex)}
- >
-
-
-
-
- {/* Show this at the last option */}
- {oIndex === question.options.length - 1 && (
-
+ {view === 'teacher' ? (
+
handleOptionChange(qIndex, oIndex, e.target.value)}
+ placeholder="Option"
+ className="w-full mx-2 px-3 pr-6 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold"
+ />
+ ) : (
+
+ {option.text}
+
+ )}
+ {view === 'teacher' && (
+ <>
addOption(qIndex)}
+ className={`w-fit flex-none flex text-xs px-2 py-0.5 space-x-1 items-center h-fit rounded-lg ${option.correct ? 'bg-lime-200 text-lime-600' : 'bg-rose-200/60 text-rose-500'
+ } hover:bg-lime-300 text-sm transition-all ease-linear cursor-pointer`}
+ onClick={() => toggleCorrectOption(qIndex, oIndex)}
>
-
-
+ {option.correct ?
:
}
+ {option.correct ? (
+
Correct
+ ) : (
+
Incorrect
+ )}
-
+
removeOption(qIndex, oIndex)}
+ >
+
+
+ >
)}
+ {view === 'teacher' && oIndex === question.options.length - 1 && (
+
+
addOption(qIndex)}
+ >
+
+
+
+
+ )}
))}
))}
-
-
-
-
Add Question
+ {view === 'teacher' && (
+
-
+ )}
);
}
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
index 44b2c164..b1605d25 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
@@ -1,10 +1,9 @@
'use client';
import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'
-import { BookOpen, BookX, EllipsisVertical, LayoutList } from 'lucide-react'
+import { BookOpen, BookX, EllipsisVertical, Eye, LayoutList } from 'lucide-react'
import React, { useEffect } from 'react'
import { AssignmentProvider, useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
import AssignmentTasks from './_components/Tasks';
-import { useParams } from 'next/navigation';
import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import ToolTip from '@components/StyledElements/Tooltip/Tooltip';
import AssignmentTaskEditor from './_components/TaskEditor/TaskEditor';
@@ -13,6 +12,8 @@ import { useLHSession } from '@components/Contexts/LHSessionContext';
import { mutate } from 'swr';
import { getAPIUrl } from '@services/config/config';
import toast from 'react-hot-toast';
+import Link from 'next/link';
+import { useParams } from 'next/navigation';
function AssignmentEdit() {
const params = useParams<{ assignmentuuid: string; }>()
@@ -83,7 +84,7 @@ function PublishingState() {
}
useEffect(() => {
- console.log('assignment', assignment?.assignment_object?.assignment_uuid)
+ console.log('assignment', assignment)
}, [assignment])
return (
@@ -104,6 +105,19 @@ function PublishingState() {
Unpublish
}
+
+
+
+ Preview
+
+
{!assignment?.assignment_object?.published &&
swrFetcher(url, accessToken)
)
- // Define a key for the course object based on assignment data
const course_id = assignment?.course_id
const { data: course_object, error: courseObjectError } = useSWR(
@@ -38,12 +37,14 @@ export function AssignmentProvider({ children, assignment_uuid }: { children: Re
)
useEffect(() => {
- setAssignmentsFull({ assignment_object: assignment, assignment_tasks: assignment_tasks, course_object: course_object, activity_object: activity_object })
- }, [assignment, assignment_tasks, course_object, activity_object])
+ if (assignment && assignment_tasks && (!course_id || course_object) && (!activity_id || activity_object)) {
+ setAssignmentsFull({ assignment_object: assignment, assignment_tasks: assignment_tasks, course_object: course_object, activity_object: activity_object })
+ }
+ }, [assignment, assignment_tasks, course_object, activity_object, course_id, activity_id])
- if (assignmentError || assignmentTasksError || courseObjectError) return
+ if (assignmentError || assignmentTasksError || courseObjectError || activityObjectError) return
- if (!assignment || !assignment_tasks || (course_id && !course_object)) return
+ if (!assignment || !assignment_tasks || (course_id && !course_object) || (activity_id && !activity_object)) return
return {children}
}
diff --git a/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
similarity index 55%
rename from apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
rename to apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
index f91f10d9..b8c25ca9 100644
--- a/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx
+++ b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
@@ -1,17 +1,18 @@
-import { BookUser, EllipsisVertical, FileUp, ListTodo, Save } from 'lucide-react'
+import { BookUser, EllipsisVertical, FileUp, Forward, ListTodo, Save } from 'lucide-react'
import React from 'react'
type AssignmentBoxProps = {
type: 'quiz' | 'file'
view?: 'teacher' | 'student'
saveFC?: () => void
+ submitFC?: () => void
children: React.ReactNode
}
-function AssignmentBoxUI({ type, view, saveFC, children }: AssignmentBoxProps) {
+function AssignmentBoxUI({ type, view, saveFC, submitFC, children }: AssignmentBoxProps) {
return (
-
+
@@ -20,13 +21,13 @@ function AssignmentBoxUI({ type, view, saveFC, children }: AssignmentBoxProps) {
Quiz
}
- {type === 'file' &&
+ {type === 'file' &&
}
-
+
@@ -41,12 +42,22 @@ function AssignmentBoxUI({ type, view, saveFC, children }: AssignmentBoxProps) {
{/* Save button */}
-
saveFC && saveFC()}
- className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-slate-500 bg-white/60 hover:bg-white/80 linear transition-all nice-shadow '>
-
-
Save
-
+ {view === 'teacher' &&
+
saveFC && saveFC()}
+ className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-slate-500 bg-white/60 hover:bg-white/80 linear transition-all nice-shadow '>
+
+
Save
+
+ }
+ {view === 'student' &&
+
submitFC && submitFC()}
+ className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-slate-500 bg-white/60 hover:bg-white/80 linear transition-all nice-shadow '>
+
+
Save
+
+ }
diff --git a/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx b/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx
new file mode 100644
index 00000000..d428d021
--- /dev/null
+++ b/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx
@@ -0,0 +1,89 @@
+import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
+import { useAssignmentsTask } from '@components/Contexts/Assignments/AssignmentsTaskContext';
+import { useCourse } from '@components/Contexts/CourseContext';
+import { useOrg } from '@components/Contexts/OrgContext';
+import { getTaskRefFileDir } from '@services/media/media';
+import TaskFileObject from 'app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject';
+import TaskQuizObject from 'app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject'
+import { Backpack, Calendar, Download, EllipsisVertical, Info } from 'lucide-react';
+import Link from 'next/link';
+import React, { useEffect } from 'react'
+
+function AssignmentStudentActivity() {
+ const assignments = useAssignments() as any;
+ const course = useCourse() as any;
+ const org = useOrg() as any;
+
+ useEffect(() => {
+ console.log(assignments)
+ }, [assignments, org])
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
Due Date
+
{assignments?.assignment_object?.due_date}
+
+
+
+
+
+
+
+ {assignments && assignments?.assignment_tasks?.sort((a: any, b: any) => a.id - b.id).map((task: any, index: number) => {
+ return (
+
+
+
+
Task {index + 1} :
+
{task.description}
+
+
+
alert(task.hint)}
+ className='px-3 py-1 flex items-center nice-shadow bg-amber-50/40 text-amber-900 rounded-full space-x-2 cursor-pointer'>
+
+
View Hint
+
+
+
+
Reference file
+
+
+
+
+ {task.assignment_type === 'QUIZ' && }
+ {task.assignment_type === 'FILE_SUBMISSION' && }
+
+
+ )
+ })}
+
+ )
+}
+
+export default AssignmentStudentActivity
\ No newline at end of file
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
index 1a6e54e8..16f57945 100644
--- a/apps/web/services/courses/assignments.ts
+++ b/apps/web/services/courses/assignments.ts
@@ -138,3 +138,25 @@ export async function updateReferenceFile(
const res = await getResponseMetadata(result)
return res
}
+
+
+export async function updateSubFile(
+ file: any,
+ assignmentTaskUUID: string,
+ assignmentUUID: string,
+ access_token: string
+) {
+
+ // Send file thumbnail as form data
+ const formData = new FormData()
+
+ if (file) {
+ formData.append('sub_file', file)
+ }
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/sub_file`,
+ RequestBodyFormWithAuthHeader('POST', formData, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
From 6d7e521bba4033e44e7fc1ea80b5439e95165ff7 Mon Sep 17 00:00:00 2001
From: swve
Date: Thu, 18 Jul 2024 21:40:54 +0200
Subject: [PATCH 14/25] feat: Add student quiz saving functionality
---
.../Subs/TaskTypes/TaskQuizObject.tsx | 63 ++++++++++++++++++-
1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
index 69ab4d0b..722221d9 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
@@ -20,6 +20,14 @@ type QuizSchema = {
}[];
};
+type QuizSubmitSchema = {
+ questions: QuizSchema[];
+ submissions: {
+ questionUUID: string;
+ optionUUID: string;
+ }[];
+};
+
type TaskQuizObjectProps = {
view: 'teacher' | 'student';
assignmentTaskUUID?: string;
@@ -32,6 +40,7 @@ function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any;
const assignment = useAssignments() as any;
+
/* TEACHER VIEW CODE */
const [questions, setQuestions] = useState([
{ questionText: '', questionUUID: 'question_' + uuidv4(), options: [{ text: '', fileID: '', type: 'text', correct: false, optionUUID: 'option_' + uuidv4() }] },
@@ -100,6 +109,38 @@ function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
/* TEACHER VIEW CODE */
/* STUDENT VIEW CODE */
+ const [userSubmissions, setUserSubmissions] = useState({
+ questions: [],
+ submissions: [],
+ });
+
+ async function chooseOption(qIndex: number, oIndex: number) {
+ const updatedSubmissions = [...userSubmissions.submissions];
+ const questionUUID = questions[qIndex].questionUUID;
+ const optionUUID = questions[qIndex].options[oIndex].optionUUID;
+
+ // Check if this question already has a submission with the selected option
+ const existingSubmissionIndex = updatedSubmissions.findIndex(
+ (submission) => submission.questionUUID === questionUUID && submission.optionUUID === optionUUID
+ );
+
+ if (existingSubmissionIndex === -1 && optionUUID && questionUUID) {
+ // If the selected option is not already chosen, add it to the submissions
+ updatedSubmissions.push({ questionUUID, optionUUID });
+ } else {
+ // If the selected option is already chosen, remove it from the submissions
+ updatedSubmissions.splice(existingSubmissionIndex, 1);
+ }
+
+ setUserSubmissions({
+ ...userSubmissions,
+ submissions: updatedSubmissions,
+ });
+ console.log(userSubmissions);
+ }
+
+
+
async function getAssignmentTaskUI() {
if (assignmentTaskUUID) {
const res = await getAssignmentTask(assignmentTaskUUID, access_token);
@@ -158,7 +199,8 @@ function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
{question.options.map((option, oIndex) => (
view === 'student' && chooseOption(qIndex, oIndex)}
+ className={"answer outline outline-3 outline-white pr-2 shadow w-full flex items-center space-x-2 h-[30px] hover:bg-opacity-100 hover:shadow-md rounded-lg bg-white text-sm duration-150 cursor-pointer ease-linear nice-shadow " + (view == 'student' ? 'active:scale-110' : '')}
>
{String.fromCharCode(65 + oIndex)}
@@ -198,6 +240,25 @@ function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
>
)}
+ {view === 'student' && (
+
+ submission.questionUUID === question.questionUUID && submission.optionUUID === option.optionUUID
+ )
+ ? "bg-green-200/60 text-green-500 hover:bg-green-300" // Selected state colors
+ : "bg-slate-200/60 text-slate-500 hover:bg-slate-300" // Default state colors
+ } text-sm transition-all ease-linear cursor-pointer`}>
+ {userSubmissions.submissions.find(
+ (submission) =>
+ submission.questionUUID === question.questionUUID && submission.optionUUID === option.optionUUID
+ ) ? (
+
+ ) : (
+
+ )}
+
+ )}
+
{view === 'teacher' && oIndex === question.options.length - 1 && (
From bfb977ac5df7dad4d286b3ce084c3e219759c150 Mon Sep 17 00:00:00 2001
From: swve
Date: Fri, 19 Jul 2024 19:56:49 +0200
Subject: [PATCH 15/25] feat: enable Tasks submissions
---
apps/api/src/db/courses/assignments.py | 13 +-
apps/api/src/routers/courses/assignments.py | 26 ++-
.../courses/activities/assignments.py | 154 ++++++++++++------
.../Subs/TaskTypes/TaskFileObject.tsx | 108 ++++++++++--
.../Subs/TaskTypes/TaskQuizObject.tsx | 59 ++++++-
.../assignments/[assignmentuuid]/page.tsx | 25 +--
.../Activities/Assignment/AssignmentBoxUI.tsx | 18 +-
.../Assignment/AssignmentStudentActivity.tsx | 10 +-
apps/web/services/courses/assignments.ts | 27 +++
9 files changed, 330 insertions(+), 110 deletions(-)
diff --git a/apps/api/src/db/courses/assignments.py b/apps/api/src/db/courses/assignments.py
index e5d38b9e..dc7722a5 100644
--- a/apps/api/src/db/courses/assignments.py
+++ b/apps/api/src/db/courses/assignments.py
@@ -1,5 +1,5 @@
from typing import Optional, Dict
-from sqlalchemy import JSON, Column, ForeignKey
+from sqlalchemy import JSON, Column, ForeignKey, null
from sqlmodel import Field, SQLModel
from enum import Enum
@@ -125,7 +125,7 @@ class AssignmentTaskUpdate(SQLModel):
description: Optional[str]
hint: Optional[str]
assignment_type: Optional[AssignmentTaskTypeEnum]
- contents: Optional[Dict] = Field(default={}, sa_column=Column(JSON))
+ contents: Optional[Dict] = Field(default=None, sa_column=Column(JSON))
max_grade_value: Optional[int]
@@ -194,17 +194,12 @@ class AssignmentTaskSubmissionRead(AssignmentTaskSubmissionBase):
class AssignmentTaskSubmissionUpdate(SQLModel):
"""Model for updating an assignment task submission."""
-
+ assignment_task_id: Optional[int]
assignment_task_submission_uuid: Optional[str]
- task_submission: Optional[Dict] = Field(default={}, sa_column=Column(JSON))
+ task_submission: Optional[Dict] = Field(default=None, sa_column=Column(JSON))
grade: Optional[int]
task_submission_grade_feedback: Optional[str]
assignment_type: Optional[AssignmentTaskTypeEnum]
- user_id: Optional[int]
- activity_id: Optional[int]
- course_id: Optional[int]
- chapter_id: Optional[int]
- assignment_task_id: Optional[int]
class AssignmentTaskSubmission(AssignmentTaskSubmissionBase, table=True):
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index 6f4c4aa8..3365ca94 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -4,6 +4,7 @@ from src.db.courses.assignments import (
AssignmentRead,
AssignmentTaskCreate,
AssignmentTaskSubmissionCreate,
+ AssignmentTaskSubmissionUpdate,
AssignmentTaskUpdate,
AssignmentUpdate,
AssignmentUserSubmissionCreate,
@@ -15,12 +16,12 @@ from src.services.courses.activities.assignments import (
create_assignment,
create_assignment_submission,
create_assignment_task,
- create_assignment_task_submission,
delete_assignment,
delete_assignment_from_activity_uuid,
delete_assignment_submission,
delete_assignment_task,
delete_assignment_task_submission,
+ handle_assignment_task_submission,
put_assignment_task_reference_file,
put_assignment_task_submission_file,
read_assignment,
@@ -31,6 +32,7 @@ from src.services.courses.activities.assignments import (
read_assignment_tasks,
read_user_assignment_submissions,
read_user_assignment_task_submissions,
+ read_user_assignment_task_submissions_me,
update_assignment,
update_assignment_submission,
update_assignment_task,
@@ -240,10 +242,10 @@ async def api_delete_assignment_tasks(
## ASSIGNMENTS Tasks Submissions ##
-@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions")
-async def api_create_assignment_task_submissions(
+@router.put("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions")
+async def api_handle_assignment_task_submissions(
request: Request,
- assignment_task_submission_object: AssignmentTaskSubmissionCreate,
+ assignment_task_submission_object: AssignmentTaskSubmissionUpdate,
assignment_task_uuid: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
@@ -251,7 +253,7 @@ async def api_create_assignment_task_submissions(
"""
Create new task submissions for an assignment
"""
- return await create_assignment_task_submission(
+ return await handle_assignment_task_submission(
request,
assignment_task_uuid,
assignment_task_submission_object,
@@ -275,6 +277,20 @@ async def api_read_user_assignment_task_submissions(
request, assignment_task_uuid, user_id, current_user, db_session
)
+@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/user/me")
+async def api_read_user_assignment_task_submissions_me(
+ request: Request,
+ assignment_task_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Read task submissions for an assignment from a user
+ """
+ return await read_user_assignment_task_submissions_me(
+ request, assignment_task_uuid, current_user, db_session
+ )
+
@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions")
async def api_read_assignment_task_submissions(
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index f8f196d6..ee96e6aa 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -19,6 +19,7 @@ from src.db.courses.assignments import (
AssignmentTaskSubmission,
AssignmentTaskSubmissionCreate,
AssignmentTaskSubmissionRead,
+ AssignmentTaskSubmissionUpdate,
AssignmentTaskUpdate,
AssignmentUpdate,
AssignmentUserSubmission,
@@ -464,7 +465,7 @@ async def put_assignment_task_reference_file(
status_code=404,
detail="Course not found",
)
-
+
# Get org uuid
org_statement = select(Organization).where(Organization.id == course.org_id)
org = db_session.exec(org_statement).first()
@@ -478,7 +479,13 @@ async def put_assignment_task_reference_file(
f"{assignment_task_uuid}{uuid4()}.{reference_file.filename.split('.')[-1]}"
)
await upload_reference_file(
- reference_file, name_in_disk, activity.activity_uuid, org.org_uuid, course.course_uuid, assignment.assignment_uuid, assignment_task_uuid
+ reference_file,
+ name_in_disk,
+ activity.activity_uuid,
+ org.org_uuid,
+ course.course_uuid,
+ assignment.assignment_uuid,
+ assignment_task_uuid,
)
course.thumbnail_image = name_in_disk
# Update reference file
@@ -494,6 +501,7 @@ async def put_assignment_task_reference_file(
# return assignment task read
return AssignmentTaskRead.model_validate(assignment_task)
+
async def put_assignment_task_submission_file(
request: Request,
db_session: Session,
@@ -536,7 +544,7 @@ async def put_assignment_task_submission_file(
status_code=404,
detail="Course not found",
)
-
+
# Get org uuid
org_statement = select(Organization).where(Organization.id == course.org_id)
org = db_session.exec(org_statement).first()
@@ -546,15 +554,18 @@ async def put_assignment_task_submission_file(
# Upload reference file
if sub_file and sub_file.filename and activity and org:
- name_in_disk = (
- f"{assignment_task_uuid}_sub_{current_user.email}_{uuid4()}.{sub_file.filename.split('.')[-1]}"
- )
+ name_in_disk = f"{assignment_task_uuid}_sub_{current_user.email}_{uuid4()}.{sub_file.filename.split('.')[-1]}"
await upload_submission_file(
- sub_file, name_in_disk, activity.activity_uuid, org.org_uuid, course.course_uuid, assignment.assignment_uuid, assignment_task_uuid
+ sub_file,
+ name_in_disk,
+ activity.activity_uuid,
+ org.org_uuid,
+ course.course_uuid,
+ assignment.assignment_uuid,
+ assignment_task_uuid,
)
- return {"message": "Assignment Task Submission File uploaded"}
-
+ return {"file_uuid": name_in_disk}
async def update_assignment_task(
@@ -665,13 +676,14 @@ async def delete_assignment_task(
## > Assignments Tasks Submissions CRUD
-async def create_assignment_task_submission(
+async def handle_assignment_task_submission(
request: Request,
assignment_task_uuid: str,
- assignment_task_submission_object: AssignmentTaskSubmissionCreate,
+ assignment_task_submission_object: AssignmentTaskSubmissionUpdate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
+ # TODO: Improve terrible implementation of this function
# Check if assignment task exists
statement = select(AssignmentTask).where(
AssignmentTask.assignment_task_uuid == assignment_task_uuid
@@ -694,51 +706,82 @@ async def create_assignment_task_submission(
detail="Assignment not found",
)
- # Check if course exists
- statement = select(Course).where(Course.id == assignment.course_id)
- course = db_session.exec(statement).first()
+ # Check if user already submitted the assignment
+ statement = select(AssignmentTaskSubmission).where(
+ AssignmentTaskSubmission.assignment_task_id == assignment_task.id,
+ AssignmentTaskSubmission.user_id == current_user.id,
+ )
+ assignment_task_submission = db_session.exec(statement).first()
- if not course:
- raise HTTPException(
- status_code=404,
- detail="Course not found",
+ # Update Task submission if it exists
+ if assignment_task_submission:
+ # Update only the fields that were passed in
+ for var, value in vars(assignment_task_submission_object).items():
+ if value is not None:
+ setattr(assignment_task_submission, var, value)
+ assignment_task_submission.update_date = str(datetime.now())
+
+ # Insert Assignment Task Submission in DB
+ db_session.add(assignment_task_submission)
+ db_session.commit()
+ db_session.refresh(assignment_task_submission)
+
+ # return assignment task submission read
+ return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
+
+ else:
+ # Create new Task submission
+ current_time = str(datetime.now())
+
+ # Assuming model_dump() returns a dictionary
+ model_data = assignment_task_submission_object.model_dump()
+
+ assignment_task_submission = AssignmentTaskSubmission(
+ assignment_task_submission_uuid=f"assignmenttasksubmission_{uuid4()}",
+ task_submission=model_data["task_submission"],
+ grade=model_data["grade"],
+ task_submission_grade_feedback=model_data["task_submission_grade_feedback"],
+ assignment_task_id=int(assignment_task.id), # type: ignore
+ assignment_type=assignment_task.assignment_type,
+ activity_id=assignment.activity_id,
+ course_id=assignment.course_id,
+ chapter_id=assignment.chapter_id,
+ user_id=current_user.id,
+ creation_date=current_time,
+ update_date=current_time,
)
- # RBAC check
- await rbac_check(request, course.course_uuid, current_user, "create", db_session)
+ # Insert Assignment Task Submission in DB
+ db_session.add(assignment_task_submission)
+ db_session.commit()
- # Create Assignment Task Submission
- assignment_task_submission = AssignmentTaskSubmission(
- **assignment_task_submission_object.model_dump()
- )
-
- assignment_task_submission.assignment_task_submission_uuid = str(
- f"assignmenttasksubmission_{uuid4()}"
- )
- assignment_task_submission.creation_date = str(datetime.now())
- assignment_task_submission.update_date = str(datetime.now())
- assignment_task_submission.org_id = course.org_id
-
- # Insert Assignment Task Submission in DB
- db_session.add(assignment_task_submission)
- db_session.commit()
- db_session.refresh(assignment_task_submission)
-
- # return assignment task submission read
- return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
+ # return assignment task submission read
+ return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
async def read_user_assignment_task_submissions(
request: Request,
- assignment_task_submission_uuid: str,
+ assignment_task_uuid: str,
user_id: int,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
+
+ # Check if assignment task exists
+ statement = select(AssignmentTask).where(
+ AssignmentTask.assignment_task_uuid == assignment_task_uuid
+ )
+ assignment_task = db_session.exec(statement).first()
+
+ if not assignment_task:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment Task not found",
+ )
+
# Check if assignment task submission exists
statement = select(AssignmentTaskSubmission).where(
- AssignmentTaskSubmission.assignment_task_submission_uuid
- == assignment_task_submission_uuid,
+ AssignmentTaskSubmission.assignment_task_id == assignment_task.id,
AssignmentTaskSubmission.user_id == user_id,
)
assignment_task_submission = db_session.exec(statement).first()
@@ -749,18 +792,6 @@ async def read_user_assignment_task_submissions(
detail="Assignment Task Submission not found",
)
- # Check if assignment task exists
- statement = select(AssignmentTask).where(
- AssignmentTask.id == assignment_task_submission.assignment_task_id
- )
- assignment_task = db_session.exec(statement).first()
-
- if not assignment_task:
- raise HTTPException(
- status_code=404,
- detail="Assignment Task not found",
- )
-
# Check if assignment exists
statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id)
assignment = db_session.exec(statement).first()
@@ -788,6 +819,21 @@ async def read_user_assignment_task_submissions(
return AssignmentTaskSubmissionRead.model_validate(assignment_task_submission)
+async def read_user_assignment_task_submissions_me(
+ request: Request,
+ assignment_task_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ return await read_user_assignment_task_submissions(
+ request,
+ assignment_task_uuid,
+ current_user.id,
+ current_user,
+ db_session,
+ )
+
+
async def read_assignment_task_submissions(
request: Request,
assignment_task_submission_uuid: str,
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
index 4aafcee3..c5d34976 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
@@ -2,13 +2,13 @@ import { useAssignments } from '@components/Contexts/Assignments/AssignmentConte
import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import { useLHSession } from '@components/Contexts/LHSessionContext';
import AssignmentBoxUI from '@components/Objects/Activities/Assignment/AssignmentBoxUI'
-import { getAssignmentTask, updateSubFile } from '@services/courses/assignments';
+import { getAssignmentTask, getAssignmentTaskSubmissionsMe, handleAssignmentTaskSubmission, updateSubFile } from '@services/courses/assignments';
import { Cloud, File, Info, Loader, UploadCloud } from 'lucide-react'
-import React, { useEffect } from 'react'
+import React, { useEffect, useState } from 'react'
import toast from 'react-hot-toast';
type FileSchema = {
- fileID: string;
+ fileUUID: string;
};
type TaskFileObjectProps = {
@@ -26,6 +26,18 @@ export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObj
const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any;
const assignment = useAssignments() as any;
+ /* TEACHER VIEW CODE */
+ /* TEACHER VIEW CODE */
+
+ /* STUDENT VIEW CODE */
+ const [showSavingDisclaimer, setShowSavingDisclaimer] = useState(false);
+ const [userSubmissions, setUserSubmissions] = useState({
+ fileUUID: '',
+ });
+ const [initialUserSubmissions, setInitialUserSubmissions] = useState({
+ fileUUID: '',
+ });
+
const handleFileChange = async (event: any) => {
const file = event.target.files[0]
@@ -37,19 +49,56 @@ export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObj
assignment.assignment_object.assignment_uuid,
access_token
)
- assignmentTaskStateHook({ type: 'reload' })
+
// wait for 1 second to show loading animation
await new Promise((r) => setTimeout(r, 1500))
if (res.success === false) {
+
setError(res.data.detail)
setIsLoading(false)
} else {
+ assignmentTaskStateHook({ type: 'reload' })
+ setUserSubmissions({
+ fileUUID: res.data.file_uuid,
+ })
setIsLoading(false)
setError('')
}
}
+ async function getAssignmentTaskSubmissionFromUserUI() {
+ if (assignmentTaskUUID) {
+ const res = await getAssignmentTaskSubmissionsMe(assignmentTaskUUID, assignment.assignment_object.assignment_uuid, access_token);
+ if (res.success) {
+ setUserSubmissions(res.data.task_submission);
+ setInitialUserSubmissions(res.data.task_submission);
+ }
+
+ }
+ }
+
+ const submitFC = async () => {
+ // Save the quiz to the server
+ const values = {
+ task_submission: userSubmissions,
+ grade: 0,
+ task_submission_grade_feedback: '',
+ };
+ if (assignmentTaskUUID) {
+ const res = await handleAssignmentTaskSubmission(values, assignmentTaskUUID, assignment.assignment_object.assignment_uuid, access_token);
+ if (res) {
+ assignmentTaskStateHook({
+ type: 'reload',
+ });
+ toast.success('Task saved successfully');
+ setShowSavingDisclaimer(false);
+ } else {
+ toast.error('Error saving task, please retry later.');
+ }
+ }
+ };
+
async function getAssignmentTaskUI() {
if (assignmentTaskUUID) {
const res = await getAssignmentTask(assignmentTaskUUID, access_token);
@@ -60,13 +109,27 @@ export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObj
}
}
+ // Detect changes between initial and current submissions
useEffect(() => {
- getAssignmentTaskUI()
+ if (userSubmissions.fileUUID !== initialUserSubmissions.fileUUID) {
+ setShowSavingDisclaimer(true);
+ } else {
+ setShowSavingDisclaimer(false);
+ }
+ }, [userSubmissions]);
+
+ /* STUDENT VIEW CODE */
+
+ useEffect(() => {
+ if (view === 'student') {
+ getAssignmentTaskUI()
+ getAssignmentTaskSubmissionFromUserUI()
+ }
}
, [assignmentTaskUUID])
return (
-
+
{view === 'teacher' && (
@@ -91,20 +154,35 @@ export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObj
-
+
-
-
- {localUploadFile.name}
+
+
+ {localUploadFile.name}
+
+
+ )}
+ {userSubmissions.fileUUID && !isLoading && !localUploadFile && (
+
+
+
+
+
+
+
+
+
+ {`${userSubmissions.fileUUID.slice(0, 8)}...${userSubmissions.fileUUID.slice(-4)}`}
+
)}
-
-
Allowed formats : pdf, docx, mp4, jpg, jpeg, pptx
-
+
+
Allowed formats : pdf, docx, mp4, jpg, jpeg, pptx
+
{isLoading ? (
+ {activity && activity.published == false && (
+
+
+
+ This activity is not published yet
+
+
+
+ )}
- {activity ? (
+ {activity && activity.published == true && (
@@ -173,8 +182,6 @@ function ActivityClient(props: ActivityClientProps) {
)}
- ) : (
-
)}
{
}
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/course.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/course.tsx
index 26a23c5c..fbf095de 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/course.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/course.tsx
@@ -12,7 +12,7 @@ import {
getCourseThumbnailMediaDirectory,
getUserAvatarMediaDirectory,
} from '@services/media/media'
-import { ArrowRight, Check, File, Sparkles, Video } from 'lucide-react'
+import { ArrowRight, Backpack, Check, File, Sparkles, Video } from 'lucide-react'
import { useOrg } from '@components/Contexts/OrgContext'
import UserAvatar from '@components/Objects/UserAvatar'
import CourseUpdates from '@components/Objects/CourseUpdates/CourseUpdates'
@@ -185,6 +185,15 @@ const CourseClient = (props: any) => {
/>
)}
+ {activity.activity_type ===
+ 'TYPE_ASSIGNMENT' && (
+
+
+
+ )}
{
>
)}
+ {activity.activity_type ===
+ 'TYPE_ASSIGNMENT' && (
+ <>
+
+
+
+ >
+ )}
>
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx
index 42255b16..55d44598 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskGeneralEdit.tsx
@@ -90,7 +90,7 @@ export function AssignmentTaskGeneralEdit() {
-
Allowed formats : pdf, docx, mp4, jpg, jpeg, pptx
+
Allowed formats : pdf, docx, mp4, jpg, jpeg, png, pptx
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
index c5d34976..ff338183 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
@@ -181,7 +181,7 @@ export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObj
)}
-
Allowed formats : pdf, docx, mp4, jpg, jpeg, pptx
+
Allowed formats : pdf, docx, mp4, jpg, jpeg, png, pptx
{isLoading ? (
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
index 6897009c..b87dceb2 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
@@ -305,7 +305,7 @@ function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
)}
- {view === 'teacher' && oIndex === question.options.length - 1 && (
+ {view === 'teacher' && oIndex === question.options.length - 1 && questions[qIndex].options.length <= 4 && (
))}
- {view === 'teacher' && (
+ {view === 'teacher' &&questions.length <= 5 && (
()
@@ -74,7 +75,8 @@ function PublishingState() {
async function updateAssignmentPublishState(assignmentUUID: string) {
const res = await updateAssignment({ published: !assignment?.assignment_object?.published }, assignmentUUID, access_token)
- if (res.success) {
+ const res2 = await updateActivity({ published: !assignment?.assignment_object?.published }, assignment?.activity_object?.activity_uuid, access_token)
+ if (res.success && res2) {
mutate(`${getAPIUrl()}assignments/${assignmentUUID}`)
toast.success('The assignment has been updated successfully')
}
@@ -84,7 +86,6 @@ function PublishingState() {
}
useEffect(() => {
- console.log('assignment', assignment)
}, [assignment])
return (
From e9caa2ceb4f86bbd3a0ba40f9f07f009a47a5384 Mon Sep 17 00:00:00 2001
From: swve
Date: Sat, 20 Jul 2024 20:10:43 +0200
Subject: [PATCH 17/25] feat: add assignment submission from the activity page
---
apps/api/src/db/courses/assignments.py | 22 +++--
apps/api/src/routers/courses/assignments.py | 21 ++++-
.../courses/activities/assignments.py | 48 ++++++++--
.../activity/[activityid]/activity.tsx | 93 +++++++++++++++++--
.../AssignmentSubmissionContext.tsx | 28 ++++++
.../Activities/Assignment/AssignmentBoxUI.tsx | 10 +-
apps/web/services/courses/assignments.ts | 14 +++
7 files changed, 207 insertions(+), 29 deletions(-)
create mode 100644 apps/web/components/Contexts/Assignments/AssignmentSubmissionContext.tsx
diff --git a/apps/api/src/db/courses/assignments.py b/apps/api/src/db/courses/assignments.py
index dc7722a5..a2884114 100644
--- a/apps/api/src/db/courses/assignments.py
+++ b/apps/api/src/db/courses/assignments.py
@@ -4,7 +4,6 @@ from sqlmodel import Field, SQLModel
from enum import Enum
-
## Assignment ##
class GradingTypeEnum(str, Enum):
ALPHABET = "ALPHABET"
@@ -87,7 +86,7 @@ class Assignment(AssignmentBase, table=True):
class AssignmentTaskTypeEnum(str, Enum):
FILE_SUBMISSION = "FILE_SUBMISSION"
QUIZ = "QUIZ"
- FORM = "FORM" # soon to be implemented
+ FORM = "FORM" # soon to be implemented
OTHER = "OTHER"
@@ -102,8 +101,6 @@ class AssignmentTaskBase(SQLModel):
contents: Dict = Field(default={}, sa_column=Column(JSON))
max_grade_value: int = 0 # Value is always between 0-100
-
-
class AssignmentTaskCreate(AssignmentTaskBase):
"""Model for creating a new assignment task."""
@@ -194,6 +191,7 @@ class AssignmentTaskSubmissionRead(AssignmentTaskSubmissionBase):
class AssignmentTaskSubmissionUpdate(SQLModel):
"""Model for updating an assignment task submission."""
+
assignment_task_id: Optional[int]
assignment_task_submission_uuid: Optional[str]
task_submission: Optional[Dict] = Field(default=None, sa_column=Column(JSON))
@@ -233,10 +231,12 @@ class AssignmentTaskSubmission(AssignmentTaskSubmissionBase, table=True):
creation_date: str
update_date: str
+
## AssignmentTaskSubmission ##
## AssignmentUserSubmission ##
+
class AssignmentUserSubmissionStatus(str, Enum):
PENDING = "PENDING"
SUBMITTED = "SUBMITTED"
@@ -248,11 +248,10 @@ class AssignmentUserSubmissionStatus(str, Enum):
class AssignmentUserSubmissionBase(SQLModel):
"""Represents the submission status of an assignment for a user."""
-
submission_status: AssignmentUserSubmissionStatus = (
AssignmentUserSubmissionStatus.PENDING
)
- grade: str
+ grade: int
user_id: int = Field(
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
)
@@ -262,11 +261,14 @@ class AssignmentUserSubmissionBase(SQLModel):
)
)
-class AssignmentUserSubmissionCreate(AssignmentUserSubmissionBase):
+
+class AssignmentUserSubmissionCreate(SQLModel):
"""Model for creating a new assignment user submission."""
+ assignment_id: int
pass # Inherits all fields from AssignmentUserSubmissionBase
+
class AssignmentUserSubmissionRead(AssignmentUserSubmissionBase):
"""Model for reading an assignment user submission."""
@@ -274,6 +276,7 @@ class AssignmentUserSubmissionRead(AssignmentUserSubmissionBase):
creation_date: str
update_date: str
+
class AssignmentUserSubmissionUpdate(SQLModel):
"""Model for updating an assignment user submission."""
@@ -282,17 +285,19 @@ class AssignmentUserSubmissionUpdate(SQLModel):
user_id: Optional[int]
assignment_id: Optional[int]
+
class AssignmentUserSubmission(AssignmentUserSubmissionBase, table=True):
"""Represents the submission status of an assignment for a user."""
id: Optional[int] = Field(default=None, primary_key=True)
creation_date: str
update_date: str
+ assignmentusersubmission_uuid: str
submission_status: AssignmentUserSubmissionStatus = (
AssignmentUserSubmissionStatus.PENDING
)
- grade: str
+ grade: int
user_id: int = Field(
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
)
@@ -301,4 +306,3 @@ class AssignmentUserSubmission(AssignmentUserSubmissionBase, table=True):
"assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
)
)
-
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index 3365ca94..8211b776 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -31,6 +31,7 @@ from src.services.courses.activities.assignments import (
read_assignment_task_submissions,
read_assignment_tasks,
read_user_assignment_submissions,
+ read_user_assignment_submissions_me,
read_user_assignment_task_submissions,
read_user_assignment_task_submissions_me,
update_assignment,
@@ -208,6 +209,7 @@ async def api_put_assignment_task_ref_file(
request, db_session, assignment_task_uuid, current_user, reference_file
)
+
@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/sub_file")
async def api_put_assignment_task_sub_file(
request: Request,
@@ -277,6 +279,7 @@ async def api_read_user_assignment_task_submissions(
request, assignment_task_uuid, user_id, current_user, db_session
)
+
@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/user/me")
async def api_read_user_assignment_task_submissions_me(
request: Request,
@@ -331,7 +334,6 @@ async def api_delete_assignment_task_submissions(
async def api_create_assignment_submissions(
request: Request,
assignment_uuid: str,
- assignment_submission: AssignmentUserSubmissionCreate,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
):
@@ -339,7 +341,7 @@ async def api_create_assignment_submissions(
Create new submissions for an assignment
"""
return await create_assignment_submission(
- request, assignment_uuid, assignment_submission, current_user, db_session
+ request, assignment_uuid, current_user, db_session
)
@@ -358,6 +360,21 @@ async def api_read_assignment_submissions(
)
+@router.get("/{assignment_uuid}/submissions/me")
+async def api_read_user_assignment_submission_me(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Read submissions for an assignment from the current user
+ """
+ return await read_user_assignment_submissions_me(
+ request, assignment_uuid, current_user, db_session
+ )
+
+
@router.get("/{assignment_uuid}/submissions/{user_id}")
async def api_read_user_assignment_submissions(
request: Request,
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index c29e84f3..447ec12b 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -7,6 +7,7 @@ from typing import Literal
from uuid import uuid4
from fastapi import HTTPException, Request, UploadFile
from sqlmodel import Session, select
+from sympy import Sum
from src.db.courses.activities import Activity
from src.db.courses.assignments import (
@@ -25,6 +26,7 @@ from src.db.courses.assignments import (
AssignmentUserSubmission,
AssignmentUserSubmissionCreate,
AssignmentUserSubmissionRead,
+ AssignmentUserSubmissionStatus,
)
from src.db.courses.courses import Course
from src.db.organizations import Organization
@@ -1028,7 +1030,6 @@ async def delete_assignment_task_submission(
async def create_assignment_submission(
request: Request,
assignment_uuid: str,
- assignment_user_submission_object: AssignmentUserSubmissionCreate,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
@@ -1045,7 +1046,7 @@ async def create_assignment_submission(
# Check if the submission has already been made
statement = select(AssignmentUserSubmission).where(
AssignmentUserSubmission.assignment_id == assignment.id,
- AssignmentUserSubmission.user_id == assignment_user_submission_object.user_id,
+ AssignmentUserSubmission.user_id == current_user.id,
)
assignment_user_submission = db_session.exec(statement).first()
@@ -1066,21 +1067,33 @@ async def create_assignment_submission(
detail="Course not found",
)
+ # Check if User already submitted the assignment
+ statement = select(AssignmentUserSubmission).where(
+ AssignmentUserSubmission.assignment_id == assignment.id,
+ AssignmentUserSubmission.user_id == current_user.id,
+ )
+ assignment_user_submission = db_session.exec(statement).first()
+
+ if assignment_user_submission:
+ raise HTTPException(
+ status_code=400,
+ detail="Assignment User Submission already exists",
+ )
+
# RBAC check
await rbac_check(request, course.course_uuid, current_user, "create", db_session)
# Create Assignment User Submission
assignment_user_submission = AssignmentUserSubmission(
- **assignment_user_submission_object.model_dump()
+ user_id=current_user.id,
+ assignment_id=assignment.id, # type: ignore
+ grade=0,
+ assignmentusersubmission_uuid=str(f"assignmentusersubmission_{uuid4()}"),
+ submission_status=AssignmentUserSubmissionStatus.PENDING,
+ creation_date=str(datetime.now()),
+ update_date=str(datetime.now()),
)
- assignment_user_submission.assignment_user_submission_uuid = str(
- f"assignmentusersubmission_{uuid4()}"
- )
- assignment_user_submission.creation_date = str(datetime.now())
- assignment_user_submission.update_date = str(datetime.now())
- assignment_user_submission.org_id = course.org_id
-
# Insert Assignment User Submission in DB
db_session.add(assignment_user_submission)
db_session.commit()
@@ -1173,6 +1186,21 @@ async def read_user_assignment_submissions(
]
+async def read_user_assignment_submissions_me(
+ request: Request,
+ assignment_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ return await read_user_assignment_submissions(
+ request,
+ assignment_uuid,
+ current_user.id,
+ current_user,
+ db_session,
+ )
+
+
async def update_assignment_submission(
request: Request,
user_id: str,
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
index d579d760..fe12ea9d 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
@@ -1,9 +1,9 @@
'use client'
import Link from 'next/link'
-import { getUriWithOrg } from '@services/config/config'
+import { getAPIUrl, getUriWithOrg } from '@services/config/config'
import Canva from '@components/Objects/Activities/DynamicCanva/DynamicCanva'
import VideoActivity from '@components/Objects/Activities/Video/Video'
-import { Check, MoreVertical } from 'lucide-react'
+import { BookOpenCheck, Check, MoreVertical, UserRoundPen } from 'lucide-react'
import { markActivityAsComplete } from '@services/courses/activity'
import DocumentPdfActivity from '@components/Objects/Activities/DocumentPdf/DocumentPdf'
import ActivityIndicators from '@components/Pages/Courses/ActivityIndicators'
@@ -17,10 +17,14 @@ import AIActivityAsk from '@components/Objects/Activities/AI/AIActivityAsk'
import AIChatBotProvider from '@components/Contexts/AI/AIChatBotContext'
import { useLHSession } from '@components/Contexts/LHSessionContext'
import React, { useEffect } from 'react'
-import { getAssignmentFromActivityUUID } from '@services/courses/assignments'
+import { getAssignmentFromActivityUUID, submitAssignmentForGrading } from '@services/courses/assignments'
import AssignmentStudentActivity from '@components/Objects/Activities/Assignment/AssignmentStudentActivity'
import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext'
import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext'
+import AssignmentSubmissionProvider, { AssignmentSubmissionContext, useAssignmentSubmission } from '@components/Contexts/Assignments/AssignmentSubmissionContext'
+import toast from 'react-hot-toast'
+import { mutate } from 'swr'
+import ConfirmationModal from '@components/StyledElements/ConfirmationModal/ConfirmationModal'
interface ActivityClientProps {
activityid: string
@@ -135,6 +139,21 @@ function ActivityClient(props: ActivityClientProps) {
/>
>
}
+ {activity.activity_type == 'TYPE_ASSIGNMENT' &&
+ <>
+
+
+
+
+
+ >
+ }
@@ -172,7 +191,9 @@ function ActivityClient(props: ActivityClientProps) {
{assignment ? (
-
+
+
+
) : (
@@ -225,7 +246,7 @@ export function MarkStatus(props: {
return (
<>
{isActivityCompleted() ? (
-
+
{' '}
@@ -233,7 +254,7 @@ export function MarkStatus(props: {
) : (
{' '}
@@ -247,4 +268,64 @@ export function MarkStatus(props: {
)
}
+function AssignmentTools(props: {
+ activity: any
+ activityid: string
+ course: any
+ orgslug: string
+ assignment: any
+}) {
+ const submission = useAssignmentSubmission() as any
+ const session = useLHSession() as any;
+
+ const submitForGradingUI = async () => {
+ if (props.assignment) {
+ const res = await submitAssignmentForGrading(
+ props.assignment?.assignment_uuid,
+ session.data?.tokens?.access_token
+ )
+ if (res.success) {
+ toast.success('Assignment submitted for grading')
+ mutate(`${getAPIUrl()}assignments/${props.assignment?.assignment_uuid}/submissions/me`,)
+ }
+ else {
+ toast.error('Failed to submit assignment for grading')
+ }
+ }
+ }
+
+ useEffect(() => {
+ }
+ , [submission, props.assignment])
+
+ return <>
+ {submission && submission.length == 0 && (
+
+
+
+ {' '}
+ Submit for grading
+
}
+ functionToExecute={() => submitForGradingUI()}
+ status="info"
+ />
+ )}
+ {submission && submission.length > 0 && (
+
+
+
+ {' '}
+ Grading in progress
+
)
+ }
+ >
+}
+
export default ActivityClient
diff --git a/apps/web/components/Contexts/Assignments/AssignmentSubmissionContext.tsx b/apps/web/components/Contexts/Assignments/AssignmentSubmissionContext.tsx
new file mode 100644
index 00000000..0fc36739
--- /dev/null
+++ b/apps/web/components/Contexts/Assignments/AssignmentSubmissionContext.tsx
@@ -0,0 +1,28 @@
+'use client'
+import React from 'react'
+import { useLHSession } from '../LHSessionContext'
+import { getAPIUrl } from '@services/config/config'
+import { swrFetcher } from '@services/utils/ts/requests'
+import useSWR from 'swr'
+
+export const AssignmentSubmissionContext = React.createContext({})
+
+function AssignmentSubmissionProvider({ children, assignment_uuid }: { children: React.ReactNode, assignment_uuid: string }) {
+ const session = useLHSession() as any
+ const accessToken = session?.data?.tokens?.access_token
+
+ const { data: assignmentSubmission, error: assignmentError } = useSWR(
+ `${getAPIUrl()}assignments/${assignment_uuid}/submissions/me`,
+ (url) => swrFetcher(url, accessToken)
+ )
+
+ return (
+
{children}
+ )
+}
+
+export function useAssignmentSubmission() {
+ return React.useContext(AssignmentSubmissionContext)
+}
+
+export default AssignmentSubmissionProvider
\ No newline at end of file
diff --git a/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
index 85f6d92c..4767a802 100644
--- a/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
+++ b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
@@ -1,5 +1,6 @@
+import { useAssignmentSubmission } from '@components/Contexts/Assignments/AssignmentSubmissionContext'
import { BookUser, EllipsisVertical, FileUp, Forward, Info, InfoIcon, ListTodo, Save } from 'lucide-react'
-import React from 'react'
+import React, { use, useEffect } from 'react'
type AssignmentBoxProps = {
type: 'quiz' | 'file'
@@ -12,6 +13,10 @@ type AssignmentBoxProps = {
}
function AssignmentBoxUI({ type, view, saveFC, submitFC, showSavingDisclaimer, children }: AssignmentBoxProps) {
+ const submission = useAssignmentSubmission() as any
+ useEffect(() => {
+ }
+ , [submission])
return (
@@ -47,6 +52,7 @@ function AssignmentBoxUI({ type, view, saveFC, submitFC, showSavingDisclaimer, c
Don't forget to save your progress
}
+
{/* Save button */}
{view === 'teacher' &&
Save
}
- {view === 'student' &&
+ {view === 'student' && submission.length <= 0 &&
submitFC && submitFC()}
className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-emerald-700 bg-emerald-300/20 hover:bg-emerald-300/10 hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-emerald-500/60'>
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
index b79b124f..bddf86fa 100644
--- a/apps/web/services/courses/assignments.ts
+++ b/apps/web/services/courses/assignments.ts
@@ -187,3 +187,17 @@ export async function updateSubFile(
const res = await getResponseMetadata(result)
return res
}
+
+// submissions
+
+export async function submitAssignmentForGrading(
+ assignmentUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/submissions`,
+ RequestBodyWithAuthHeader('POST', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
\ No newline at end of file
From dab80069d4793f7987bf0b1effaaa840c5f2cdea Mon Sep 17 00:00:00 2001
From: swve
Date: Sat, 20 Jul 2024 21:12:13 +0200
Subject: [PATCH 18/25] feat: init assignment subpages and misc python and ts
improvements
---
apps/api/migrations/env.py | 2 +-
apps/api/migrations/script.py.mako | 4 +-
.../versions/6295e05ff7d0_enum_updates.py | 4 +-
...95932_add_reference_for_assignmenttasks.py | 2 +-
.../df2981bf24dd_initial_migration.py | 4 +-
apps/api/src/db/courses/assignments.py | 2 +-
apps/api/src/routers/courses/assignments.py | 1 -
.../courses/activities/assignments.py | 3 +-
.../courses/activities/uploads/sub_file.py | 3 +-
.../activities/uploads/tasks_ref_files.py | 3 +-
apps/web/app/home/home.tsx | 3 -
.../activity/[activityid]/activity.tsx | 8 ++-
.../_components/TaskEditor/TaskEditor.tsx | 3 +-
.../assignments/[assignmentuuid]/page.tsx | 56 ++++++++++++-------
.../subpages/AssignmentEditorSubPage.tsx | 29 ++++++++++
.../subpages/AssignmentSubmissionsSubPage.tsx | 25 +++++++++
.../Assignments/AssignmentsTaskContext.tsx | 1 -
.../DraggableElements/ActivityElement.tsx | 3 -
.../Create/NewActivityModal/Assignment.tsx | 2 -
19 files changed, 109 insertions(+), 49 deletions(-)
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentEditorSubPage.tsx
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentSubmissionsSubPage.tsx
diff --git a/apps/api/migrations/env.py b/apps/api/migrations/env.py
index 08a2dd30..f4f75f2c 100644
--- a/apps/api/migrations/env.py
+++ b/apps/api/migrations/env.py
@@ -1,7 +1,7 @@
import importlib
from logging.config import fileConfig
import os
-import alembic_postgresql_enum
+import alembic_postgresql_enum # noqa: F401
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from sqlmodel import SQLModel
diff --git a/apps/api/migrations/script.py.mako b/apps/api/migrations/script.py.mako
index 6ce33510..0c1e80d5 100644
--- a/apps/api/migrations/script.py.mako
+++ b/apps/api/migrations/script.py.mako
@@ -8,8 +8,8 @@ Create Date: ${create_date}
from typing import Sequence, Union
from alembic import op
-import sqlalchemy as sa
-import sqlmodel
+import sqlalchemy as sa # noqa: F401
+import sqlmodel # noqa: F401
${imports if imports else ""}
# revision identifiers, used by Alembic.
diff --git a/apps/api/migrations/versions/6295e05ff7d0_enum_updates.py b/apps/api/migrations/versions/6295e05ff7d0_enum_updates.py
index 4ff2406e..762028ce 100644
--- a/apps/api/migrations/versions/6295e05ff7d0_enum_updates.py
+++ b/apps/api/migrations/versions/6295e05ff7d0_enum_updates.py
@@ -8,8 +8,8 @@ Create Date: 2024-07-11 20:46:26.582170
from typing import Sequence, Union
from alembic import op
-import sqlalchemy as sa
-import sqlmodel
+import sqlalchemy as sa # noqa: F401
+import sqlmodel # noqa: F401
from alembic_postgresql_enum import TableReference # type: ignore
# revision identifiers, used by Alembic.
diff --git a/apps/api/migrations/versions/d8bc71595932_add_reference_for_assignmenttasks.py b/apps/api/migrations/versions/d8bc71595932_add_reference_for_assignmenttasks.py
index 10634418..ae5c5e2a 100644
--- a/apps/api/migrations/versions/d8bc71595932_add_reference_for_assignmenttasks.py
+++ b/apps/api/migrations/versions/d8bc71595932_add_reference_for_assignmenttasks.py
@@ -9,7 +9,7 @@ from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
-import sqlmodel
+import sqlmodel # noqa: F401
# revision identifiers, used by Alembic.
diff --git a/apps/api/migrations/versions/df2981bf24dd_initial_migration.py b/apps/api/migrations/versions/df2981bf24dd_initial_migration.py
index a6a5be8a..7dac90ee 100644
--- a/apps/api/migrations/versions/df2981bf24dd_initial_migration.py
+++ b/apps/api/migrations/versions/df2981bf24dd_initial_migration.py
@@ -8,9 +8,9 @@ Create Date: 2024-07-11 19:33:37.993767
from typing import Sequence, Union
from alembic import op
-from grpc import server
+from grpc import server # noqa: F401
import sqlalchemy as sa
-import sqlmodel
+import sqlmodel # noqa: F401
# revision identifiers, used by Alembic.
diff --git a/apps/api/src/db/courses/assignments.py b/apps/api/src/db/courses/assignments.py
index a2884114..dd30b221 100644
--- a/apps/api/src/db/courses/assignments.py
+++ b/apps/api/src/db/courses/assignments.py
@@ -1,5 +1,5 @@
from typing import Optional, Dict
-from sqlalchemy import JSON, Column, ForeignKey, null
+from sqlalchemy import JSON, Column, ForeignKey
from sqlmodel import Field, SQLModel
from enum import Enum
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index 8211b776..ba3f30e4 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -3,7 +3,6 @@ from src.db.courses.assignments import (
AssignmentCreate,
AssignmentRead,
AssignmentTaskCreate,
- AssignmentTaskSubmissionCreate,
AssignmentTaskSubmissionUpdate,
AssignmentTaskUpdate,
AssignmentUpdate,
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index 447ec12b..14acb75b 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -7,7 +7,6 @@ from typing import Literal
from uuid import uuid4
from fastapi import HTTPException, Request, UploadFile
from sqlmodel import Session, select
-from sympy import Sum
from src.db.courses.activities import Activity
from src.db.courses.assignments import (
@@ -1172,7 +1171,7 @@ async def read_user_assignment_submissions(
# Find assignments tasks for an assignment
statement = select(AssignmentUserSubmission).where(
- assignment.assignment_uuid == assignment_uuid,
+ AssignmentUserSubmission.assignment_id == assignment.id,
AssignmentUserSubmission.user_id == user_id,
)
diff --git a/apps/api/src/services/courses/activities/uploads/sub_file.py b/apps/api/src/services/courses/activities/uploads/sub_file.py
index 48df3cc5..9ebd46f5 100644
--- a/apps/api/src/services/courses/activities/uploads/sub_file.py
+++ b/apps/api/src/services/courses/activities/uploads/sub_file.py
@@ -1,4 +1,3 @@
-from uuid import uuid4
from src.services.utils.upload_content import upload_content
@@ -12,7 +11,7 @@ async def upload_submission_file(
assignment_task_uuid,
):
contents = file.file.read()
- file_format = file.filename.split(".")[-1]
+ file.filename.split(".")[-1]
await upload_content(
f"courses/{course_uuid}/activities/{activity_uuid}/assignments/{assignment_uuid}/tasks/{assignment_task_uuid}/subs",
diff --git a/apps/api/src/services/courses/activities/uploads/tasks_ref_files.py b/apps/api/src/services/courses/activities/uploads/tasks_ref_files.py
index d9f7c128..56981cc0 100644
--- a/apps/api/src/services/courses/activities/uploads/tasks_ref_files.py
+++ b/apps/api/src/services/courses/activities/uploads/tasks_ref_files.py
@@ -1,4 +1,3 @@
-from uuid import uuid4
from src.services.utils.upload_content import upload_content
@@ -12,7 +11,7 @@ async def upload_reference_file(
assignment_task_uuid,
):
contents = file.file.read()
- file_format = file.filename.split(".")[-1]
+ file.filename.split(".")[-1]
await upload_content(
f"courses/{course_uuid}/activities/{activity_uuid}/assignments/{assignment_uuid}/tasks/{assignment_task_uuid}",
diff --git a/apps/web/app/home/home.tsx b/apps/web/app/home/home.tsx
index 6c5c83ae..6755a7c1 100644
--- a/apps/web/app/home/home.tsx
+++ b/apps/web/app/home/home.tsx
@@ -17,9 +17,6 @@ function HomeClient() {
const { data: orgs } = useSWR(`${getAPIUrl()}orgs/user/page/1/limit/10`, (url) => swrFetcher(url, access_token))
useEffect(() => {
- console.log(orgs)
-
-
}, [session, orgs])
return (
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
index fe12ea9d..d441b31c 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
@@ -8,7 +8,7 @@ import { markActivityAsComplete } from '@services/courses/activity'
import DocumentPdfActivity from '@components/Objects/Activities/DocumentPdf/DocumentPdf'
import ActivityIndicators from '@components/Pages/Courses/ActivityIndicators'
import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWrapper'
-import { useRouter } from 'next/navigation'
+import { usePathname, useRouter } from 'next/navigation'
import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement'
import { getCourseThumbnailMediaDirectory } from '@services/media/media'
import { useOrg } from '@components/Contexts/OrgContext'
@@ -42,6 +42,7 @@ function ActivityClient(props: ActivityClientProps) {
const course = props.course
const org = useOrg() as any
const session = useLHSession() as any;
+ const pathname = usePathname()
const access_token = session?.data?.tokens?.access_token;
const [bgColor, setBgColor] = React.useState('bg-white')
const [assignment, setAssignment] = React.useState(null) as any;
@@ -78,7 +79,7 @@ function ActivityClient(props: ActivityClientProps) {
setBgColor('bg-zinc-950');
}
}
- , [activity])
+ , [activity,pathname ])
return (
<>
@@ -126,6 +127,7 @@ function ActivityClient(props: ActivityClientProps) {
+ {activity && activity.published == true && (
{activity.activity_type != 'TYPE_ASSIGNMENT' &&
<>
@@ -141,7 +143,6 @@ function ActivityClient(props: ActivityClientProps) {
}
{activity.activity_type == 'TYPE_ASSIGNMENT' &&
<>
-
+ )}
{activity && activity.published == false && (
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx
index 09ba8d58..e5f910c5 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/TaskEditor.tsx
@@ -8,8 +8,9 @@ import { GalleryVerticalEnd, Info, TentTree, Trash } from 'lucide-react'
import React, { useEffect } from 'react'
import toast from 'react-hot-toast';
import { mutate } from 'swr';
+import dynamic from 'next/dynamic';
import { AssignmentTaskGeneralEdit } from './Subs/AssignmentTaskGeneralEdit';
-import AssignmentTaskContentEdit from './Subs/AssignmentTaskContentEdit';
+const AssignmentTaskContentEdit = dynamic(() => import('./Subs/AssignmentTaskContentEdit'))
function AssignmentTaskEditor({ page }: any) {
const [selectedSubPage, setSelectedSubPage] = React.useState(page)
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
index a31fd711..b4056e04 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
@@ -1,12 +1,9 @@
'use client';
import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'
-import { BookOpen, BookX, EllipsisVertical, Eye, LayoutList } from 'lucide-react'
+import { BookOpen, BookX, EllipsisVertical, Eye, Layers2, UserRoundPen } from 'lucide-react'
import React, { useEffect } from 'react'
import { AssignmentProvider, useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
-import AssignmentTasks from './_components/Tasks';
-import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import ToolTip from '@components/StyledElements/Tooltip/Tooltip';
-import AssignmentTaskEditor from './_components/TaskEditor/TaskEditor';
import { updateAssignment } from '@services/courses/assignments';
import { useLHSession } from '@components/Contexts/LHSessionContext';
import { mutate } from 'swr';
@@ -15,40 +12,59 @@ import toast from 'react-hot-toast';
import Link from 'next/link';
import { useParams } from 'next/navigation';
import { updateActivity } from '@services/courses/activities';
+// Lazy Loading
+import dynamic from 'next/dynamic';
+import AssignmentEditorSubPage from './subpages/AssignmentEditorSubPage';
+const AssignmentSubmissionsSubPage = dynamic(() => import('./subpages/AssignmentSubmissionsSubPage'))
function AssignmentEdit() {
const params = useParams<{ assignmentuuid: string; }>()
+ const [selectedSubPage, setSelectedSubPage] = React.useState('editor')
return (
-
+
-
Assignment Editor
+
Assignment Tools
+
+
setSelectedSubPage('editor')}
+ className={`flex space-x-4 py-2 w-fit text-center border-black transition-all ease-linear ${selectedSubPage === 'editor'
+ ? 'border-b-4'
+ : 'opacity-50'
+ } cursor-pointer`}
+ >
+
+
+
setSelectedSubPage('submissions')}
+ className={`flex space-x-4 py-2 w-fit text-center border-black transition-all ease-linear ${selectedSubPage === 'submissions'
+ ? 'border-b-4'
+ : 'opacity-50'
+ } cursor-pointer`}
+ >
+
+
+
-
-
-
-
+ {selectedSubPage === 'editor' &&
}
+ {selectedSubPage === 'submissions' &&
}
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentEditorSubPage.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentEditorSubPage.tsx
new file mode 100644
index 00000000..70756060
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentEditorSubPage.tsx
@@ -0,0 +1,29 @@
+'use client';
+import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext'
+import { LayoutList } from 'lucide-react'
+import React from 'react'
+import AssignmentTasks from '../_components/Tasks'
+import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext'
+import dynamic from 'next/dynamic';
+const AssignmentTaskEditor = dynamic(() => import('../_components/TaskEditor/TaskEditor'))
+
+function AssignmentEditorSubPage({ assignmentuuid }: { assignmentuuid: string }) {
+ return (
+
+
+
+
+ )
+}
+
+export default AssignmentEditorSubPage
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentSubmissionsSubPage.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentSubmissionsSubPage.tsx
new file mode 100644
index 00000000..c4266fe8
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentSubmissionsSubPage.tsx
@@ -0,0 +1,25 @@
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import { getAPIUrl } from '@services/config/config'
+import { swrFetcher } from '@services/utils/ts/requests';
+import React from 'react'
+import useSWR from 'swr';
+
+function AssignmentSubmissionsSubPage({ assignment_uuid }: { assignment_uuid: string }) {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+
+ const { data: assignmentSubmission, error: assignmentError } = useSWR(
+ `${getAPIUrl()}assignments/assignment_${assignment_uuid}/submissions`,
+ (url) => swrFetcher(url, access_token)
+ )
+ return (
+
+ {assignmentSubmission && assignmentSubmission.length > 0 && (
+
s
+ )}
+
+
+ )
+}
+
+export default AssignmentSubmissionsSubPage
\ No newline at end of file
diff --git a/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx b/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
index 32b69145..6cfeccfc 100644
--- a/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
+++ b/apps/web/components/Contexts/Assignments/AssignmentsTaskContext.tsx
@@ -78,7 +78,6 @@ export function useAssignmentsTaskDispatch() {
function assignmentstaskReducer(state: State, action: Action): State {
switch (action.type) {
case 'setSelectedAssignmentTaskUUID':
- console.log('st', action.payload)
return { ...state, selectedAssignmentTaskUUID: action.payload };
case 'setAssignmentTask':
return { ...state, assignmentTask: action.payload };
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
index 9a226bb0..3af1484a 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
@@ -254,9 +254,6 @@ const ActivityElementOptions = ({ activity }: any) => {
};
useEffect(() => {
-
- console.log(activity)
-
fetchAssignmentUUID();
}, [activity, course]);
diff --git a/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx b/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx
index 95abf80b..f69d7cbc 100644
--- a/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx
+++ b/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/Assignment.tsx
@@ -55,8 +55,6 @@ function NewAssignment({ submitActivity, chapterId, course, closeModal }: any) {
}
const activity_res = await createActivity(activity, chapterId, org?.id, session.data?.tokens?.access_token)
- console.log(course)
- console.log(activity_res)
await createAssignment({
title: activityName,
description: activityDescription,
From d6aa071425ed264c59a27e44cec897e64e3c37f1 Mon Sep 17 00:00:00 2001
From: swve
Date: Mon, 5 Aug 2024 19:45:24 +0200
Subject: [PATCH 19/25] feat: add publish status change from the course edition
page
---
apps/api/src/db/courses/assignments.py | 4 +-
apps/api/src/routers/courses/assignments.py | 4 +-
.../courses/activities/assignments.py | 4 +-
.../Subs/TaskTypes/TaskQuizObject.tsx | 349 +++++---
.../subpages/AssignmentSubmissionsSubPage.tsx | 136 ++-
.../subpages/Modals/EvaluateAssignment.tsx | 73 ++
.../DraggableElements/ActivityElement.tsx | 37 +-
.../Activities/Assignment/AssignmentBoxUI.tsx | 47 +-
.../components/StyledElements/Modal/Modal.tsx | 1 +
apps/web/package.json | 30 +-
apps/web/pnpm-lock.yaml | 809 +++++++++---------
apps/web/services/courses/assignments.ts | 16 +-
12 files changed, 929 insertions(+), 581 deletions(-)
create mode 100644 apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/Modals/EvaluateAssignment.tsx
diff --git a/apps/api/src/db/courses/assignments.py b/apps/api/src/db/courses/assignments.py
index dd30b221..aefd1ff9 100644
--- a/apps/api/src/db/courses/assignments.py
+++ b/apps/api/src/db/courses/assignments.py
@@ -249,7 +249,7 @@ class AssignmentUserSubmissionBase(SQLModel):
"""Represents the submission status of an assignment for a user."""
submission_status: AssignmentUserSubmissionStatus = (
- AssignmentUserSubmissionStatus.PENDING
+ AssignmentUserSubmissionStatus.SUBMITTED
)
grade: int
user_id: int = Field(
@@ -295,7 +295,7 @@ class AssignmentUserSubmission(AssignmentUserSubmissionBase, table=True):
assignmentusersubmission_uuid: str
submission_status: AssignmentUserSubmissionStatus = (
- AssignmentUserSubmissionStatus.PENDING
+ AssignmentUserSubmissionStatus.SUBMITTED
)
grade: int
user_id: int = Field(
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index ba3f30e4..91de1cbd 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -263,7 +263,7 @@ async def api_handle_assignment_task_submissions(
)
-@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/{user_id}")
+@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/user/{user_id}")
async def api_read_user_assignment_task_submissions(
request: Request,
assignment_task_uuid: str,
@@ -279,7 +279,7 @@ async def api_read_user_assignment_task_submissions(
)
-@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/user/me")
+@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/me")
async def api_read_user_assignment_task_submissions_me(
request: Request,
assignment_task_uuid: str,
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index 14acb75b..c66ffb3e 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -1088,7 +1088,7 @@ async def create_assignment_submission(
assignment_id=assignment.id, # type: ignore
grade=0,
assignmentusersubmission_uuid=str(f"assignmentusersubmission_{uuid4()}"),
- submission_status=AssignmentUserSubmissionStatus.PENDING,
+ submission_status=AssignmentUserSubmissionStatus.SUBMITTED,
creation_date=str(datetime.now()),
update_date=str(datetime.now()),
)
@@ -1129,7 +1129,7 @@ async def read_assignment_submissions(
# Find assignments tasks for an assignment
statement = select(AssignmentUserSubmission).where(
- assignment.assignment_uuid == assignment_uuid
+ AssignmentUserSubmission.assignment_id == assignment.id
)
# RBAC check
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
index b87dceb2..80460f35 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
@@ -2,8 +2,8 @@ import { useAssignments } from '@components/Contexts/Assignments/AssignmentConte
import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import { useLHSession } from '@components/Contexts/LHSessionContext';
import AssignmentBoxUI from '@components/Objects/Activities/Assignment/AssignmentBoxUI';
-import { getAssignmentTask, getAssignmentTaskSubmissionsMe, handleAssignmentTaskSubmission, updateAssignmentTask } from '@services/courses/assignments';
-import { Check, Minus, Plus, PlusCircle, X } from 'lucide-react';
+import { getAssignmentTask, getAssignmentTaskSubmissionsMe, getAssignmentTaskSubmissionsUser, handleAssignmentTaskSubmission, updateAssignmentTask } from '@services/courses/assignments';
+import { Check, Info, Minus, Plus, PlusCircle, X } from 'lucide-react';
import React, { useEffect, useState } from 'react';
import toast from 'react-hot-toast';
import { v4 as uuidv4 } from 'uuid';
@@ -29,11 +29,12 @@ type QuizSubmitSchema = {
};
type TaskQuizObjectProps = {
- view: 'teacher' | 'student';
+ view: 'teacher' | 'student' | 'grading';
+ user_id?: string; // Only for read-only view
assignmentTaskUUID?: string;
};
-function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
+function TaskQuizObject({ view, assignmentTaskUUID, user_id }: TaskQuizObjectProps) {
const session = useLHSession() as any;
const access_token = session?.data?.tokens?.access_token;
const assignmentTaskState = useAssignmentsTask() as any;
@@ -118,6 +119,7 @@ function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
submissions: [],
});
const [showSavingDisclaimer, setShowSavingDisclaimer] = useState(false);
+ const [assignmentTaskOutsideProvider, setAssignmentTaskOutsideProvider] = useState(null);
async function chooseOption(qIndex: number, oIndex: number) {
const updatedSubmissions = [...userSubmissions.submissions];
@@ -147,6 +149,7 @@ function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
if (assignmentTaskUUID) {
const res = await getAssignmentTask(assignmentTaskUUID, access_token);
if (res.success) {
+ setAssignmentTaskOutsideProvider(res.data);
setQuestions(res.data.contents.questions);
}
@@ -164,11 +167,11 @@ function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
}
}
- // Detect changes between initial and current submissions
- useEffect(() => {
- const hasChanges = JSON.stringify(initialUserSubmissions.submissions) !== JSON.stringify(userSubmissions.submissions);
- setShowSavingDisclaimer(hasChanges);
- }, [userSubmissions, initialUserSubmissions.submissions]);
+ // Detect changes between initial and current submissions
+ useEffect(() => {
+ const hasChanges = JSON.stringify(initialUserSubmissions.submissions) !== JSON.stringify(userSubmissions.submissions);
+ setShowSavingDisclaimer(hasChanges);
+ }, [userSubmissions, initialUserSubmissions.submissions]);
@@ -193,10 +196,57 @@ function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
}
};
-
-
/* STUDENT VIEW CODE */
+ /* GRADING VIEW CODE */
+ const [userSubmissionObject, setUserSubmissionObject] = useState(null);
+ async function getAssignmentTaskSubmissionFromIdentifiedUserUI() {
+ if (assignmentTaskUUID && user_id) {
+ const res = await getAssignmentTaskSubmissionsUser(assignmentTaskUUID, user_id, assignment.assignment_object.assignment_uuid, access_token);
+ if (res.success) {
+ setUserSubmissions(res.data.task_submission);
+ setUserSubmissionObject(res.data);
+ setInitialUserSubmissions(res.data.task_submission);
+ }
+
+ }
+ }
+
+ async function gradeFC() {
+ if (assignmentTaskUUID) {
+ // Ensure maxPoints is defined
+ const maxPoints = assignmentTaskOutsideProvider?.max_grade_value || 100; // Default to 100 if not defined
+
+ // Ensure userSubmissions.questions are set
+ const totalQuestions = questions.length;
+ const correctQuestions = userSubmissions.submissions.filter((submission) => {
+ const question = questions.find((q) => q.questionUUID === submission.questionUUID);
+ const option = question?.options.find((o) => o.optionUUID === submission.optionUUID);
+ return option?.correct;
+ }).length;
+
+ // Calculate grade based on correct questions
+ const grade = Math.floor((correctQuestions / totalQuestions) * maxPoints);
+
+ // Save the grade to the server
+ const values = {
+ task_submission: userSubmissions,
+ grade,
+ task_submission_grade_feedback: 'Auto graded by system',
+ };
+
+ const res = await handleAssignmentTaskSubmission(values, assignmentTaskUUID, assignment.assignment_object.assignment_uuid, access_token);
+ if (res) {
+ getAssignmentTaskSubmissionFromIdentifiedUserUI();
+ toast.success(`Task graded successfully with ${grade} points`);
+ } else {
+ toast.error('Error grading task, please retry later.');
+ }
+ }
+ }
+
+ /* GRADING VIEW CODE */
+
useEffect(() => {
assignmentTaskStateHook({
setSelectedAssignmentTaskUUID: assignmentTaskUUID,
@@ -210,131 +260,180 @@ function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) {
getAssignmentTaskUI();
getAssignmentTaskSubmissionFromUserUI();
}
+
+ // Grading area
+ else if (view == 'grading') {
+ getAssignmentTaskUI();
+ //setQuestions(assignmentTaskState.assignmentTask.contents.questions);
+ getAssignmentTaskSubmissionFromIdentifiedUserUI();
+
+ }
}, [assignmentTaskState, assignment, assignmentTaskStateHook, access_token]);
-
- return (
-
-
- {questions && questions.map((question, qIndex) => (
-
-
- {view === 'teacher' ? (
-
handleQuestionChange(qIndex, e.target.value)}
- placeholder="Question"
- className="w-full px-3 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold"
- />
- ) : (
-
- {question.questionText}
-
- )}
- {view === 'teacher' && (
-
removeQuestion(qIndex)}
- >
-
-
- )}
-
-
- {question.options.map((option, oIndex) => (
-
+ if (questions && questions.length >= 0) {
+ return (
+
+
+ {questions && questions.map((question, qIndex) => (
+
+
+ {view === 'teacher' ? (
+
handleQuestionChange(qIndex, e.target.value)}
+ placeholder="Question"
+ className="w-full px-3 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold"
+ />
+ ) : (
+
+ {question.questionText}
+
+ )}
+ {view === 'teacher' && (
view === 'student' && chooseOption(qIndex, oIndex)}
- className={"answer outline outline-3 outline-white pr-2 shadow w-full flex items-center space-x-2 h-[30px] hover:bg-opacity-100 hover:shadow-md rounded-lg bg-white text-sm duration-150 cursor-pointer ease-linear nice-shadow " + (view == 'student' ? 'active:scale-110' : '')}
+ className="w-[20px] flex-none flex items-center h-[20px] rounded-lg bg-slate-200/60 text-slate-500 hover:bg-slate-300 text-sm transition-all ease-linear cursor-pointer"
+ onClick={() => removeQuestion(qIndex)}
>
-
-
{String.fromCharCode(65 + oIndex)}
-
- {view === 'teacher' ? (
-
handleOptionChange(qIndex, oIndex, e.target.value)}
- placeholder="Option"
- className="w-full mx-2 px-3 pr-6 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold"
- />
- ) : (
-
- {option.text}
-
- )}
- {view === 'teacher' && (
- <>
-
toggleCorrectOption(qIndex, oIndex)}
- >
- {option.correct ?
:
}
- {option.correct ? (
-
Correct
- ) : (
-
Incorrect
- )}
-
-
removeOption(qIndex, oIndex)}
- >
-
-
- >
- )}
- {view === 'student' && (
-
- submission.questionUUID === question.questionUUID && submission.optionUUID === option.optionUUID
- )
- ? "bg-green-200/60 text-green-500 hover:bg-green-300" // Selected state colors
- : "bg-slate-200/60 text-slate-500 hover:bg-slate-300" // Default state colors
- } text-sm transition-all ease-linear cursor-pointer`}>
- {userSubmissions.submissions.find(
+
+
+ )}
+
+
+ {question.options.map((option, oIndex) => (
+
+
view === 'student' && chooseOption(qIndex, oIndex)}
+ className={"answer outline outline-3 outline-white pr-2 shadow w-full flex items-center space-x-2 h-[30px] hover:bg-opacity-100 hover:shadow-md rounded-lg bg-white text-sm duration-150 cursor-pointer ease-linear nice-shadow " + (view == 'student' ? 'active:scale-110' : '')}
+ >
+
+
{String.fromCharCode(65 + oIndex)}
+
+ {view === 'teacher' ? (
+
handleOptionChange(qIndex, oIndex, e.target.value)}
+ placeholder="Option"
+ className="w-full mx-2 px-3 pr-6 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold"
+ />
+ ) : (
+
+ {option.text}
+
+ )}
+ {view === 'teacher' && (
+ <>
+
toggleCorrectOption(qIndex, oIndex)}
+ >
+ {option.correct ?
:
}
+ {option.correct ? (
+
Correct
+ ) : (
+
Incorrect
+ )}
+
+
removeOption(qIndex, oIndex)}
+ >
+
+
+ >
+ )}
+ {view === 'grading' && (
+ <>
+
+ {option.correct ?
:
}
+ {option.correct ? (
+
Marked as Correct
+ ) : (
+
Marked as Incorrect
+ )}
+
+
+ >
+ )}
+ {view === 'student' && (
+
submission.questionUUID === question.questionUUID && submission.optionUUID === option.optionUUID
- ) ? (
-
- ) : (
-
- )}
+ )
+ ? "bg-green-200/60 text-green-500 hover:bg-green-300" // Selected state colors
+ : "bg-slate-200/60 text-slate-500 hover:bg-slate-300" // Default state colors
+ } text-sm transition-all ease-linear cursor-pointer`}>
+ {userSubmissions.submissions.find(
+ (submission) =>
+ submission.questionUUID === question.questionUUID && submission.optionUUID === option.optionUUID
+ ) ? (
+
+ ) : (
+
+ )}
+
+ )}
+ {view === 'grading' && (
+
+ submission.questionUUID === question.questionUUID && submission.optionUUID === option.optionUUID
+ )
+ ? "bg-green-200/60 text-green-500 hover:bg-green-300" // Selected state colors
+ : "bg-slate-200/60 text-slate-500 hover:bg-slate-300" // Default state colors
+ } text-sm transition-all ease-linear cursor-pointer`}>
+ {userSubmissions.submissions.find(
+ (submission) =>
+ submission.questionUUID === question.questionUUID && submission.optionUUID === option.optionUUID
+ ) ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+
+ {view === 'teacher' && oIndex === question.options.length - 1 && questions[qIndex].options.length <= 4 && (
+
+
addOption(qIndex)}
+ >
+
+
+
)}
-
- {view === 'teacher' && oIndex === question.options.length - 1 && questions[qIndex].options.length <= 4 && (
-
-
addOption(qIndex)}
- >
-
-
-
-
- )}
-
- ))}
+ ))}
+
+
+ ))}
+
+ {view === 'teacher' && questions.length <= 5 && (
+
- ))}
-
- {view === 'teacher' &&questions.length <= 5 && (
-
- )}
-
- );
+ )}
+
+ );
+ }
+ else {
+ return
;
+ }
}
export default TaskQuizObject;
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentSubmissionsSubPage.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentSubmissionsSubPage.tsx
index c4266fe8..35e1f73a 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentSubmissionsSubPage.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/AssignmentSubmissionsSubPage.tsx
@@ -1,8 +1,16 @@
import { useLHSession } from '@components/Contexts/LHSessionContext';
-import { getAPIUrl } from '@services/config/config'
+import UserAvatar from '@components/Objects/UserAvatar';
+import Modal from '@components/StyledElements/Modal/Modal';
+import { getAPIUrl } from '@services/config/config';
+import { getUserAvatarMediaDirectory } from '@services/media/media';
import { swrFetcher } from '@services/utils/ts/requests';
-import React from 'react'
+import { Loader, SendHorizonal, UserCheck, X } from 'lucide-react';
+import React, { useEffect } from 'react';
import useSWR from 'swr';
+import EvaluateAssignment from './Modals/EvaluateAssignment';
+import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext';
+import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext';
+import AssignmentSubmissionProvider from '@components/Contexts/Assignments/AssignmentSubmissionContext';
function AssignmentSubmissionsSubPage({ assignment_uuid }: { assignment_uuid: string }) {
const session = useLHSession() as any;
@@ -11,15 +19,123 @@ function AssignmentSubmissionsSubPage({ assignment_uuid }: { assignment_uuid: st
const { data: assignmentSubmission, error: assignmentError } = useSWR(
`${getAPIUrl()}assignments/assignment_${assignment_uuid}/submissions`,
(url) => swrFetcher(url, access_token)
- )
- return (
-
- {assignmentSubmission && assignmentSubmission.length > 0 && (
-
s
- )}
+ );
+ useEffect(() => {
+ console.log(assignmentSubmission);
+ }, [session, assignmentSubmission]);
+
+ const renderSubmissions = (status: string) => {
+ return assignmentSubmission
+ ?.filter((submission: any) => submission.submission_status === status)
+ .map((submission: any) => (
+
+ ));
+ };
+
+ return (
+
+
+
+
+
+
Late
+
+ {renderSubmissions('LATE')}
+
+
+
+
+
Submitted
+
+ {renderSubmissions('SUBMITTED')}
+
+
+
+
+
Graded
+
+ {renderSubmissions('GRADED')}
+
+
+
- )
+ );
}
-export default AssignmentSubmissionsSubPage
\ No newline at end of file
+function SubmissionBox({ assignment_uuid, user_id, submission }: any) {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const [gradeSudmissionModal, setGradeSubmissionModal] = React.useState({
+ open: false,
+ submission_id: '',
+ });
+
+ const { data: user, error: userError } = useSWR(
+ `${getAPIUrl()}users/id/${user_id}`,
+ (url) => swrFetcher(url, access_token)
+ );
+
+ useEffect(() => {
+ console.log(user);
+ }
+ , [session, user]);
+
+ return (
+
+
+
+
Submission
+
+ {new Date(submission.creation_date).toLocaleDateString('en-UK', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ })}
+
+
+
+
+
+
+ {user?.first_name && user?.last_name ? (
{user?.first_name} {user?.last_name}
) : (
@{user?.username}
)}
+
{user?.email}
+
+
+
+
+
setGradeSubmissionModal({ open, submission_id: submission.submission_uuid })}
+ minHeight="lg"
+ minWidth="lg"
+ dialogContent={
+
+
+
+
+
+
+
+ }
+ dialogTitle={`Evaluate @${user?.username}`}
+ dialogDescription="Evaluate the submission"
+ dialogTrigger={
+
+ Evaluate
+
+ }
+ />
+
+
+
+
+ );
+}
+
+export default AssignmentSubmissionsSubPage;
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/Modals/EvaluateAssignment.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/Modals/EvaluateAssignment.tsx
new file mode 100644
index 00000000..0ef0ac9a
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/Modals/EvaluateAssignment.tsx
@@ -0,0 +1,73 @@
+import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
+import { Download, Info, Medal } from 'lucide-react';
+import Link from 'next/link';
+import React from 'react'
+import TaskQuizObject from '../../_components/TaskEditor/Subs/TaskTypes/TaskQuizObject';
+import TaskFileObject from '../../_components/TaskEditor/Subs/TaskTypes/TaskFileObject';
+import { useOrg } from '@components/Contexts/OrgContext';
+import { getTaskRefFileDir } from '@services/media/media';
+
+function EvaluateAssignment({ user_id }: any) {
+ const assignments = useAssignments() as any;
+ const org = useOrg() as any;
+
+ console.log(assignments);
+ return (
+
+ {assignments && assignments?.assignment_tasks?.sort((a: any, b: any) => a.id - b.id).map((task: any, index: number) => {
+ return (
+
+
+
+
Task {index + 1} :
+
{task.description}
+
+
+
alert(task.hint)}
+ className='px-3 py-1 flex items-center nice-shadow bg-amber-50/40 text-amber-900 rounded-full space-x-2 cursor-pointer'>
+
+
View Hint
+
+
+
+
+ {task.reference_file && (
+
+
+
+ )}
+
Reference Document
+
+
+
+
+
+ {task.assignment_type === 'QUIZ' && }
+ {task.assignment_type === 'FILE_SUBMISSION' && }
+
+
+ )
+ })}
+
+
+
+
+ )
+}
+
+export default EvaluateAssignment
\ No newline at end of file
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
index 3af1484a..bfb43372 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
@@ -7,6 +7,8 @@ import {
Eye,
File,
FilePenLine,
+ Globe,
+ Lock,
MoreVertical,
Pencil,
Save,
@@ -60,6 +62,19 @@ function ActivityElement(props: ActivitiyElementProps) {
router.refresh()
}
+ async function changePublicStatus() {
+ await updateActivity(
+ {
+ published: !props.activity.published,
+ },
+ props.activity.activity_uuid,
+ access_token
+ )
+ mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`)
+ await revalidateTags(['courses'], props.orgslug)
+ router.refresh()
+ }
+
async function updateActivityName(activityId: string) {
if (
modifiedActivity?.activityId === activityId &&
@@ -134,9 +149,27 @@ function ActivityElement(props: ActivitiyElementProps) {
className="text-neutral-400 hover:cursor-pointer"
/>
+
+
{/* Edit and View Button */}
+ {/* Publishing */}
+
changePublicStatus()}
+ >
+ {!props.activity.published ? (
+
+ ) : (
+
+ )}
+ {!props.activity.published ? 'Publish' : 'UnPublish'}
+
-
+
Preview
diff --git a/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
index 4767a802..3b3d152d 100644
--- a/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
+++ b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
@@ -1,22 +1,25 @@
import { useAssignmentSubmission } from '@components/Contexts/Assignments/AssignmentSubmissionContext'
-import { BookUser, EllipsisVertical, FileUp, Forward, Info, InfoIcon, ListTodo, Save } from 'lucide-react'
-import React, { use, useEffect } from 'react'
+import { BookPlus, BookUser, EllipsisVertical, FileUp, Forward, InfoIcon, ListTodo, Save } from 'lucide-react'
+import React, { useEffect } from 'react'
type AssignmentBoxProps = {
type: 'quiz' | 'file'
- view?: 'teacher' | 'student'
+ view?: 'teacher' | 'student' | 'grading'
+ maxPoints?: number
+ currentPoints?: number
saveFC?: () => void
submitFC?: () => void
+ gradeFC?: () => void
showSavingDisclaimer?: boolean
children: React.ReactNode
}
-function AssignmentBoxUI({ type, view, saveFC, submitFC, showSavingDisclaimer, children }: AssignmentBoxProps) {
+function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitFC, gradeFC, showSavingDisclaimer, children }: AssignmentBoxProps) {
const submission = useAssignmentSubmission() as any
useEffect(() => {
}
- , [submission])
+ , [submission])
return (
@@ -44,16 +47,22 @@ function AssignmentBoxUI({ type, view, saveFC, submitFC, showSavingDisclaimer, c
Teacher view
}
+ {maxPoints &&
+
+ }
- {showSavingDisclaimer &&
-
-
-
Don't forget to save your progress
-
+ {showSavingDisclaimer &&
+
+
+
Don't forget to save your progress
+
}
- {/* Save button */}
+ {/* Teacher button */}
{view === 'teacher' &&
saveFC && saveFC()}
@@ -62,7 +71,9 @@ function AssignmentBoxUI({ type, view, saveFC, submitFC, showSavingDisclaimer, c
Save
}
- {view === 'student' && submission.length <= 0 &&
+
+ {/* Student button */}
+ {view === 'student' && submission && submission.length <= 0 &&
submitFC && submitFC()}
className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-emerald-700 bg-emerald-300/20 hover:bg-emerald-300/10 hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-emerald-500/60'>
@@ -71,6 +82,18 @@ function AssignmentBoxUI({ type, view, saveFC, submitFC, showSavingDisclaimer, c
}
+ {/* Grading button */}
+ {view === 'grading' &&
+
gradeFC && gradeFC()}
+ className='flex px-0.5 py-0.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
+
Current points : {currentPoints}
+
+
+ }
{children}
diff --git a/apps/web/components/StyledElements/Modal/Modal.tsx b/apps/web/components/StyledElements/Modal/Modal.tsx
index 0b1ca9c7..b78350ec 100644
--- a/apps/web/components/StyledElements/Modal/Modal.tsx
+++ b/apps/web/components/StyledElements/Modal/Modal.tsx
@@ -82,6 +82,7 @@ const contentClose = keyframes({
const DialogOverlay = styled(Dialog.Overlay, {
backgroundColor: blackA.blackA9,
+ backdropFilter: 'blur(0.6px)',
position: 'fixed',
zIndex: 500,
inset: 0,
diff --git a/apps/web/package.json b/apps/web/package.json
index 13591031..bca7fdd9 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -20,25 +20,25 @@
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"@stitches/react": "^1.2.8",
- "@tiptap/core": "^2.5.4",
- "@tiptap/extension-code-block-lowlight": "^2.5.4",
- "@tiptap/extension-collaboration": "^2.5.4",
- "@tiptap/extension-collaboration-cursor": "^2.5.4",
- "@tiptap/extension-youtube": "^2.5.4",
- "@tiptap/html": "^2.5.4",
- "@tiptap/pm": "^2.5.4",
- "@tiptap/react": "^2.5.4",
- "@tiptap/starter-kit": "^2.5.4",
+ "@tiptap/core": "^2.5.8",
+ "@tiptap/extension-code-block-lowlight": "^2.5.8",
+ "@tiptap/extension-collaboration": "^2.5.8",
+ "@tiptap/extension-collaboration-cursor": "^2.5.8",
+ "@tiptap/extension-youtube": "^2.5.8",
+ "@tiptap/html": "^2.5.8",
+ "@tiptap/pm": "^2.5.8",
+ "@tiptap/react": "^2.5.8",
+ "@tiptap/starter-kit": "^2.5.8",
"@types/randomcolor": "^0.5.9",
"avvvatars-react": "^0.4.2",
- "dayjs": "^1.11.11",
+ "dayjs": "^1.11.12",
"formik": "^2.4.6",
"framer-motion": "^10.18.0",
"get-youtube-id": "^1.0.1",
"highlight.js": "^11.10.0",
"katex": "^0.16.11",
"lowlight": "^3.1.0",
- "lucide-react": "^0.408.0",
+ "lucide-react": "^0.424.0",
"next": "14.2.5",
"next-auth": "^4.24.7",
"nextjs-toploader": "^1.6.12",
@@ -60,7 +60,7 @@
"tailwind-scrollbar": "^3.1.0",
"uuid": "^9.0.1",
"y-indexeddb": "^9.0.12",
- "y-prosemirror": "^1.2.9",
+ "y-prosemirror": "^1.2.11",
"y-webrtc": "^10.3.0",
"yjs": "^13.6.18"
},
@@ -73,12 +73,12 @@
"@types/react-transition-group": "^4.4.10",
"@types/styled-components": "^5.1.34",
"@types/uuid": "^9.0.8",
- "autoprefixer": "^10.4.19",
+ "autoprefixer": "^10.4.20",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.5",
"eslint-plugin-unused-imports": "^3.2.0",
- "postcss": "^8.4.39",
- "tailwindcss": "^3.4.6",
+ "postcss": "^8.4.40",
+ "tailwindcss": "^3.4.7",
"typescript": "5.4.4"
}
}
diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml
index 986953f2..e095c99c 100644
--- a/apps/web/pnpm-lock.yaml
+++ b/apps/web/pnpm-lock.yaml
@@ -36,32 +36,32 @@ importers:
specifier: ^1.2.8
version: 1.2.8(react@18.3.1)
'@tiptap/core':
- specifier: ^2.5.4
- version: 2.5.4(@tiptap/pm@2.5.4)
+ specifier: ^2.5.8
+ version: 2.5.8(@tiptap/pm@2.5.8)
'@tiptap/extension-code-block-lowlight':
- specifier: ^2.5.4
- version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/extension-code-block@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
+ specifier: ^2.5.8
+ version: 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/extension-code-block@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)
'@tiptap/extension-collaboration':
- specifier: ^2.5.4
- version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)(y-prosemirror@1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))
+ specifier: ^2.5.8
+ version: 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)(y-prosemirror@1.2.11(prosemirror-model@1.22.2)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))
'@tiptap/extension-collaboration-cursor':
- specifier: ^2.5.4
- version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(y-prosemirror@1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))
+ specifier: ^2.5.8
+ version: 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(y-prosemirror@1.2.11(prosemirror-model@1.22.2)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))
'@tiptap/extension-youtube':
- specifier: ^2.5.4
- version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ specifier: ^2.5.8
+ version: 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
'@tiptap/html':
- specifier: ^2.5.4
- version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
+ specifier: ^2.5.8
+ version: 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)
'@tiptap/pm':
- specifier: ^2.5.4
- version: 2.5.4
+ specifier: ^2.5.8
+ version: 2.5.8
'@tiptap/react':
- specifier: ^2.5.4
- version: 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: ^2.5.8
+ version: 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@tiptap/starter-kit':
- specifier: ^2.5.4
- version: 2.5.4(@tiptap/pm@2.5.4)
+ specifier: ^2.5.8
+ version: 2.5.8(@tiptap/pm@2.5.8)
'@types/randomcolor':
specifier: ^0.5.9
version: 0.5.9
@@ -69,8 +69,8 @@ importers:
specifier: ^0.4.2
version: 0.4.2(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
dayjs:
- specifier: ^1.11.11
- version: 1.11.11
+ specifier: ^1.11.12
+ version: 1.11.12
formik:
specifier: ^2.4.6
version: 2.4.6(react@18.3.1)
@@ -90,8 +90,8 @@ importers:
specifier: ^3.1.0
version: 3.1.0
lucide-react:
- specifier: ^0.408.0
- version: 0.408.0(react@18.3.1)
+ specifier: ^0.424.0
+ version: 0.424.0(react@18.3.1)
next:
specifier: 14.2.5
version: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -148,7 +148,7 @@ importers:
version: 2.4.0
tailwind-scrollbar:
specifier: ^3.1.0
- version: 3.1.0(tailwindcss@3.4.6)
+ version: 3.1.0(tailwindcss@3.4.7)
uuid:
specifier: ^9.0.1
version: 9.0.1
@@ -156,8 +156,8 @@ importers:
specifier: ^9.0.12
version: 9.0.12(yjs@13.6.18)
y-prosemirror:
- specifier: ^1.2.9
- version: 1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
+ specifier: ^1.2.11
+ version: 1.2.11(prosemirror-model@1.22.2)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
y-webrtc:
specifier: ^10.3.0
version: 10.3.0(yjs@13.6.18)
@@ -190,8 +190,8 @@ importers:
specifier: ^9.0.8
version: 9.0.8
autoprefixer:
- specifier: ^10.4.19
- version: 10.4.19(postcss@8.4.39)
+ specifier: ^10.4.20
+ version: 10.4.20(postcss@8.4.40)
eslint:
specifier: ^8.57.0
version: 8.57.0
@@ -202,11 +202,11 @@ importers:
specifier: ^3.2.0
version: 3.2.0(eslint@8.57.0)
postcss:
- specifier: ^8.4.39
- version: 8.4.39
+ specifier: ^8.4.40
+ version: 8.4.40
tailwindcss:
- specifier: ^3.4.6
- version: 3.4.6
+ specifier: ^3.4.7
+ version: 3.4.7
typescript:
specifier: 5.4.4
version: 5.4.4
@@ -217,8 +217,8 @@ packages:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
- '@babel/runtime@7.24.8':
- resolution: {integrity: sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==}
+ '@babel/runtime@7.25.0':
+ resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==}
engines: {node: '>=6.9.0'}
'@emnapi/runtime@1.2.0':
@@ -257,11 +257,11 @@ packages:
resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- '@floating-ui/core@1.6.4':
- resolution: {integrity: sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==}
+ '@floating-ui/core@1.6.5':
+ resolution: {integrity: sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==}
- '@floating-ui/dom@1.6.7':
- resolution: {integrity: sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==}
+ '@floating-ui/dom@1.6.8':
+ resolution: {integrity: sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==}
'@floating-ui/react-dom@2.1.1':
resolution: {integrity: sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==}
@@ -269,8 +269,8 @@ packages:
react: '>=16.8.0'
react-dom: '>=16.8.0'
- '@floating-ui/utils@0.2.4':
- resolution: {integrity: sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==}
+ '@floating-ui/utils@0.2.5':
+ resolution: {integrity: sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==}
'@hocuspocus/common@2.13.5':
resolution: {integrity: sha512-8D9FzhZFlt0WsgXw5yT2zwSxi6z9d4V2vUz6co2vo3Cj+Y2bvGZsdDiTvU/MerGcCLME5k/w6PwLPojLYH/4pg==}
@@ -882,8 +882,8 @@ packages:
'@remirror/core-constants@2.0.2':
resolution: {integrity: sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ==}
- '@rushstack/eslint-patch@1.10.3':
- resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==}
+ '@rushstack/eslint-patch@1.10.4':
+ resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==}
'@stitches/react@1.2.8':
resolution: {integrity: sha512-9g9dWI4gsSVe8bNLlb+lMkBYsnIKCZTmvqvDG+Avnn69XfmHZKiaMrx7cgTaddq7aTPPmXiTsbFcUy0xgI4+wA==}
@@ -896,162 +896,162 @@ packages:
'@swc/helpers@0.5.5':
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
- '@tiptap/core@2.5.4':
- resolution: {integrity: sha512-Zs/hShr4+W02+0nOlpmr5cS2YjDRLqd+XMt+jsiQH0QNr3s1Lc82pfF6C3CjgLEZtdUzImZrW2ABtLlpvbogaA==}
+ '@tiptap/core@2.5.8':
+ resolution: {integrity: sha512-lkWCKyoAoMTxM137MoEsorG7tZ5MZU6O3wMRuZ0P9fcTRY5vd1NWncWuPzuGSJIpL20gwBQOsS6PaQSfR3xjlA==}
peerDependencies:
- '@tiptap/pm': ^2.5.4
+ '@tiptap/pm': ^2.5.8
- '@tiptap/extension-blockquote@2.5.4':
- resolution: {integrity: sha512-UqeJunZM3IiCQGZE0X5YNUOWYkuIieqrwPgOEghAIjnhDcQizQcouRQ5R7cwwv/scNr2JvZHncOTLrALV3Janw==}
+ '@tiptap/extension-blockquote@2.5.8':
+ resolution: {integrity: sha512-P8vDiagtRrUfIewfCKrJe0ddDSjPgOTKzqoM1UXKS+MenT8C/wT4bjiwopAoWP6zMoV0TfHWXah9emllmCfXFA==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-bold@2.5.4':
- resolution: {integrity: sha512-H5sjqloFMjq7VOSfE+U4T7dqGoflOiF6RW6/gZm/U6KYeHG2/bG0ktq7mWAnnhbiKiy7gUcxyJCV+ILdGX9C5g==}
+ '@tiptap/extension-bold@2.5.8':
+ resolution: {integrity: sha512-4vEn+U7Y8B4e8izcL7QuEKYJ9thCSdo+UF1K3TOqQWuJTzTrJLPMwTZ4vYOHzvuq5uIXyPLnWzLgnRLgy5mJRg==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-bubble-menu@2.5.4':
- resolution: {integrity: sha512-GHwef912K1yd75pp9JGDnKSp1DvdOHH8BcHQv0no+a3q2ePFPYcgaSwVRR59jHRX9WzdVfoLcqDSAeoNGOrISw==}
+ '@tiptap/extension-bubble-menu@2.5.8':
+ resolution: {integrity: sha512-COmd1Azudu7i281emZFIESECe7FnvWiRoBoQBVjjWSyq5PVzwJaA3PAlnU7GyNZKtVXMZ4xbrckdyNQfDeVQDA==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/pm': ^2.5.8
- '@tiptap/extension-bullet-list@2.5.4':
- resolution: {integrity: sha512-aAfpALeD6OxymkbtrzDqbgkAkzVVHudxOb8GsK1N6m42nFL7Q9JzHJ5/8KzB+xi25CcIbS+HmXJkRIQJXgNbSA==}
+ '@tiptap/extension-bullet-list@2.5.8':
+ resolution: {integrity: sha512-Wvf0HWBI0ulssoCsCOguxJB1Ntmj9PtE8b/ieFwFvrNptP+sf25XiWgjMs7H1KQrtmpngBu/Bhh5jJRgAmAgeQ==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-code-block-lowlight@2.5.4':
- resolution: {integrity: sha512-K+bDt6CY2IxGANtmVK32uD8lRY/DqFGJwDKhearpFTR7yAn8q2MpWZjH15eOqZIgXGNf1fK6VK6wfczjecrV3A==}
+ '@tiptap/extension-code-block-lowlight@2.5.8':
+ resolution: {integrity: sha512-ga5iYzVeX7pQ6P44ZkW+Sf+sTcAjD8gjkz6szQ4qKZbJNKWhUPbWyhp41mlhwBq+QzvqcGNWiGcOe6ZwPR01sA==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/extension-code-block': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/extension-code-block': ^2.5.8
+ '@tiptap/pm': ^2.5.8
- '@tiptap/extension-code-block@2.5.4':
- resolution: {integrity: sha512-lZRz44ACSL0IC4syWkNsNSe90sZuLig0yidfV9rs2muSCLoS3PRcCIJv4GjdBHouangxxBZqzIqWgPBqe6pqwA==}
+ '@tiptap/extension-code-block@2.5.8':
+ resolution: {integrity: sha512-atMtT1Ddc4hv9+OiH/UCLfQ6Ooo45xpPaaOhqs1Ab509YyqxoyEbfNSOth/yx9DFb8VOenRWE1WV3Z3C0ial0Q==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/pm': ^2.5.8
- '@tiptap/extension-code@2.5.4':
- resolution: {integrity: sha512-PCP0VcWR0Jsj3rum3czp1jateR+kv1iuB9E+TieGLN4vFqhoiUwSv2UAuhvD8x66MGCYLA3btgnmPov1w/iNmA==}
+ '@tiptap/extension-code@2.5.8':
+ resolution: {integrity: sha512-56lb4NnaYAbIkqBTCIg4ZoITrw86Dj8C2HSi6DrU7f5q9cfvGuH+2057I5n8eEEfASu1AeDN6tSnCz3NR+yiHw==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-collaboration-cursor@2.5.4':
- resolution: {integrity: sha512-M32JChnP5RVdr1n+Tf0gF9bxx0gHvc0uV4SDxCMN3uaNH5YpcofmvKElS60rDGVfCdRTId/aj7P3AtwrvRlYdQ==}
+ '@tiptap/extension-collaboration-cursor@2.5.8':
+ resolution: {integrity: sha512-dLwwphpIEYhMAL2j1DPJwmqtCTa1Vg6Qk3VSpcQQ1Q/M9bKy/E0j4wyi87p9vaeG4oRPM4b/xGy++gRN2FNRcw==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
y-prosemirror: ^1.2.6
- '@tiptap/extension-collaboration@2.5.4':
- resolution: {integrity: sha512-CpQdbr7XpQaVqRFo/A1DchrQZMDb8vrkP+FcUIgvHN0b8hwKDmXRAHDtuk8yTTEatW1EqpX8lx8UxaUTcDNbIg==}
+ '@tiptap/extension-collaboration@2.5.8':
+ resolution: {integrity: sha512-xSvYbTK+x0HozZ2io5DNhpe53mGdABQvsNMwzqdcY00abZV+qTZ6TTdafwOxrNhwMUzUttyzIMDF9SEddOiXvg==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/pm': ^2.5.8
y-prosemirror: ^1.2.6
- '@tiptap/extension-document@2.5.4':
- resolution: {integrity: sha512-4RDrhASxCTOZETYhIhEW1TfZqx3Tm+LQxouvBMFyODmT1PSgsg5Xz1FYpDPr+J49bGAK0Pr9ae0XcGW011L3sA==}
+ '@tiptap/extension-document@2.5.8':
+ resolution: {integrity: sha512-r3rP4ihCJAdp3VRIeqd80etHx7jttzZaKNFX8hkQShHK6eTHwrR92VL0jDE4K+NOE3bxjMsOlYizJYWV042BtA==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-dropcursor@2.5.4':
- resolution: {integrity: sha512-jzSnuuYhlc0SsHvAteWkE9TJy3eRwkxQs4MO2JxALOzJECN4G82nlX8vciihBD6xf7lVgVSBACejK9+rsTHqCg==}
+ '@tiptap/extension-dropcursor@2.5.8':
+ resolution: {integrity: sha512-xPmIfTYqurFF8RukCPlHd8mT8I7hDinWrgq7CQTRROxcJ3DNw8PooWrKWaBYs9HXHe1pbiQ5EK0uOsNvQ1bcDg==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/pm': ^2.5.8
- '@tiptap/extension-floating-menu@2.5.4':
- resolution: {integrity: sha512-EqD4rgi3UhnDcV3H1+ndAS4Ue2zpsU7hFKoevOIV6GS7xVnWN70AGt6swH24QzuHKKISFtWoLpKjrwRORNIxuA==}
+ '@tiptap/extension-floating-menu@2.5.8':
+ resolution: {integrity: sha512-qsM6tCyRlXnI/gADrkO/2p0Tldu5aY96CnsXpZMaflMgsO577qhcXD0ReGg17uLXBzJa5xmV8qOik0Ptq3WEWg==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/pm': ^2.5.8
- '@tiptap/extension-gapcursor@2.5.4':
- resolution: {integrity: sha512-wzTh1piODZBS0wmuDgPjjg8PQwclYa5LssnxDIo9pDSnt4l3AfHSAJIJSGIfgt96KnzF1wqRTRpe08qNa1n7/g==}
+ '@tiptap/extension-gapcursor@2.5.8':
+ resolution: {integrity: sha512-nR7AUOE4xWdp0sDbLbe4uwAhQ/xq+MTLVafvffMLT81U/Hl9R+w0Ap2XF0+c6/JTQwVjZiOalAmg4dobx7rJUQ==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/pm': ^2.5.8
- '@tiptap/extension-hard-break@2.5.4':
- resolution: {integrity: sha512-nLn6HP9tqgdGGwbMORXVtcY30DTGctYFaWADRthvBjVgacYSeKlhUcsSu3YgaxtbxZp6BhfRvD2kKrxyQsSjnQ==}
+ '@tiptap/extension-hard-break@2.5.8':
+ resolution: {integrity: sha512-samZEL0EXzHSmMQ7KyLnfSxdDv3qSjia0JzelfCnFZS6LLcbwjrIjV8ZPxEhJ7UlZqroQdFxPegllkLHZj/MdQ==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-heading@2.5.4':
- resolution: {integrity: sha512-DuAB58/e7eho1rkyad0Z/SjW+EB+H2hRqHlswEeZZYhBTjzey5UmBwkMWTGC/SQiRisx1xYQYTd8T0fiABi5hw==}
+ '@tiptap/extension-heading@2.5.8':
+ resolution: {integrity: sha512-fDQoUkTLN+U8MNQ8PI+syKyshS9qFHlKihxzMLf/+tRisJvP47gzHDur99nffTSbXFDnASDqhavhKjI/2xTWlQ==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-history@2.5.4':
- resolution: {integrity: sha512-WB1fZYGIlpahAD6Ba+mj9vIb1tk8S3TsADXDFKxLVpZWZPQ+B7duGJP7g/vRH2XAXEs836JzC2oxjKeaop3k7A==}
+ '@tiptap/extension-history@2.5.8':
+ resolution: {integrity: sha512-5IrZZfp2Rg9Tov/08aYTKhwoiqdun8v3j3vleuqyW5RB7LU/NKLR19EtSSMh9mVkFZVbhab2zDOFmn5ilsEOhw==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/pm': ^2.5.8
- '@tiptap/extension-horizontal-rule@2.5.4':
- resolution: {integrity: sha512-uXLDe/iyzQbyfDkJ8kE5XaAkY3EOcbTFLjbueqGlkbWtjJgy+3LysGvh8fQj8PAOaIBMaFRFhTq7GMbW2ebRog==}
+ '@tiptap/extension-horizontal-rule@2.5.8':
+ resolution: {integrity: sha512-L8Is73WGaP6VNdKrIry+lCIM9W1KaL/Tw2Z6DGMVMU5mr1lLx0xq7nWEStqD7e4zh+n4+3PV15cZSA2F34DZrg==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/pm': ^2.5.8
- '@tiptap/extension-italic@2.5.4':
- resolution: {integrity: sha512-TAhtl/fNBgv1elzF3HWES8uwVdpKBSYrq1e6yeYfj74mQn//3ksvdhWQrLzc1e+zcoHbk1PeOp/5ODdPuZ6tkg==}
+ '@tiptap/extension-italic@2.5.8':
+ resolution: {integrity: sha512-Kh35a7slBai+Qr/tiF9XFXmuWMgUQz4Nt51hmzqVGVuG+QsdWzQE8IZBGypKm8aAzxTGSY0d0QA0rys+YRNq1Q==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-list-item@2.5.4':
- resolution: {integrity: sha512-bPxUCFt9HnAfoaZQgwqCfRAZ6L3QlYhIRDDbOvZag7IxCdQuZmeY4k5OZfQIGijNDTag7CN9cdL4fl9rnm6/sQ==}
+ '@tiptap/extension-list-item@2.5.8':
+ resolution: {integrity: sha512-RFIIzHxxXdPmdf7BL0zhE4VPHoR6BTWtfi3JCTftmNqKoH7o+mLKT0RHMGvF1CGNn2HewHzXAF0iXfKCwmEgHQ==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-ordered-list@2.5.4':
- resolution: {integrity: sha512-cl3cTJitY6yDUmxqgjDUtDWCyX1VVsZNJ6i9yiPeARcxvzFc81KmUJxTGl8WPT5TjqmM+TleRkZjsxgvXX57+Q==}
+ '@tiptap/extension-ordered-list@2.5.8':
+ resolution: {integrity: sha512-84gWdWhc8rUCCssn8+6Z1rFKdG7/yIe+gwYkU6WqAtDrcluJdt5jRHrcMOLxb2dbY8ww9pa72EYV/bwOisZlFQ==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-paragraph@2.5.4':
- resolution: {integrity: sha512-pC1YIkkRPXoU0eDrhfAf8ZrFJQzvw2ftP6KRhLnnSw/Ot1DOjT1r95l7zsFefS9oCDMT/L4HghTAiPZ4rcpPbg==}
+ '@tiptap/extension-paragraph@2.5.8':
+ resolution: {integrity: sha512-AMfD3lfGSiomfkSE2tUourUjVahLtIfWUQew13NTPuWoxAXaSyoCGO0ULkiou/lO3JVUUUmF9+KJrAHWGIARdA==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-strike@2.5.4':
- resolution: {integrity: sha512-OSN6ePbCwEhi3hYZZOPow/P9Ym2Kv3NhVbUvasjZCiqQuk8TGc33xirPWl9DTjb/BLfL66TtJ2tKUEVOKl5dKg==}
+ '@tiptap/extension-strike@2.5.8':
+ resolution: {integrity: sha512-uiHhBIEqawX9Up2ofklotVQ5XpGIjwRL6wprZF38s1le3XpsgyhVV7oDnqDkC7ujCsGkOJJfXZtv3LsO3R2nzQ==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-text@2.5.4':
- resolution: {integrity: sha512-+3x/hYqhmCYbvedCcQzQHFtZ5MAcMOlKuczomZtygf8AfDfuQVrG1m4GoJyNzJdqxjN80/xq4e2vDVvqQxYTCw==}
+ '@tiptap/extension-text@2.5.8':
+ resolution: {integrity: sha512-CNkD51jRMdcYCqFVOkrnebqBQ6pCD3ZD5z9kO5bOC5UPZKZBkLsWdlrHGAVwosxcGxdJACbqJ0Nj+fMgIw4tNA==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/extension-youtube@2.5.4':
- resolution: {integrity: sha512-iHcvXOA32MZsVJTT7mvZ1CWKUo2quQMQXfBniizLm0lUG1ftSioqnDuXy4kEjeCBR2cnZr3yph6tbG/pF0RcHg==}
+ '@tiptap/extension-youtube@2.5.8':
+ resolution: {integrity: sha512-TEZ/mZgAIgc4thTO0pbmuNpWhMcCKk4IPgG3ko5HJ6w4lm13aVBroGoTXxHmK50kDzr+yD0g9JaJJTIvJ2cvGA==}
peerDependencies:
- '@tiptap/core': ^2.5.4
+ '@tiptap/core': ^2.5.8
- '@tiptap/html@2.5.4':
- resolution: {integrity: sha512-Fcvsa7kkO+Id7WBFimDN5zdHksVGVnyHnffaN/PaAgbKmzP53BC38Pd0XuHS+KL6btqQIFE2GlqNYnyIos7i+g==}
+ '@tiptap/html@2.5.8':
+ resolution: {integrity: sha512-d97bNiRJu3jzYGQpLUTehm7tOk0+ihLXVrckKjDAHsxvhO1tS0YvLuQYtimauRHRuRbe/2RZ2AuFqfi5TFs2iQ==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/pm': ^2.5.8
- '@tiptap/pm@2.5.4':
- resolution: {integrity: sha512-oFIsuniptdUXn93x4aM2sVN3hYKo9Fj55zAkYrWhwxFYUYcPxd5ibra2we+wRK5TaiPu098wpC+yMSTZ/KKMpA==}
+ '@tiptap/pm@2.5.8':
+ resolution: {integrity: sha512-CVhHaTG4QNHSkvuh6HHsUR4hE+nbUnk7z+VMUedaqPU8tNqkTwWGCMbiyTc+PCsz0T9Mni7vvBR+EXgEQ3+w4g==}
- '@tiptap/react@2.5.4':
- resolution: {integrity: sha512-2HPHt2lEK6Z4jOV3HHVTee8hD4NS6eEj0zRZWSFjt1zDzXtFqX8VIv7qC1iDYsQgyiFnFnOucOQtAlDewBb23A==}
+ '@tiptap/react@2.5.8':
+ resolution: {integrity: sha512-twUMm8HV7scUgR/E1hYS9N6JDtKPl7cgDiPjxTynNHc5S5f5Ecv4ns/BZRq3TMZ/JDrp4rghLvgq+ImQsLvPOA==}
peerDependencies:
- '@tiptap/core': ^2.5.4
- '@tiptap/pm': ^2.5.4
+ '@tiptap/core': ^2.5.8
+ '@tiptap/pm': ^2.5.8
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
- '@tiptap/starter-kit@2.5.4':
- resolution: {integrity: sha512-IYnSETtBUSsy+Ece4kfVyzew+zyj7W9rP2Ronx0CbjeWQarfCAGxjuZ6uGLPB+tC5ZuMVt68Gyqb2y8GFes2Yw==}
+ '@tiptap/starter-kit@2.5.8':
+ resolution: {integrity: sha512-Beb6Q3cFmJ1pE22WlFrG3wj8XAGXqaGkbqtsGAJDnoyWL4uoSs4vLt5I/UJshK/nQlNqTWFdpd9SxRFsxBYpqg==}
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
@@ -1215,9 +1215,6 @@ packages:
resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
engines: {node: '>= 0.4'}
- array.prototype.toreversed@1.1.2:
- resolution: {integrity: sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==}
-
array.prototype.tosorted@1.1.4:
resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==}
engines: {node: '>= 0.4'}
@@ -1229,8 +1226,8 @@ packages:
ast-types-flow@0.0.8:
resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==}
- autoprefixer@10.4.19:
- resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==}
+ autoprefixer@10.4.20:
+ resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
@@ -1246,8 +1243,8 @@ packages:
react: '>= 16'
react-dom: '>= 16'
- axe-core@4.9.1:
- resolution: {integrity: sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==}
+ axe-core@4.10.0:
+ resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==}
engines: {node: '>=4'}
axobject-query@3.1.1:
@@ -1273,8 +1270,8 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
- browserslist@4.23.2:
- resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==}
+ browserslist@4.23.3:
+ resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
@@ -1300,8 +1297,8 @@ packages:
camelize@1.0.1:
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
- caniuse-lite@1.0.30001642:
- resolution: {integrity: sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==}
+ caniuse-lite@1.0.30001649:
+ resolution: {integrity: sha512-fJegqZZ0ZX8HOWr6rcafGr72+xcgJKI9oWfDW5DrD7ExUtgZC7a7R7ZYmZqplh7XDocFdGeIFn7roAxhOeYrPQ==}
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
@@ -1387,8 +1384,8 @@ packages:
resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
engines: {node: '>= 0.4'}
- dayjs@1.11.11:
- resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==}
+ dayjs@1.11.12:
+ resolution: {integrity: sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==}
debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
@@ -1406,8 +1403,8 @@ packages:
supports-color:
optional: true
- debug@4.3.5:
- resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
+ debug@4.3.6:
+ resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
@@ -1469,8 +1466,8 @@ packages:
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
- electron-to-chromium@1.4.829:
- resolution: {integrity: sha512-5qp1N2POAfW0u1qGAxXEtz6P7bO1m6gpZr5hdf5ve6lxpLM7MpiM4jIPz7xcrNlClQMafbyUDDWjlIQZ1Mw0Rw==}
+ electron-to-chromium@1.5.4:
+ resolution: {integrity: sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -1478,8 +1475,8 @@ packages:
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
- enhanced-resolve@5.17.0:
- resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==}
+ enhanced-resolve@5.17.1:
+ resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==}
engines: {node: '>=10.13.0'}
entities@4.5.0:
@@ -1593,11 +1590,11 @@ packages:
peerDependencies:
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
- eslint-plugin-react@7.34.4:
- resolution: {integrity: sha512-Np+jo9bUwJNxCsT12pXtrGhJgT3T44T1sHhn1Ssr42XFn8TES0267wPGo5nNrMHi8qkyimDAX2BUmkf9pSaVzA==}
+ eslint-plugin-react@7.35.0:
+ resolution: {integrity: sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==}
engines: {node: '>=4'}
peerDependencies:
- eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
eslint-plugin-unused-imports@3.2.0:
resolution: {integrity: sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==}
@@ -1740,8 +1737,8 @@ packages:
resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
engines: {node: '>= 0.4'}
- get-tsconfig@4.7.5:
- resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==}
+ get-tsconfig@4.7.6:
+ resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==}
get-youtube-id@1.0.1:
resolution: {integrity: sha512-5yidLzoLXbtw82a/Wb7LrajkGn29BM6JuLWeHyNfzOGp1weGyW4+7eMz6cP23+etqj27VlOFtq8fFFDMLq/FXQ==}
@@ -2043,8 +2040,8 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
- lib0@0.2.94:
- resolution: {integrity: sha512-hZ3p54jL4Wpu7IOg26uC7dnEWiMyNlUrb9KoG7+xYs45WkQwpVvKFndVq2+pqLYKe1u8Fp3+zAfZHVvTK34PvQ==}
+ lib0@0.2.96:
+ resolution: {integrity: sha512-xeV9M34+D4HD1sd6xAarnWYgU7pKau64bvmPySibX85G+hx/KonzISpO409K6OS9IVLORWfQZkKBRZV5sQegFQ==}
engines: {node: '>=16'}
hasBin: true
@@ -2092,10 +2089,10 @@ packages:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
- lucide-react@0.408.0:
- resolution: {integrity: sha512-8kETAAeWmOvtGIr7HPHm51DXoxlfkNncQ5FZWXR+abX8saQwMYXANWIkUstaYtcKSo/imOe/q+tVFA8ANzdSVA==}
+ lucide-react@0.424.0:
+ resolution: {integrity: sha512-x2Nj2aytk1iOyHqt4hKenfVlySq0rYxNeEf8hE0o+Yh0iE36Rqz0rkngVdv2uQtjZ70LAE73eeplhhptYt9x4Q==}
peerDependencies:
- react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
markdown-it@14.1.0:
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
@@ -2189,8 +2186,8 @@ packages:
react: '>= 16.0.0'
react-dom: '>= 16.0.0'
- node-releases@2.0.17:
- resolution: {integrity: sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==}
+ node-releases@2.0.18:
+ resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==}
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
@@ -2348,8 +2345,8 @@ packages:
ts-node:
optional: true
- postcss-nested@6.0.1:
- resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
+ postcss-nested@6.2.0:
+ resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==}
engines: {node: '>=12.0'}
peerDependencies:
postcss: ^8.2.14
@@ -2369,8 +2366,8 @@ packages:
resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
engines: {node: ^10 || ^12 || >=14}
- postcss@8.4.39:
- resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==}
+ postcss@8.4.40:
+ resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==}
engines: {node: ^10 || ^12 || >=14}
preact-render-to-string@5.2.6:
@@ -2378,8 +2375,8 @@ packages:
peerDependencies:
preact: '>=10'
- preact@10.22.1:
- resolution: {integrity: sha512-jRYbDDgMpIb5LHq3hkI0bbl+l/TQ9UnkdQ0ww+lp+4MMOdqaUYdFc5qeyP+IV8FAd/2Em7drVPeKdQxsiWCf/A==}
+ preact@10.23.1:
+ resolution: {integrity: sha512-O5UdRsNh4vdZaTieWe3XOgSpdMAmkIYBCT3VhQDlKrzyCm8lUYsk0fmVEvoQQifoOjFRTaHZO69ylrzTW2BH+A==}
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
@@ -2397,8 +2394,8 @@ packages:
prosemirror-collab@1.3.1:
resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==}
- prosemirror-commands@1.5.2:
- resolution: {integrity: sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==}
+ prosemirror-commands@1.6.0:
+ resolution: {integrity: sha512-xn1U/g36OqXn2tn5nGmvnnimAj/g1pUx2ypJJIe8WkVX83WyJVC5LTARaxZa2AtQRwntu9Jc5zXs9gL9svp/mg==}
prosemirror-dropcursor@1.8.1:
resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==}
@@ -2421,8 +2418,8 @@ packages:
prosemirror-menu@1.2.4:
resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==}
- prosemirror-model@1.22.1:
- resolution: {integrity: sha512-gMrxal+F3higDFxCkBK5iQXckRVYvIu/3dopERJ6b20xfwZ9cbYvQvuldqaN+v/XytNPGyURYUpUU23kBRxWCQ==}
+ prosemirror-model@1.22.2:
+ resolution: {integrity: sha512-I4lS7HHIW47D0Xv/gWmi4iUWcQIDYaJKd8Hk4+lcSps+553FlQrhmxtItpEvTr75iAruhzVShVp6WUwsT6Boww==}
prosemirror-schema-basic@1.2.3:
resolution: {integrity: sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==}
@@ -2433,8 +2430,8 @@ packages:
prosemirror-state@1.4.3:
resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==}
- prosemirror-tables@1.3.7:
- resolution: {integrity: sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA==}
+ prosemirror-tables@1.4.0:
+ resolution: {integrity: sha512-fxryZZkQG12fSCNuZDrYx6Xvo2rLYZTbKLRd8rglOPgNJGMKIS8uvTt6gGC38m7UCu/ENnXIP9pEz5uDaPc+cA==}
prosemirror-trailing-node@2.0.9:
resolution: {integrity: sha512-YvyIn3/UaLFlFKrlJB6cObvUhmwFNZVhy1Q8OpW/avoTbD/Y7H5EcjK4AZFKhmuS6/N6WkGgt7gWtBWDnmFvHg==}
@@ -2446,8 +2443,8 @@ packages:
prosemirror-transform@1.9.0:
resolution: {integrity: sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg==}
- prosemirror-view@1.33.8:
- resolution: {integrity: sha512-4PhMr/ufz2cdvFgpUAnZfs+0xij3RsFysreeG9V/utpwX7AJtYCDVyuRxzWoMJIEf4C7wVihuBNMPpFLPCiLQw==}
+ prosemirror-view@1.33.9:
+ resolution: {integrity: sha512-xV1A0Vz9cIcEnwmMhKKFAOkfIp8XmJRnaZoPqNXrPS7EK5n11Ov8V76KhR0RsfQd/SIzmWY+bg+M44A2Lx/Nnw==}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
@@ -2804,8 +2801,8 @@ packages:
peerDependencies:
tailwindcss: 3.x
- tailwindcss@3.4.6:
- resolution: {integrity: sha512-1uRHzPB+Vzu57ocybfZ4jh5Q3SdlH7XW23J5sQoM9LhE9eIOlzxer/3XPSsycvih3rboRsvt0QCmzSrqyOYUIA==}
+ tailwindcss@3.4.7:
+ resolution: {integrity: sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==}
engines: {node: '>=14.0.0'}
hasBin: true
@@ -2951,8 +2948,8 @@ packages:
which-boxed-primitive@1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
- which-builtin-type@1.1.3:
- resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==}
+ which-builtin-type@1.1.4:
+ resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==}
engines: {node: '>= 0.4'}
which-collection@1.0.2:
@@ -3001,8 +2998,8 @@ packages:
peerDependencies:
yjs: ^13.0.0
- y-prosemirror@1.2.9:
- resolution: {integrity: sha512-fThGIVmSqrqnG/ckywEGlHM9ElfILC4TcMZd5zxWPe/i+UuP97TEr4swsopRKG3Y+KHBVt4Y/5NVBC3AAsUoUg==}
+ y-prosemirror@1.2.11:
+ resolution: {integrity: sha512-MUGMYyokOb9DpBRHr4Cadob2KheDCKW2LHceAM2yrWp9dfX+3HZZUNEubEPd4zszq4DF2fGCFhE3N66zOTLoxA==}
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
peerDependencies:
prosemirror-model: ^1.7.1
@@ -3027,8 +3024,8 @@ packages:
yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
- yaml@2.4.5:
- resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==}
+ yaml@2.5.0:
+ resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==}
engines: {node: '>= 14'}
hasBin: true
@@ -3051,7 +3048,7 @@ snapshots:
'@alloc/quick-lru@5.2.0': {}
- '@babel/runtime@7.24.8':
+ '@babel/runtime@7.25.0':
dependencies:
regenerator-runtime: 0.14.1
@@ -3086,7 +3083,7 @@ snapshots:
'@eslint/eslintrc@2.1.4':
dependencies:
ajv: 6.12.6
- debug: 4.3.5
+ debug: 4.3.6
espree: 9.6.1
globals: 13.24.0
ignore: 5.3.1
@@ -3099,32 +3096,32 @@ snapshots:
'@eslint/js@8.57.0': {}
- '@floating-ui/core@1.6.4':
+ '@floating-ui/core@1.6.5':
dependencies:
- '@floating-ui/utils': 0.2.4
+ '@floating-ui/utils': 0.2.5
- '@floating-ui/dom@1.6.7':
+ '@floating-ui/dom@1.6.8':
dependencies:
- '@floating-ui/core': 1.6.4
- '@floating-ui/utils': 0.2.4
+ '@floating-ui/core': 1.6.5
+ '@floating-ui/utils': 0.2.5
'@floating-ui/react-dom@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@floating-ui/dom': 1.6.7
+ '@floating-ui/dom': 1.6.8
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- '@floating-ui/utils@0.2.4': {}
+ '@floating-ui/utils@0.2.5': {}
'@hocuspocus/common@2.13.5':
dependencies:
- lib0: 0.2.94
+ lib0: 0.2.96
'@hocuspocus/provider@2.13.5(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)':
dependencies:
'@hocuspocus/common': 2.13.5
'@lifeomic/attempt': 3.1.0
- lib0: 0.2.94
+ lib0: 0.2.96
ws: 8.18.0
y-protocols: 1.0.6(yjs@13.6.18)
yjs: 13.6.18
@@ -3135,7 +3132,7 @@ snapshots:
'@humanwhocodes/config-array@0.11.14':
dependencies:
'@humanwhocodes/object-schema': 2.0.3
- debug: 4.3.5
+ debug: 4.3.6
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
@@ -3303,7 +3300,7 @@ snapshots:
'@radix-ui/primitive@1.0.1':
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
'@radix-ui/primitive@1.1.0': {}
@@ -3327,7 +3324,7 @@ snapshots:
'@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
@@ -3340,7 +3337,7 @@ snapshots:
'@radix-ui/react-context@1.0.1(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
@@ -3405,7 +3402,7 @@ snapshots:
'@radix-ui/react-form@0.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
'@radix-ui/react-context': 1.0.1(@types/react@18.2.74)(react@18.3.1)
@@ -3424,7 +3421,7 @@ snapshots:
'@radix-ui/react-id@1.0.1(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
optionalDependencies:
@@ -3439,7 +3436,7 @@ snapshots:
'@radix-ui/react-label@2.0.2(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
@@ -3487,7 +3484,7 @@ snapshots:
'@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.74)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
@@ -3506,7 +3503,7 @@ snapshots:
'@radix-ui/react-slot@1.0.2(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.3.1)
react: 18.3.1
optionalDependencies:
@@ -3576,7 +3573,7 @@ snapshots:
'@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.74)(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
react: 18.3.1
optionalDependencies:
'@types/react': 18.2.74
@@ -3620,7 +3617,7 @@ snapshots:
'@remirror/core-constants@2.0.2': {}
- '@rushstack/eslint-patch@1.10.3': {}
+ '@rushstack/eslint-patch@1.10.4': {}
'@stitches/react@1.2.8(react@18.3.1)':
dependencies:
@@ -3633,131 +3630,131 @@ snapshots:
'@swc/counter': 0.1.3
tslib: 2.6.3
- '@tiptap/core@2.5.4(@tiptap/pm@2.5.4)':
+ '@tiptap/core@2.5.8(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/pm': 2.5.4
+ '@tiptap/pm': 2.5.8
- '@tiptap/extension-blockquote@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-blockquote@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-bold@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-bold@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-bubble-menu@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
+ '@tiptap/extension-bubble-menu@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
tippy.js: 6.3.7
- '@tiptap/extension-bullet-list@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-bullet-list@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-code-block-lowlight@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/extension-code-block@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
+ '@tiptap/extension-code-block-lowlight@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/extension-code-block@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-code-block': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/extension-code-block': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
- '@tiptap/extension-code-block@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
+ '@tiptap/extension-code-block@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
- '@tiptap/extension-code@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-code@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-collaboration-cursor@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(y-prosemirror@1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))':
+ '@tiptap/extension-collaboration-cursor@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(y-prosemirror@1.2.11(prosemirror-model@1.22.2)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- y-prosemirror: 1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ y-prosemirror: 1.2.11(prosemirror-model@1.22.2)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
- '@tiptap/extension-collaboration@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)(y-prosemirror@1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))':
+ '@tiptap/extension-collaboration@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)(y-prosemirror@1.2.11(prosemirror-model@1.22.2)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
- y-prosemirror: 1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
+ y-prosemirror: 1.2.11(prosemirror-model@1.22.2)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
- '@tiptap/extension-document@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-document@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-dropcursor@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
+ '@tiptap/extension-dropcursor@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
- '@tiptap/extension-floating-menu@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
+ '@tiptap/extension-floating-menu@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
tippy.js: 6.3.7
- '@tiptap/extension-gapcursor@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
+ '@tiptap/extension-gapcursor@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
- '@tiptap/extension-hard-break@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-hard-break@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-heading@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-heading@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-history@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
+ '@tiptap/extension-history@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
- '@tiptap/extension-horizontal-rule@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
+ '@tiptap/extension-horizontal-rule@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
- '@tiptap/extension-italic@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-italic@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-list-item@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-list-item@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-ordered-list@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-ordered-list@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-paragraph@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-paragraph@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-strike@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-strike@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-text@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-text@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/extension-youtube@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))':
+ '@tiptap/extension-youtube@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
- '@tiptap/html@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)':
+ '@tiptap/html@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
zeed-dom: 0.10.11
- '@tiptap/pm@2.5.4':
+ '@tiptap/pm@2.5.8':
dependencies:
prosemirror-changeset: 2.2.1
prosemirror-collab: 1.3.1
- prosemirror-commands: 1.5.2
+ prosemirror-commands: 1.6.0
prosemirror-dropcursor: 1.8.1
prosemirror-gapcursor: 1.3.2
prosemirror-history: 1.4.1
@@ -3765,47 +3762,47 @@ snapshots:
prosemirror-keymap: 1.2.2
prosemirror-markdown: 1.13.0
prosemirror-menu: 1.2.4
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
prosemirror-schema-basic: 1.2.3
prosemirror-schema-list: 1.4.1
prosemirror-state: 1.4.3
- prosemirror-tables: 1.3.7
- prosemirror-trailing-node: 2.0.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)
+ prosemirror-tables: 1.4.0
+ prosemirror-trailing-node: 2.0.9(prosemirror-model@1.22.2)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9)
prosemirror-transform: 1.9.0
- prosemirror-view: 1.33.8
+ prosemirror-view: 1.33.9
- '@tiptap/react@2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@tiptap/react@2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-bubble-menu': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
- '@tiptap/extension-floating-menu': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
- '@tiptap/pm': 2.5.4
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/extension-bubble-menu': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)
+ '@tiptap/extension-floating-menu': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)
+ '@tiptap/pm': 2.5.8
'@types/use-sync-external-store': 0.0.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
use-sync-external-store: 1.2.2(react@18.3.1)
- '@tiptap/starter-kit@2.5.4(@tiptap/pm@2.5.4)':
+ '@tiptap/starter-kit@2.5.8(@tiptap/pm@2.5.8)':
dependencies:
- '@tiptap/core': 2.5.4(@tiptap/pm@2.5.4)
- '@tiptap/extension-blockquote': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-bold': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-bullet-list': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-code': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-code-block': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
- '@tiptap/extension-document': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-dropcursor': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
- '@tiptap/extension-gapcursor': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
- '@tiptap/extension-hard-break': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-heading': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-history': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
- '@tiptap/extension-horizontal-rule': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))(@tiptap/pm@2.5.4)
- '@tiptap/extension-italic': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-list-item': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-ordered-list': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-paragraph': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-strike': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
- '@tiptap/extension-text': 2.5.4(@tiptap/core@2.5.4(@tiptap/pm@2.5.4))
+ '@tiptap/core': 2.5.8(@tiptap/pm@2.5.8)
+ '@tiptap/extension-blockquote': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-bold': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-bullet-list': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-code': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-code-block': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)
+ '@tiptap/extension-document': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-dropcursor': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)
+ '@tiptap/extension-gapcursor': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)
+ '@tiptap/extension-hard-break': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-heading': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-history': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)
+ '@tiptap/extension-horizontal-rule': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))(@tiptap/pm@2.5.8)
+ '@tiptap/extension-italic': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-list-item': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-ordered-list': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-paragraph': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-strike': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
+ '@tiptap/extension-text': 2.5.8(@tiptap/core@2.5.8(@tiptap/pm@2.5.8))
transitivePeerDependencies:
- '@tiptap/pm'
@@ -3876,7 +3873,7 @@ snapshots:
'@typescript-eslint/types': 7.2.0
'@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.4)
'@typescript-eslint/visitor-keys': 7.2.0
- debug: 4.3.5
+ debug: 4.3.6
eslint: 8.57.0
optionalDependencies:
typescript: 5.4.4
@@ -3894,7 +3891,7 @@ snapshots:
dependencies:
'@typescript-eslint/types': 7.2.0
'@typescript-eslint/visitor-keys': 7.2.0
- debug: 4.3.5
+ debug: 4.3.6
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.3
@@ -4002,13 +3999,6 @@ snapshots:
es-abstract: 1.23.3
es-shim-unscopables: 1.0.2
- array.prototype.toreversed@1.1.2:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
- es-shim-unscopables: 1.0.2
-
array.prototype.tosorted@1.1.4:
dependencies:
call-bind: 1.0.7
@@ -4030,14 +4020,14 @@ snapshots:
ast-types-flow@0.0.8: {}
- autoprefixer@10.4.19(postcss@8.4.39):
+ autoprefixer@10.4.20(postcss@8.4.40):
dependencies:
- browserslist: 4.23.2
- caniuse-lite: 1.0.30001642
+ browserslist: 4.23.3
+ caniuse-lite: 1.0.30001649
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.0.1
- postcss: 8.4.39
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
available-typed-arrays@1.0.7:
@@ -4052,7 +4042,7 @@ snapshots:
transitivePeerDependencies:
- csstype
- axe-core@4.9.1: {}
+ axe-core@4.10.0: {}
axobject-query@3.1.1:
dependencies:
@@ -4077,12 +4067,12 @@ snapshots:
dependencies:
fill-range: 7.1.1
- browserslist@4.23.2:
+ browserslist@4.23.3:
dependencies:
- caniuse-lite: 1.0.30001642
- electron-to-chromium: 1.4.829
- node-releases: 2.0.17
- update-browserslist-db: 1.1.0(browserslist@4.23.2)
+ caniuse-lite: 1.0.30001649
+ electron-to-chromium: 1.5.4
+ node-releases: 2.0.18
+ update-browserslist-db: 1.1.0(browserslist@4.23.3)
buffer@6.0.3:
dependencies:
@@ -4107,7 +4097,7 @@ snapshots:
camelize@1.0.1: {}
- caniuse-lite@1.0.30001642: {}
+ caniuse-lite@1.0.30001649: {}
chalk@4.1.2:
dependencies:
@@ -4198,7 +4188,7 @@ snapshots:
es-errors: 1.3.0
is-data-view: 1.0.1
- dayjs@1.11.11: {}
+ dayjs@1.11.12: {}
debug@2.6.9:
dependencies:
@@ -4208,7 +4198,7 @@ snapshots:
dependencies:
ms: 2.1.3
- debug@4.3.5:
+ debug@4.3.6:
dependencies:
ms: 2.1.2
@@ -4277,13 +4267,13 @@ snapshots:
eastasianwidth@0.2.0: {}
- electron-to-chromium@1.4.829: {}
+ electron-to-chromium@1.5.4: {}
emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {}
- enhanced-resolve@5.17.0:
+ enhanced-resolve@5.17.1:
dependencies:
graceful-fs: 4.2.11
tapable: 2.2.1
@@ -4403,14 +4393,14 @@ snapshots:
eslint-config-next@14.2.5(eslint@8.57.0)(typescript@5.4.4):
dependencies:
'@next/eslint-plugin-next': 14.2.5
- '@rushstack/eslint-patch': 1.10.3
+ '@rushstack/eslint-patch': 1.10.4
'@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.4)
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0)
- eslint-plugin-react: 7.34.4(eslint@8.57.0)
+ eslint-plugin-react: 7.35.0(eslint@8.57.0)
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0)
optionalDependencies:
typescript: 5.4.4
@@ -4428,13 +4418,13 @@ snapshots:
eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0):
dependencies:
- debug: 4.3.5
- enhanced-resolve: 5.17.0
+ debug: 4.3.6
+ enhanced-resolve: 5.17.1
eslint: 8.57.0
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
fast-glob: 3.3.2
- get-tsconfig: 4.7.5
+ get-tsconfig: 4.7.6
is-core-module: 2.15.0
is-glob: 4.0.3
transitivePeerDependencies:
@@ -4487,7 +4477,7 @@ snapshots:
array-includes: 3.1.8
array.prototype.flatmap: 1.3.2
ast-types-flow: 0.0.8
- axe-core: 4.9.1
+ axe-core: 4.10.0
axobject-query: 3.1.1
damerau-levenshtein: 1.0.8
emoji-regex: 9.2.2
@@ -4505,12 +4495,11 @@ snapshots:
dependencies:
eslint: 8.57.0
- eslint-plugin-react@7.34.4(eslint@8.57.0):
+ eslint-plugin-react@7.35.0(eslint@8.57.0):
dependencies:
array-includes: 3.1.8
array.prototype.findlast: 1.2.5
array.prototype.flatmap: 1.3.2
- array.prototype.toreversed: 1.1.2
array.prototype.tosorted: 1.1.4
doctrine: 2.1.0
es-iterator-helpers: 1.0.19
@@ -4555,7 +4544,7 @@ snapshots:
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.3
- debug: 4.3.5
+ debug: 4.3.6
doctrine: 3.0.0
escape-string-regexp: 4.0.0
eslint-scope: 7.2.2
@@ -4707,7 +4696,7 @@ snapshots:
es-errors: 1.3.0
get-intrinsic: 1.2.4
- get-tsconfig@4.7.5:
+ get-tsconfig@4.7.6:
dependencies:
resolve-pkg-maps: 1.0.0
@@ -5010,7 +4999,7 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
- lib0@0.2.94:
+ lib0@0.2.96:
dependencies:
isomorphic.js: 0.2.5
@@ -5052,7 +5041,7 @@ snapshots:
dependencies:
yallist: 4.0.0
- lucide-react@0.408.0(react@18.3.1):
+ lucide-react@0.424.0(react@18.3.1):
dependencies:
react: 18.3.1
@@ -5110,15 +5099,15 @@ snapshots:
next-auth@4.24.7(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
'@panva/hkdf': 1.2.1
cookie: 0.5.0
jose: 4.15.9
next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
oauth: 0.9.15
openid-client: 5.6.5
- preact: 10.22.1
- preact-render-to-string: 5.2.6(preact@10.22.1)
+ preact: 10.23.1
+ preact-render-to-string: 5.2.6(preact@10.23.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
uuid: 8.3.2
@@ -5128,7 +5117,7 @@ snapshots:
'@next/env': 14.2.5
'@swc/helpers': 0.5.5
busboy: 1.6.0
- caniuse-lite: 1.0.30001642
+ caniuse-lite: 1.0.30001649
graceful-fs: 4.2.11
postcss: 8.4.31
react: 18.3.1
@@ -5156,7 +5145,7 @@ snapshots:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- node-releases@2.0.17: {}
+ node-releases@2.0.18: {}
normalize-path@3.0.0: {}
@@ -5276,28 +5265,28 @@ snapshots:
possible-typed-array-names@1.0.0: {}
- postcss-import@15.1.0(postcss@8.4.39):
+ postcss-import@15.1.0(postcss@8.4.40):
dependencies:
- postcss: 8.4.39
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.8
- postcss-js@4.0.1(postcss@8.4.39):
+ postcss-js@4.0.1(postcss@8.4.40):
dependencies:
camelcase-css: 2.0.1
- postcss: 8.4.39
+ postcss: 8.4.40
- postcss-load-config@4.0.2(postcss@8.4.39):
+ postcss-load-config@4.0.2(postcss@8.4.40):
dependencies:
lilconfig: 3.1.2
- yaml: 2.4.5
+ yaml: 2.5.0
optionalDependencies:
- postcss: 8.4.39
+ postcss: 8.4.40
- postcss-nested@6.0.1(postcss@8.4.39):
+ postcss-nested@6.2.0(postcss@8.4.40):
dependencies:
- postcss: 8.4.39
+ postcss: 8.4.40
postcss-selector-parser: 6.1.1
postcss-selector-parser@6.1.1:
@@ -5319,18 +5308,18 @@ snapshots:
picocolors: 1.0.1
source-map-js: 1.2.0
- postcss@8.4.39:
+ postcss@8.4.40:
dependencies:
nanoid: 3.3.7
picocolors: 1.0.1
source-map-js: 1.2.0
- preact-render-to-string@5.2.6(preact@10.22.1):
+ preact-render-to-string@5.2.6(preact@10.23.1):
dependencies:
- preact: 10.22.1
+ preact: 10.23.1
pretty-format: 3.8.0
- preact@10.22.1: {}
+ preact@10.23.1: {}
prelude-ls@1.2.1: {}
@@ -5350,9 +5339,9 @@ snapshots:
dependencies:
prosemirror-state: 1.4.3
- prosemirror-commands@1.5.2:
+ prosemirror-commands@1.6.0:
dependencies:
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
@@ -5360,20 +5349,20 @@ snapshots:
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
- prosemirror-view: 1.33.8
+ prosemirror-view: 1.33.9
prosemirror-gapcursor@1.3.2:
dependencies:
prosemirror-keymap: 1.2.2
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
- prosemirror-view: 1.33.8
+ prosemirror-view: 1.33.9
prosemirror-history@1.4.1:
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
- prosemirror-view: 1.33.8
+ prosemirror-view: 1.33.9
rope-sequence: 1.3.4
prosemirror-inputrules@1.4.0:
@@ -5389,58 +5378,58 @@ snapshots:
prosemirror-markdown@1.13.0:
dependencies:
markdown-it: 14.1.0
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
prosemirror-menu@1.2.4:
dependencies:
crelt: 1.0.6
- prosemirror-commands: 1.5.2
+ prosemirror-commands: 1.6.0
prosemirror-history: 1.4.1
prosemirror-state: 1.4.3
- prosemirror-model@1.22.1:
+ prosemirror-model@1.22.2:
dependencies:
orderedmap: 2.1.1
prosemirror-schema-basic@1.2.3:
dependencies:
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
prosemirror-schema-list@1.4.1:
dependencies:
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
prosemirror-state@1.4.3:
dependencies:
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
prosemirror-transform: 1.9.0
- prosemirror-view: 1.33.8
+ prosemirror-view: 1.33.9
- prosemirror-tables@1.3.7:
+ prosemirror-tables@1.4.0:
dependencies:
prosemirror-keymap: 1.2.2
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
- prosemirror-view: 1.33.8
+ prosemirror-view: 1.33.9
- prosemirror-trailing-node@2.0.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8):
+ prosemirror-trailing-node@2.0.9(prosemirror-model@1.22.2)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9):
dependencies:
'@remirror/core-constants': 2.0.2
escape-string-regexp: 4.0.0
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
- prosemirror-view: 1.33.8
+ prosemirror-view: 1.33.9
prosemirror-transform@1.9.0:
dependencies:
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
- prosemirror-view@1.33.8:
+ prosemirror-view@1.33.9:
dependencies:
- prosemirror-model: 1.22.1
+ prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
@@ -5465,7 +5454,7 @@ snapshots:
react-beautiful-dnd@13.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
css-box-model: 1.2.1
memoize-one: 5.2.1
raf-schd: 4.0.3
@@ -5510,7 +5499,7 @@ snapshots:
react-redux@7.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
'@types/react-redux': 7.1.33
hoist-non-react-statics: 3.3.2
loose-envify: 1.4.0
@@ -5582,7 +5571,7 @@ snapshots:
redux@4.2.1:
dependencies:
- '@babel/runtime': 7.24.8
+ '@babel/runtime': 7.25.0
reflect.getprototypeof@1.0.6:
dependencies:
@@ -5592,7 +5581,7 @@ snapshots:
es-errors: 1.3.0
get-intrinsic: 1.2.4
globalthis: 1.0.4
- which-builtin-type: 1.1.3
+ which-builtin-type: 1.1.4
regenerator-runtime@0.14.1: {}
@@ -5716,7 +5705,7 @@ snapshots:
simple-peer@9.11.1:
dependencies:
buffer: 6.0.3
- debug: 4.3.5
+ debug: 4.3.6
err-code: 3.0.1
get-browser-rtc: 1.1.0
queue-microtask: 1.2.3
@@ -5858,11 +5847,11 @@ snapshots:
tailwind-merge@2.4.0: {}
- tailwind-scrollbar@3.1.0(tailwindcss@3.4.6):
+ tailwind-scrollbar@3.1.0(tailwindcss@3.4.7):
dependencies:
- tailwindcss: 3.4.6
+ tailwindcss: 3.4.7
- tailwindcss@3.4.6:
+ tailwindcss@3.4.7:
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -5878,11 +5867,11 @@ snapshots:
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.0.1
- postcss: 8.4.39
- postcss-import: 15.1.0(postcss@8.4.39)
- postcss-js: 4.0.1(postcss@8.4.39)
- postcss-load-config: 4.0.2(postcss@8.4.39)
- postcss-nested: 6.0.1(postcss@8.4.39)
+ postcss: 8.4.40
+ postcss-import: 15.1.0(postcss@8.4.40)
+ postcss-js: 4.0.1(postcss@8.4.40)
+ postcss-load-config: 4.0.2(postcss@8.4.40)
+ postcss-nested: 6.2.0(postcss@8.4.40)
postcss-selector-parser: 6.1.1
resolve: 1.22.8
sucrase: 3.35.0
@@ -5983,9 +5972,9 @@ snapshots:
undici-types@5.26.5: {}
- update-browserslist-db@1.1.0(browserslist@4.23.2):
+ update-browserslist-db@1.1.0(browserslist@4.23.3):
dependencies:
- browserslist: 4.23.2
+ browserslist: 4.23.3
escalade: 3.1.2
picocolors: 1.0.1
@@ -6032,7 +6021,7 @@ snapshots:
is-string: 1.0.7
is-symbol: 1.0.4
- which-builtin-type@1.1.3:
+ which-builtin-type@1.1.4:
dependencies:
function.prototype.name: 1.1.6
has-tostringtag: 1.0.2
@@ -6086,26 +6075,26 @@ snapshots:
y-indexeddb@9.0.12(yjs@13.6.18):
dependencies:
- lib0: 0.2.94
+ lib0: 0.2.96
yjs: 13.6.18
- y-prosemirror@1.2.9(prosemirror-model@1.22.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.8)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18):
+ y-prosemirror@1.2.11(prosemirror-model@1.22.2)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18):
dependencies:
- lib0: 0.2.94
- prosemirror-model: 1.22.1
+ lib0: 0.2.96
+ prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
- prosemirror-view: 1.33.8
+ prosemirror-view: 1.33.9
y-protocols: 1.0.6(yjs@13.6.18)
yjs: 13.6.18
y-protocols@1.0.6(yjs@13.6.18):
dependencies:
- lib0: 0.2.94
+ lib0: 0.2.96
yjs: 13.6.18
y-webrtc@10.3.0(yjs@13.6.18):
dependencies:
- lib0: 0.2.94
+ lib0: 0.2.96
simple-peer: 9.11.1
y-protocols: 1.0.6(yjs@13.6.18)
yjs: 13.6.18
@@ -6118,11 +6107,11 @@ snapshots:
yallist@4.0.0: {}
- yaml@2.4.5: {}
+ yaml@2.5.0: {}
yjs@13.6.18:
dependencies:
- lib0: 0.2.94
+ lib0: 0.2.96
yocto-queue@0.1.0: {}
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
index bddf86fa..3e558801 100644
--- a/apps/web/services/courses/assignments.ts
+++ b/apps/web/services/courses/assignments.ts
@@ -97,7 +97,21 @@ export async function getAssignmentTaskSubmissionsMe(
access_token: string
) {
const result: any = await fetch(
- `${getAPIUrl()}assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/submissions/user/me`,
+ `${getAPIUrl()}assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/submissions/me`,
+ RequestBodyWithAuthHeader('GET', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
+
+export async function getAssignmentTaskSubmissionsUser(
+ assignmentTaskUUID: string,
+ user_id: string,
+ assignmentUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/submissions/user/${user_id}`,
RequestBodyWithAuthHeader('GET', null, null, access_token)
)
const res = await getResponseMetadata(result)
From ad3f66057ca3b197552eddb09710c6e6cec86523 Mon Sep 17 00:00:00 2001
From: swve
Date: Tue, 6 Aug 2024 18:55:32 +0200
Subject: [PATCH 20/25] feat: enable grading for file subs
---
.../Subs/TaskTypes/TaskFileObject.tsx | 93 +++++++++++++++++--
.../Subs/TaskTypes/TaskQuizObject.tsx | 35 ++++---
.../subpages/Modals/EvaluateAssignment.tsx | 4 +-
.../DraggableElements/ActivityElement.tsx | 2 +-
.../Activities/Assignment/AssignmentBoxUI.tsx | 25 ++++-
.../Assignment/AssignmentStudentActivity.tsx | 2 +-
apps/web/services/media/media.ts | 12 +++
7 files changed, 149 insertions(+), 24 deletions(-)
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
index ff338183..5a5c8d6d 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
@@ -1,9 +1,12 @@
import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext';
import { useLHSession } from '@components/Contexts/LHSessionContext';
+import { useOrg } from '@components/Contexts/OrgContext';
import AssignmentBoxUI from '@components/Objects/Activities/Assignment/AssignmentBoxUI'
-import { getAssignmentTask, getAssignmentTaskSubmissionsMe, handleAssignmentTaskSubmission, updateSubFile } from '@services/courses/assignments';
-import { Cloud, File, Info, Loader, UploadCloud } from 'lucide-react'
+import { getAssignmentTask, getAssignmentTaskSubmissionsMe, getAssignmentTaskSubmissionsUser, handleAssignmentTaskSubmission, updateSubFile } from '@services/courses/assignments';
+import { getTaskFileSubmissionDir } from '@services/media/media';
+import { Cloud, Download, File, Info, Loader, UploadCloud } from 'lucide-react'
+import Link from 'next/link';
import React, { useEffect, useState } from 'react'
import toast from 'react-hot-toast';
@@ -12,12 +15,14 @@ type FileSchema = {
};
type TaskFileObjectProps = {
- view: 'teacher' | 'student';
+ view: 'teacher' | 'student' | 'grading' | 'custom-grading';
assignmentTaskUUID?: string;
+ user_id?: string;
};
-export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObjectProps) {
+export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: TaskFileObjectProps) {
const session = useLHSession() as any;
+ const org = useOrg() as any;
const access_token = session?.data?.tokens?.access_token;
const [isLoading, setIsLoading] = React.useState(false);
const [localUploadFile, setLocalUploadFile] = React.useState(null);
@@ -104,6 +109,7 @@ export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObj
const res = await getAssignmentTask(assignmentTaskUUID, access_token);
if (res.success) {
setAssignmentTask(res.data);
+ setAssignmentTaskOutsideProvider(res.data);
}
}
@@ -120,22 +126,98 @@ export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObj
/* STUDENT VIEW CODE */
+ /* GRADING VIEW CODE */
+ const [userSubmissionObject, setUserSubmissionObject] = useState(null);
+ async function getAssignmentTaskSubmissionFromIdentifiedUserUI() {
+ if (assignmentTaskUUID && user_id) {
+ const res = await getAssignmentTaskSubmissionsUser(assignmentTaskUUID, user_id, assignment.assignment_object.assignment_uuid, access_token);
+ if (res.success) {
+ setUserSubmissions(res.data.task_submission);
+ setUserSubmissionObject(res.data);
+ setInitialUserSubmissions(res.data.task_submission);
+ }
+
+ }
+ }
+
+ async function gradeCustomFC(grade: number) {
+ if (assignmentTaskUUID) {
+ if (grade > assignmentTaskOutsideProvider.max_grade_value) {
+ toast.error(`Grade cannot be more than ${assignmentTaskOutsideProvider.max_grade_value} points`);
+ return;
+ }
+
+
+ // Save the grade to the server
+ const values = {
+ task_submission: userSubmissions,
+ grade: grade,
+ task_submission_grade_feedback: 'Graded by teacher : @' + session.data.user.username,
+ };
+
+ const res = await handleAssignmentTaskSubmission(values, assignmentTaskUUID, assignment.assignment_object.assignment_uuid, access_token);
+ if (res) {
+ getAssignmentTaskSubmissionFromIdentifiedUserUI();
+ toast.success(`Task graded successfully with ${grade} points`);
+ } else {
+ toast.error('Error grading task, please retry later.');
+ }
+ }
+ }
+
+ /* GRADING VIEW CODE */
+ const [assignmentTaskOutsideProvider, setAssignmentTaskOutsideProvider] = useState(null);
useEffect(() => {
+ // Student area
if (view === 'student') {
getAssignmentTaskUI()
getAssignmentTaskSubmissionFromUserUI()
}
+
+ // Grading area
+ else if (view == 'custom-grading') {
+ getAssignmentTaskUI();
+ //setQuestions(assignmentTaskState.assignmentTask.contents.questions);
+ getAssignmentTaskSubmissionFromIdentifiedUserUI();
+ }
}
, [assignmentTaskUUID])
return (
-
+
{view === 'teacher' && (
User will be able to submit a file for this task, you'll be able to review it in the Submissions Tab
)}
+ {view === 'custom-grading' && (
+
+
+
+
Please download the file and grade it manually, then input the grade below
+
+ {userSubmissions.fileUUID && !isLoading && assignmentTaskUUID && (
+
+
+
+
+
+
+
+
+ {`${userSubmissions.fileUUID.slice(0, 8)}...${userSubmissions.fileUUID.slice(-4)}`}
+
+
+
+ )}
+
+ )}
{view === 'student' && (
<>
@@ -213,7 +295,6 @@ export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObj
)}
-
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
index 80460f35..a514c67c 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx
@@ -216,34 +216,47 @@ function TaskQuizObject({ view, assignmentTaskUUID, user_id }: TaskQuizObjectPro
if (assignmentTaskUUID) {
// Ensure maxPoints is defined
const maxPoints = assignmentTaskOutsideProvider?.max_grade_value || 100; // Default to 100 if not defined
-
+
// Ensure userSubmissions.questions are set
const totalQuestions = questions.length;
- const correctQuestions = userSubmissions.submissions.filter((submission) => {
+ let correctQuestions = 0;
+ let incorrectQuestions = 0;
+
+ userSubmissions.submissions.forEach((submission) => {
const question = questions.find((q) => q.questionUUID === submission.questionUUID);
const option = question?.options.find((o) => o.optionUUID === submission.optionUUID);
- return option?.correct;
- }).length;
-
- // Calculate grade based on correct questions
- const grade = Math.floor((correctQuestions / totalQuestions) * maxPoints);
-
+ if (option?.correct) {
+ correctQuestions++;
+ } else {
+ incorrectQuestions++;
+ }
+ });
+
+ // Calculate grade with penalties for incorrect answers
+ const pointsPerQuestion = maxPoints / totalQuestions;
+ const rawGrade = (correctQuestions - incorrectQuestions) * pointsPerQuestion;
+
+ // Ensure the grade is within the valid range
+ const finalGrade = Math.max(0, Math.min(rawGrade, maxPoints));
+
// Save the grade to the server
const values = {
task_submission: userSubmissions,
- grade,
+ grade: finalGrade,
task_submission_grade_feedback: 'Auto graded by system',
};
-
+
const res = await handleAssignmentTaskSubmission(values, assignmentTaskUUID, assignment.assignment_object.assignment_uuid, access_token);
if (res) {
getAssignmentTaskSubmissionFromIdentifiedUserUI();
- toast.success(`Task graded successfully with ${grade} points`);
+ toast.success(`Task graded successfully with ${finalGrade} points`);
} else {
toast.error('Error grading task, please retry later.');
}
}
}
+
+
/* GRADING VIEW CODE */
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/Modals/EvaluateAssignment.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/Modals/EvaluateAssignment.tsx
index 0ef0ac9a..e4c5784a 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/Modals/EvaluateAssignment.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/subpages/Modals/EvaluateAssignment.tsx
@@ -27,7 +27,7 @@ function EvaluateAssignment({ user_id }: any) {
onClick={() => alert(task.hint)}
className='px-3 py-1 flex items-center nice-shadow bg-amber-50/40 text-amber-900 rounded-full space-x-2 cursor-pointer'>
-
View Hint
+
Hint
{task.assignment_type === 'QUIZ' && }
- {task.assignment_type === 'FILE_SUBMISSION' && }
+ {task.assignment_type === 'FILE_SUBMISSION' && }
)
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
index bfb43372..e693ab67 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
@@ -168,7 +168,7 @@ function ActivityElement(props: ActivitiyElementProps) {
) : (
)}
-
{!props.activity.published ? 'Publish' : 'UnPublish'}
+
{!props.activity.published ? 'Publish' : 'Unpublish'}
void
submitFC?: () => void
gradeFC?: () => void
+ gradeCustomFC?: (grade: number) => void
showSavingDisclaimer?: boolean
children: React.ReactNode
}
-function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitFC, gradeFC, showSavingDisclaimer, children }: AssignmentBoxProps) {
+function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitFC, gradeFC, gradeCustomFC, showSavingDisclaimer, children }: AssignmentBoxProps) {
+ const [customGrade, setCustomGrade] = React.useState
(0)
const submission = useAssignmentSubmission() as any
useEffect(() => {
}
, [submission])
+
return (
@@ -89,7 +92,23 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
className='flex px-0.5 py-0.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
Current points : {currentPoints}
+
+ }
+
+ {/* CustomGrading button */}
+ {view === 'custom-grading' && maxPoints &&
+
gradeCustomFC && gradeCustomFC(customGrade)}
+ className='flex px-0.5 py-0.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
+
Current points : {currentPoints}
+
setCustomGrade(parseInt(e.target.value))}
+ placeholder={maxPoints.toString()} className='w-[100px] light-shadow text-sm py-0.5 outline outline-gray-200 rounded-lg px-2' type="number" />
+
diff --git a/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx b/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx
index c7d3dfd0..da4fe81f 100644
--- a/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx
+++ b/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx
@@ -55,7 +55,7 @@ function AssignmentStudentActivity() {
onClick={() => alert(task.hint)}
className='px-3 py-1 flex items-center nice-shadow bg-amber-50/40 text-amber-900 rounded-full space-x-2 cursor-pointer'>
-
View Hint
+
Hint
Date: Tue, 6 Aug 2024 19:17:26 +0200
Subject: [PATCH 21/25] feat: fix poetry issues
---
apps/api/poetry.lock | 1063 +++++++++++++++++++++---------------------
1 file changed, 531 insertions(+), 532 deletions(-)
diff --git a/apps/api/poetry.lock b/apps/api/poetry.lock
index f50ffebf..6f036876 100644
--- a/apps/api/poetry.lock
+++ b/apps/api/poetry.lock
@@ -1,91 +1,103 @@
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
+[[package]]
+name = "aiohappyeyeballs"
+version = "2.3.4"
+description = "Happy Eyeballs for asyncio"
+optional = false
+python-versions = "<4.0,>=3.8"
+files = [
+ {file = "aiohappyeyeballs-2.3.4-py3-none-any.whl", hash = "sha256:40a16ceffcf1fc9e142fd488123b2e218abc4188cf12ac20c67200e1579baa42"},
+ {file = "aiohappyeyeballs-2.3.4.tar.gz", hash = "sha256:7e1ae8399c320a8adec76f6c919ed5ceae6edd4c3672f4d9eae2b27e37c80ff6"},
+]
+
[[package]]
name = "aiohttp"
-version = "3.9.5"
+version = "3.10.1"
description = "Async http client/server framework (asyncio)"
optional = false
python-versions = ">=3.8"
files = [
- {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"},
- {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"},
- {file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"},
- {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"},
- {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"},
- {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"},
- {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"},
- {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"},
- {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"},
- {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"},
- {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"},
- {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"},
- {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"},
- {file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"},
- {file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"},
- {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"},
- {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"},
- {file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"},
- {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"},
- {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"},
- {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"},
- {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"},
- {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"},
- {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"},
- {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"},
- {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"},
- {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"},
- {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"},
- {file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"},
- {file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"},
- {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"},
- {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"},
- {file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"},
- {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"},
- {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"},
- {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"},
- {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"},
- {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"},
- {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"},
- {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"},
- {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"},
- {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"},
- {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"},
- {file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"},
- {file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"},
- {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"},
- {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"},
- {file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"},
- {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"},
- {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"},
- {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"},
- {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"},
- {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"},
- {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"},
- {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"},
- {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"},
- {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"},
- {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"},
- {file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"},
- {file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"},
- {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"},
- {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"},
- {file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"},
- {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"},
- {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"},
- {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"},
- {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"},
- {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"},
- {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"},
- {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"},
- {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"},
- {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"},
- {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"},
- {file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"},
- {file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"},
- {file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"},
+ {file = "aiohttp-3.10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:47b4c2412960e64d97258f40616efddaebcb34ff664c8a972119ed38fac2a62c"},
+ {file = "aiohttp-3.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7dbf637f87dd315fa1f36aaed8afa929ee2c607454fb7791e74c88a0d94da59"},
+ {file = "aiohttp-3.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c8fb76214b5b739ce59e2236a6489d9dc3483649cfd6f563dbf5d8e40dbdd57d"},
+ {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c577cdcf8f92862363b3d598d971c6a84ed8f0bf824d4cc1ce70c2fb02acb4a"},
+ {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:777e23609899cb230ad2642b4bdf1008890f84968be78de29099a8a86f10b261"},
+ {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b07286a1090483799599a2f72f76ac396993da31f6e08efedb59f40876c144fa"},
+ {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9db600a86414a9a653e3c1c7f6a2f6a1894ab8f83d11505247bd1b90ad57157"},
+ {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c3f1eb280008e51965a8d160a108c333136f4a39d46f516c64d2aa2e6a53f2"},
+ {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f5dd109a925fee4c9ac3f6a094900461a2712df41745f5d04782ebcbe6479ccb"},
+ {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8c81ff4afffef9b1186639506d70ea90888218f5ddfff03870e74ec80bb59970"},
+ {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2a384dfbe8bfebd203b778a30a712886d147c61943675f4719b56725a8bbe803"},
+ {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:b9fb6508893dc31cfcbb8191ef35abd79751db1d6871b3e2caee83959b4d91eb"},
+ {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:88596384c3bec644a96ae46287bb646d6a23fa6014afe3799156aef42669c6bd"},
+ {file = "aiohttp-3.10.1-cp310-cp310-win32.whl", hash = "sha256:68164d43c580c2e8bf8e0eb4960142919d304052ccab92be10250a3a33b53268"},
+ {file = "aiohttp-3.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d6bbe2c90c10382ca96df33b56e2060404a4f0f88673e1e84b44c8952517e5f3"},
+ {file = "aiohttp-3.10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f6979b4f20d3e557a867da9d9227de4c156fcdcb348a5848e3e6190fd7feb972"},
+ {file = "aiohttp-3.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03c0c380c83f8a8d4416224aafb88d378376d6f4cadebb56b060688251055cd4"},
+ {file = "aiohttp-3.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c2b104e81b3c3deba7e6f5bc1a9a0e9161c380530479970766a6655b8b77c7c"},
+ {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b023b68c61ab0cd48bd38416b421464a62c381e32b9dc7b4bdfa2905807452a4"},
+ {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a07c76a82390506ca0eabf57c0540cf5a60c993c442928fe4928472c4c6e5e6"},
+ {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:41d8dab8c64ded1edf117d2a64f353efa096c52b853ef461aebd49abae979f16"},
+ {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:615348fab1a9ef7d0960a905e83ad39051ae9cb0d2837da739b5d3a7671e497a"},
+ {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:256ee6044214ee9d66d531bb374f065ee94e60667d6bbeaa25ca111fc3997158"},
+ {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7d5bb926805022508b7ddeaad957f1fce7a8d77532068d7bdb431056dc630cd"},
+ {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:028faf71b338f069077af6315ad54281612705d68889f5d914318cbc2aab0d50"},
+ {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:5c12310d153b27aa630750be44e79313acc4e864c421eb7d2bc6fa3429c41bf8"},
+ {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:de1a91d5faded9054957ed0a9e01b9d632109341942fc123947ced358c5d9009"},
+ {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9c186b270979fb1dee3ababe2d12fb243ed7da08b30abc83ebac3a928a4ddb15"},
+ {file = "aiohttp-3.10.1-cp311-cp311-win32.whl", hash = "sha256:4a9ce70f5e00380377aac0e568abd075266ff992be2e271765f7b35d228a990c"},
+ {file = "aiohttp-3.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:a77c79bac8d908d839d32c212aef2354d2246eb9deb3e2cb01ffa83fb7a6ea5d"},
+ {file = "aiohttp-3.10.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2212296cdb63b092e295c3e4b4b442e7b7eb41e8a30d0f53c16d5962efed395d"},
+ {file = "aiohttp-3.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4dcb127ca3eb0a61205818a606393cbb60d93b7afb9accd2fd1e9081cc533144"},
+ {file = "aiohttp-3.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb8b79a65332e1a426ccb6290ce0409e1dc16b4daac1cc5761e059127fa3d134"},
+ {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68cc24f707ed9cb961f6ee04020ca01de2c89b2811f3cf3361dc7c96a14bfbcc"},
+ {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cb54f5725b4b37af12edf6c9e834df59258c82c15a244daa521a065fbb11717"},
+ {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:51d03e948e53b3639ce4d438f3d1d8202898ec6655cadcc09ec99229d4adc2a9"},
+ {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:786299d719eb5d868f161aeec56d589396b053925b7e0ce36e983d30d0a3e55c"},
+ {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abda4009a30d51d3f06f36bc7411a62b3e647fa6cc935ef667e3e3d3a7dd09b1"},
+ {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:67f7639424c313125213954e93a6229d3a1d386855d70c292a12628f600c7150"},
+ {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8e5a26d7aac4c0d8414a347da162696eea0629fdce939ada6aedf951abb1d745"},
+ {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:120548d89f14b76a041088b582454d89389370632ee12bf39d919cc5c561d1ca"},
+ {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f5293726943bdcea24715b121d8c4ae12581441d22623b0e6ab12d07ce85f9c4"},
+ {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1f8605e573ed6c44ec689d94544b2c4bb1390aaa723a8b5a2cc0a5a485987a68"},
+ {file = "aiohttp-3.10.1-cp312-cp312-win32.whl", hash = "sha256:e7168782621be4448d90169a60c8b37e9b0926b3b79b6097bc180c0a8a119e73"},
+ {file = "aiohttp-3.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fbf8c0ded367c5c8eaf585f85ca8dd85ff4d5b73fb8fe1e6ac9e1b5e62e11f7"},
+ {file = "aiohttp-3.10.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:54b7f4a20d7cc6bfa4438abbde069d417bb7a119f870975f78a2b99890226d55"},
+ {file = "aiohttp-3.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2fa643ca990323db68911b92f3f7a0ca9ae300ae340d0235de87c523601e58d9"},
+ {file = "aiohttp-3.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d8311d0d690487359fe2247ec5d2cac9946e70d50dced8c01ce9e72341c21151"},
+ {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222821c60b8f6a64c5908cb43d69c0ee978a1188f6a8433d4757d39231b42cdb"},
+ {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7b55d9ede66af7feb6de87ff277e0ccf6d51c7db74cc39337fe3a0e31b5872d"},
+ {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a95151a5567b3b00368e99e9c5334a919514f60888a6b6d2054fea5e66e527e"},
+ {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e9e9171d2fe6bfd9d3838a6fe63b1e91b55e0bf726c16edf265536e4eafed19"},
+ {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a57e73f9523e980f6101dc9a83adcd7ac0006ea8bf7937ca3870391c7bb4f8ff"},
+ {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0df51a3d70a2bfbb9c921619f68d6d02591f24f10e9c76de6f3388c89ed01de6"},
+ {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:b0de63ff0307eac3961b4af74382d30220d4813f36b7aaaf57f063a1243b4214"},
+ {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8db9b749f589b5af8e4993623dbda6716b2b7a5fcb0fa2277bf3ce4b278c7059"},
+ {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6b14c19172eb53b63931d3e62a9749d6519f7c121149493e6eefca055fcdb352"},
+ {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5cd57ad998e3038aa87c38fe85c99ed728001bf5dde8eca121cadee06ee3f637"},
+ {file = "aiohttp-3.10.1-cp38-cp38-win32.whl", hash = "sha256:df31641e3f02b77eb3c5fb63c0508bee0fc067cf153da0e002ebbb0db0b6d91a"},
+ {file = "aiohttp-3.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:93094eba50bc2ad4c40ff4997ead1fdcd41536116f2e7d6cfec9596a8ecb3615"},
+ {file = "aiohttp-3.10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:440954ddc6b77257e67170d57b1026aa9545275c33312357472504eef7b4cc0b"},
+ {file = "aiohttp-3.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f9f8beed277488a52ee2b459b23c4135e54d6a819eaba2e120e57311015b58e9"},
+ {file = "aiohttp-3.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d8a8221a63602008550022aa3a4152ca357e1dde7ab3dd1da7e1925050b56863"},
+ {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a702bd3663b5cbf3916e84bf332400d24cdb18399f0877ca6b313ce6c08bfb43"},
+ {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1988b370536eb14f0ce7f3a4a5b422ab64c4e255b3f5d7752c5f583dc8c967fc"},
+ {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ccf1f0a304352c891d124ac1a9dea59b14b2abed1704aaa7689fc90ef9c5be1"},
+ {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc3ea6ef2a83edad84bbdb5d96e22f587b67c68922cd7b6f9d8f24865e655bcf"},
+ {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89b47c125ab07f0831803b88aeb12b04c564d5f07a1c1a225d4eb4d2f26e8b5e"},
+ {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:21778552ef3d44aac3278cc6f6d13a6423504fa5f09f2df34bfe489ed9ded7f5"},
+ {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bde0693073fd5e542e46ea100aa6c1a5d36282dbdbad85b1c3365d5421490a92"},
+ {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:bf66149bb348d8e713f3a8e0b4f5b952094c2948c408e1cfef03b49e86745d60"},
+ {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:587237571a85716d6f71f60d103416c9df7d5acb55d96d3d3ced65f39bff9c0c"},
+ {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bfe33cba6e127d0b5b417623c9aa621f0a69f304742acdca929a9fdab4593693"},
+ {file = "aiohttp-3.10.1-cp39-cp39-win32.whl", hash = "sha256:9fbff00646cf8211b330690eb2fd64b23e1ce5b63a342436c1d1d6951d53d8dd"},
+ {file = "aiohttp-3.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:5951c328f9ac42d7bce7a6ded535879bc9ae13032818d036749631fa27777905"},
+ {file = "aiohttp-3.10.1.tar.gz", hash = "sha256:8b0d058e4e425d3b45e8ec70d49b402f4d6b21041e674798b1f91ba027c73f28"},
]
[package.dependencies]
+aiohappyeyeballs = ">=2.3.0"
aiosignal = ">=1.1.2"
attrs = ">=17.3.0"
frozenlist = ">=1.1.1"
@@ -93,7 +105,7 @@ multidict = ">=4.5,<7.0"
yarl = ">=1.0,<2.0"
[package.extras]
-speedups = ["Brotli", "aiodns", "brotlicffi"]
+speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"]
[[package]]
name = "aiosignal"
@@ -130,13 +142,13 @@ tz = ["backports.zoneinfo"]
[[package]]
name = "alembic-postgresql-enum"
-version = "1.2.0"
+version = "1.3.0"
description = "Alembic autogenerate support for creation, alteration and deletion of enums"
optional = false
python-versions = "<4.0,>=3.7"
files = [
- {file = "alembic_postgresql_enum-1.2.0-py3-none-any.whl", hash = "sha256:bd156e882a10c680fc88ebad25cfe78ccf9f826dec89670f8aeb28e5359e502b"},
- {file = "alembic_postgresql_enum-1.2.0.tar.gz", hash = "sha256:971bd3a4c35ea38869bb5e263ea79e5b4a9c4a02f174a3dd7ddcb29d41260cba"},
+ {file = "alembic_postgresql_enum-1.3.0-py3-none-any.whl", hash = "sha256:42539e225f8b6c9adc9862a259edeed105b02143d55503152eeeea7a0b5af70b"},
+ {file = "alembic_postgresql_enum-1.3.0.tar.gz", hash = "sha256:64d5de7ac2ea39433afd965b057ca882fb420eb5cd6a7db8e2b4d0e7e673cae1"},
]
[package.dependencies]
@@ -179,22 +191,22 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
[[package]]
name = "attrs"
-version = "23.2.0"
+version = "24.2.0"
description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.7"
files = [
- {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"},
- {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"},
+ {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
+ {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
]
[package.extras]
-cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
-dev = ["attrs[tests]", "pre-commit"]
-docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
-tests = ["attrs[tests-no-zope]", "zope-interface"]
-tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"]
-tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"]
+benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
+tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
[[package]]
name = "backoff"
@@ -209,38 +221,38 @@ files = [
[[package]]
name = "bcrypt"
-version = "4.1.3"
+version = "4.2.0"
description = "Modern password hashing for your software and your servers"
optional = false
python-versions = ">=3.7"
files = [
- {file = "bcrypt-4.1.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:48429c83292b57bf4af6ab75809f8f4daf52aa5d480632e53707805cc1ce9b74"},
- {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a8bea4c152b91fd8319fef4c6a790da5c07840421c2b785084989bf8bbb7455"},
- {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d3b317050a9a711a5c7214bf04e28333cf528e0ed0ec9a4e55ba628d0f07c1a"},
- {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:094fd31e08c2b102a14880ee5b3d09913ecf334cd604af27e1013c76831f7b05"},
- {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:4fb253d65da30d9269e0a6f4b0de32bd657a0208a6f4e43d3e645774fb5457f3"},
- {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:193bb49eeeb9c1e2db9ba65d09dc6384edd5608d9d672b4125e9320af9153a15"},
- {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:8cbb119267068c2581ae38790e0d1fbae65d0725247a930fc9900c285d95725d"},
- {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6cac78a8d42f9d120b3987f82252bdbeb7e6e900a5e1ba37f6be6fe4e3848286"},
- {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:01746eb2c4299dd0ae1670234bf77704f581dd72cc180f444bfe74eb80495b64"},
- {file = "bcrypt-4.1.3-cp37-abi3-win32.whl", hash = "sha256:037c5bf7c196a63dcce75545c8874610c600809d5d82c305dd327cd4969995bf"},
- {file = "bcrypt-4.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:8a893d192dfb7c8e883c4576813bf18bb9d59e2cfd88b68b725990f033f1b978"},
- {file = "bcrypt-4.1.3-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d4cf6ef1525f79255ef048b3489602868c47aea61f375377f0d00514fe4a78c"},
- {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5698ce5292a4e4b9e5861f7e53b1d89242ad39d54c3da451a93cac17b61921a"},
- {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec3c2e1ca3e5c4b9edb94290b356d082b721f3f50758bce7cce11d8a7c89ce84"},
- {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3a5be252fef513363fe281bafc596c31b552cf81d04c5085bc5dac29670faa08"},
- {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5f7cd3399fbc4ec290378b541b0cf3d4398e4737a65d0f938c7c0f9d5e686611"},
- {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:c4c8d9b3e97209dd7111bf726e79f638ad9224b4691d1c7cfefa571a09b1b2d6"},
- {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:31adb9cbb8737a581a843e13df22ffb7c84638342de3708a98d5c986770f2834"},
- {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:551b320396e1d05e49cc18dd77d970accd52b322441628aca04801bbd1d52a73"},
- {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6717543d2c110a155e6821ce5670c1f512f602eabb77dba95717ca76af79867d"},
- {file = "bcrypt-4.1.3-cp39-abi3-win32.whl", hash = "sha256:6004f5229b50f8493c49232b8e75726b568535fd300e5039e255d919fc3a07f2"},
- {file = "bcrypt-4.1.3-cp39-abi3-win_amd64.whl", hash = "sha256:2505b54afb074627111b5a8dc9b6ae69d0f01fea65c2fcaea403448c503d3991"},
- {file = "bcrypt-4.1.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:cb9c707c10bddaf9e5ba7cdb769f3e889e60b7d4fea22834b261f51ca2b89fed"},
- {file = "bcrypt-4.1.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9f8ea645eb94fb6e7bea0cf4ba121c07a3a182ac52876493870033141aa687bc"},
- {file = "bcrypt-4.1.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f44a97780677e7ac0ca393bd7982b19dbbd8d7228c1afe10b128fd9550eef5f1"},
- {file = "bcrypt-4.1.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d84702adb8f2798d813b17d8187d27076cca3cd52fe3686bb07a9083930ce650"},
- {file = "bcrypt-4.1.3.tar.gz", hash = "sha256:2ee15dd749f5952fe3f0430d0ff6b74082e159c50332a1413d51b5689cf06623"},
+ {file = "bcrypt-4.2.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb"},
+ {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00"},
+ {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d"},
+ {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291"},
+ {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328"},
+ {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7"},
+ {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399"},
+ {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060"},
+ {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7"},
+ {file = "bcrypt-4.2.0-cp37-abi3-win32.whl", hash = "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458"},
+ {file = "bcrypt-4.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5"},
+ {file = "bcrypt-4.2.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841"},
+ {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68"},
+ {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe"},
+ {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2"},
+ {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c"},
+ {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae"},
+ {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d"},
+ {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e"},
+ {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8"},
+ {file = "bcrypt-4.2.0-cp39-abi3-win32.whl", hash = "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34"},
+ {file = "bcrypt-4.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9"},
+ {file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a"},
+ {file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db"},
+ {file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170"},
+ {file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184"},
+ {file = "bcrypt-4.2.0.tar.gz", hash = "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221"},
]
[package.extras]
@@ -249,17 +261,17 @@ typecheck = ["mypy"]
[[package]]
name = "boto3"
-version = "1.34.143"
+version = "1.34.154"
description = "The AWS SDK for Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "boto3-1.34.143-py3-none-any.whl", hash = "sha256:0d16832f23e6bd3ae94e35ea8e625529850bfad9baccd426de96ad8f445d8e03"},
- {file = "boto3-1.34.143.tar.gz", hash = "sha256:b590ce80c65149194def43ebf0ea1cf0533945502507837389a8d22e3ecbcf05"},
+ {file = "boto3-1.34.154-py3-none-any.whl", hash = "sha256:7ca22adef4c77ee128e1e1dc7d48bc9512a87cc6fe3d771b3f913d5ecd41c057"},
+ {file = "boto3-1.34.154.tar.gz", hash = "sha256:864f06528c583dc7b02adf12db395ecfadbf9cb0da90e907e848ffb27128ce19"},
]
[package.dependencies]
-botocore = ">=1.34.143,<1.35.0"
+botocore = ">=1.34.154,<1.35.0"
jmespath = ">=0.7.1,<2.0.0"
s3transfer = ">=0.10.0,<0.11.0"
@@ -268,13 +280,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
[[package]]
name = "botocore"
-version = "1.34.143"
+version = "1.34.154"
description = "Low-level, data-driven core of boto 3."
optional = false
python-versions = ">=3.8"
files = [
- {file = "botocore-1.34.143-py3-none-any.whl", hash = "sha256:094aea179e8aaa1bc957ad49cc27d93b189dd3a1f3075d8b0ca7c445a2a88430"},
- {file = "botocore-1.34.143.tar.gz", hash = "sha256:059f032ec05733a836e04e869c5a15534420102f93116f3bc9a5b759b0651caf"},
+ {file = "botocore-1.34.154-py3-none-any.whl", hash = "sha256:4eef4b1bb809b382ba9dc9c88f5fcc4a133f221a1acb693ee6bee4de9f325979"},
+ {file = "botocore-1.34.154.tar.gz", hash = "sha256:64d9b4c85a504d77cb56dabb2ad717cd8e1717424a88edb458b01d1e5797262a"},
]
[package.dependencies]
@@ -310,13 +322,13 @@ virtualenv = ["virtualenv (>=20.0.35)"]
[[package]]
name = "cachetools"
-version = "5.3.3"
+version = "5.4.0"
description = "Extensible memoizing collections and decorators"
optional = false
python-versions = ">=3.7"
files = [
- {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"},
- {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"},
+ {file = "cachetools-5.4.0-py3-none-any.whl", hash = "sha256:3ae3b49a3d5e28a77a0be2b37dbcb89005058959cb2323858c2657c4a8cab474"},
+ {file = "cachetools-5.4.0.tar.gz", hash = "sha256:b8adc2e7c07f105ced7bc56dbb6dfbe7c4a00acce20e2227b3f355be89bc6827"},
]
[[package]]
@@ -431,36 +443,40 @@ files = [
[[package]]
name = "chroma-hnswlib"
-version = "0.7.3"
+version = "0.7.6"
description = "Chromas fork of hnswlib"
optional = false
python-versions = "*"
files = [
- {file = "chroma-hnswlib-0.7.3.tar.gz", hash = "sha256:b6137bedde49fffda6af93b0297fe00429fc61e5a072b1ed9377f909ed95a932"},
- {file = "chroma_hnswlib-0.7.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:59d6a7c6f863c67aeb23e79a64001d537060b6995c3eca9a06e349ff7b0998ca"},
- {file = "chroma_hnswlib-0.7.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d71a3f4f232f537b6152947006bd32bc1629a8686df22fd97777b70f416c127a"},
- {file = "chroma_hnswlib-0.7.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c92dc1ebe062188e53970ba13f6b07e0ae32e64c9770eb7f7ffa83f149d4210"},
- {file = "chroma_hnswlib-0.7.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49da700a6656fed8753f68d44b8cc8ae46efc99fc8a22a6d970dc1697f49b403"},
- {file = "chroma_hnswlib-0.7.3-cp310-cp310-win_amd64.whl", hash = "sha256:108bc4c293d819b56476d8f7865803cb03afd6ca128a2a04d678fffc139af029"},
- {file = "chroma_hnswlib-0.7.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:11e7ca93fb8192214ac2b9c0943641ac0daf8f9d4591bb7b73be808a83835667"},
- {file = "chroma_hnswlib-0.7.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6f552e4d23edc06cdeb553cdc757d2fe190cdeb10d43093d6a3319f8d4bf1c6b"},
- {file = "chroma_hnswlib-0.7.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f96f4d5699e486eb1fb95849fe35ab79ab0901265805be7e60f4eaa83ce263ec"},
- {file = "chroma_hnswlib-0.7.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:368e57fe9ebae05ee5844840fa588028a023d1182b0cfdb1d13f607c9ea05756"},
- {file = "chroma_hnswlib-0.7.3-cp311-cp311-win_amd64.whl", hash = "sha256:b7dca27b8896b494456db0fd705b689ac6b73af78e186eb6a42fea2de4f71c6f"},
- {file = "chroma_hnswlib-0.7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:70f897dc6218afa1d99f43a9ad5eb82f392df31f57ff514ccf4eeadecd62f544"},
- {file = "chroma_hnswlib-0.7.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aef10b4952708f5a1381c124a29aead0c356f8d7d6e0b520b778aaa62a356f4"},
- {file = "chroma_hnswlib-0.7.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee2d8d1529fca3898d512079144ec3e28a81d9c17e15e0ea4665697a7923253"},
- {file = "chroma_hnswlib-0.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:a4021a70e898783cd6f26e00008b494c6249a7babe8774e90ce4766dd288c8ba"},
- {file = "chroma_hnswlib-0.7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a8f61fa1d417fda848e3ba06c07671f14806a2585272b175ba47501b066fe6b1"},
- {file = "chroma_hnswlib-0.7.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d7563be58bc98e8f0866907368e22ae218d6060601b79c42f59af4eccbbd2e0a"},
- {file = "chroma_hnswlib-0.7.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51b8d411486ee70d7b66ec08cc8b9b6620116b650df9c19076d2d8b6ce2ae914"},
- {file = "chroma_hnswlib-0.7.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d706782b628e4f43f1b8a81e9120ac486837fbd9bcb8ced70fe0d9b95c72d77"},
- {file = "chroma_hnswlib-0.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:54f053dedc0e3ba657f05fec6e73dd541bc5db5b09aa8bc146466ffb734bdc86"},
- {file = "chroma_hnswlib-0.7.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e607c5a71c610a73167a517062d302c0827ccdd6e259af6e4869a5c1306ffb5d"},
- {file = "chroma_hnswlib-0.7.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2358a795870156af6761890f9eb5ca8cade57eb10c5f046fe94dae1faa04b9e"},
- {file = "chroma_hnswlib-0.7.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cea425df2e6b8a5e201fff0d922a1cc1d165b3cfe762b1408075723c8892218"},
- {file = "chroma_hnswlib-0.7.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:454df3dd3e97aa784fba7cf888ad191e0087eef0fd8c70daf28b753b3b591170"},
- {file = "chroma_hnswlib-0.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:df587d15007ca701c6de0ee7d5585dd5e976b7edd2b30ac72bc376b3c3f85882"},
+ {file = "chroma_hnswlib-0.7.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f35192fbbeadc8c0633f0a69c3d3e9f1a4eab3a46b65458bbcbcabdd9e895c36"},
+ {file = "chroma_hnswlib-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f007b608c96362b8f0c8b6b2ac94f67f83fcbabd857c378ae82007ec92f4d82"},
+ {file = "chroma_hnswlib-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:456fd88fa0d14e6b385358515aef69fc89b3c2191706fd9aee62087b62aad09c"},
+ {file = "chroma_hnswlib-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dfaae825499c2beaa3b75a12d7ec713b64226df72a5c4097203e3ed532680da"},
+ {file = "chroma_hnswlib-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:2487201982241fb1581be26524145092c95902cb09fc2646ccfbc407de3328ec"},
+ {file = "chroma_hnswlib-0.7.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:81181d54a2b1e4727369486a631f977ffc53c5533d26e3d366dda243fb0998ca"},
+ {file = "chroma_hnswlib-0.7.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4b4ab4e11f1083dd0a11ee4f0e0b183ca9f0f2ed63ededba1935b13ce2b3606f"},
+ {file = "chroma_hnswlib-0.7.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53db45cd9173d95b4b0bdccb4dbff4c54a42b51420599c32267f3abbeb795170"},
+ {file = "chroma_hnswlib-0.7.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c093f07a010b499c00a15bc9376036ee4800d335360570b14f7fe92badcdcf9"},
+ {file = "chroma_hnswlib-0.7.6-cp311-cp311-win_amd64.whl", hash = "sha256:0540b0ac96e47d0aa39e88ea4714358ae05d64bbe6bf33c52f316c664190a6a3"},
+ {file = "chroma_hnswlib-0.7.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e87e9b616c281bfbe748d01705817c71211613c3b063021f7ed5e47173556cb7"},
+ {file = "chroma_hnswlib-0.7.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ec5ca25bc7b66d2ecbf14502b5729cde25f70945d22f2aaf523c2d747ea68912"},
+ {file = "chroma_hnswlib-0.7.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305ae491de9d5f3c51e8bd52d84fdf2545a4a2bc7af49765cda286b7bb30b1d4"},
+ {file = "chroma_hnswlib-0.7.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:822ede968d25a2c88823ca078a58f92c9b5c4142e38c7c8b4c48178894a0a3c5"},
+ {file = "chroma_hnswlib-0.7.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2fe6ea949047beed19a94b33f41fe882a691e58b70c55fdaa90274ae78be046f"},
+ {file = "chroma_hnswlib-0.7.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feceff971e2a2728c9ddd862a9dd6eb9f638377ad98438876c9aeac96c9482f5"},
+ {file = "chroma_hnswlib-0.7.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb0633b60e00a2b92314d0bf5bbc0da3d3320be72c7e3f4a9b19f4609dc2b2ab"},
+ {file = "chroma_hnswlib-0.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:a566abe32fab42291f766d667bdbfa234a7f457dcbd2ba19948b7a978c8ca624"},
+ {file = "chroma_hnswlib-0.7.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6be47853d9a58dedcfa90fc846af202b071f028bbafe1d8711bf64fe5a7f6111"},
+ {file = "chroma_hnswlib-0.7.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a7af35bdd39a88bffa49f9bb4bf4f9040b684514a024435a1ef5cdff980579d"},
+ {file = "chroma_hnswlib-0.7.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a53b1f1551f2b5ad94eb610207bde1bb476245fc5097a2bec2b476c653c58bde"},
+ {file = "chroma_hnswlib-0.7.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3085402958dbdc9ff5626ae58d696948e715aef88c86d1e3f9285a88f1afd3bc"},
+ {file = "chroma_hnswlib-0.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:77326f658a15adfb806a16543f7db7c45f06fd787d699e643642d6bde8ed49c4"},
+ {file = "chroma_hnswlib-0.7.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:93b056ab4e25adab861dfef21e1d2a2756b18be5bc9c292aa252fa12bb44e6ae"},
+ {file = "chroma_hnswlib-0.7.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fe91f018b30452c16c811fd6c8ede01f84e5a9f3c23e0758775e57f1c3778871"},
+ {file = "chroma_hnswlib-0.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6c0e627476f0f4d9e153420d36042dd9c6c3671cfd1fe511c0253e38c2a1039"},
+ {file = "chroma_hnswlib-0.7.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e9796a4536b7de6c6d76a792ba03e08f5aaa53e97e052709568e50b4d20c04f"},
+ {file = "chroma_hnswlib-0.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:d30e2db08e7ffdcc415bd072883a322de5995eb6ec28a8f8c054103bbd3ec1e0"},
+ {file = "chroma_hnswlib-0.7.6.tar.gz", hash = "sha256:4dce282543039681160259d29fcde6151cc9106c6461e0485f57cdccd83059b7"},
]
[package.dependencies]
@@ -468,19 +484,19 @@ numpy = "*"
[[package]]
name = "chromadb"
-version = "0.5.3"
+version = "0.5.5"
description = "Chroma."
optional = false
python-versions = ">=3.8"
files = [
- {file = "chromadb-0.5.3-py3-none-any.whl", hash = "sha256:b3874f08356e291c68c6d2e177db472cd51f22f3af7b9746215b748fd1e29982"},
- {file = "chromadb-0.5.3.tar.gz", hash = "sha256:05d887f56a46b2e0fc6ac5ab979503a27b9ee50d5ca9e455f83b2fb9840cd026"},
+ {file = "chromadb-0.5.5-py3-none-any.whl", hash = "sha256:2a5a4b84cb0fc32b380e193be68cdbadf3d9f77dbbf141649be9886e42910ddd"},
+ {file = "chromadb-0.5.5.tar.gz", hash = "sha256:84f4bfee320fb4912cbeb4d738f01690891e9894f0ba81f39ee02867102a1c4d"},
]
[package.dependencies]
bcrypt = ">=4.0.1"
build = ">=1.0.3"
-chroma-hnswlib = "0.7.3"
+chroma-hnswlib = "0.7.6"
fastapi = ">=0.95.2"
grpcio = ">=1.58.0"
httpx = ">=0.27.0"
@@ -499,7 +515,6 @@ posthog = ">=2.4.0"
pydantic = ">=1.9"
pypika = ">=0.48.9"
PyYAML = ">=6.0.0"
-requests = ">=2.28"
tenacity = ">=8.2.3"
tokenizers = ">=0.13.2"
tqdm = ">=4.65.0"
@@ -661,13 +676,13 @@ python-dateutil = ">=2.4"
[[package]]
name = "fastapi"
-version = "0.111.0"
+version = "0.111.1"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
optional = false
python-versions = ">=3.8"
files = [
- {file = "fastapi-0.111.0-py3-none-any.whl", hash = "sha256:97ecbf994be0bcbdadedf88c3150252bed7b2087075ac99735403b1b76cc8fc0"},
- {file = "fastapi-0.111.0.tar.gz", hash = "sha256:b9db9dd147c91cb8b769f7183535773d8741dd46f9dc6676cd82eab510228cd7"},
+ {file = "fastapi-0.111.1-py3-none-any.whl", hash = "sha256:4f51cfa25d72f9fbc3280832e84b32494cf186f50158d364a8765aabf22587bf"},
+ {file = "fastapi-0.111.1.tar.gz", hash = "sha256:ddd1ac34cb1f76c2e2d7f8545a4bcb5463bce4834e81abf0b189e0c359ab2413"},
]
[package.dependencies]
@@ -675,12 +690,10 @@ email_validator = ">=2.0.0"
fastapi-cli = ">=0.0.2"
httpx = ">=0.23.0"
jinja2 = ">=2.11.2"
-orjson = ">=3.2.1"
pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
python-multipart = ">=0.0.7"
starlette = ">=0.37.2,<0.38.0"
typing-extensions = ">=4.8.0"
-ujson = ">=4.0.1,<4.0.2 || >4.0.2,<4.1.0 || >4.1.0,<4.2.0 || >4.2.0,<4.3.0 || >4.3.0,<5.0.0 || >5.0.0,<5.1.0 || >5.1.0"
uvicorn = {version = ">=0.12.0", extras = ["standard"]}
[package.extras]
@@ -688,20 +701,21 @@ all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)"
[[package]]
name = "fastapi-cli"
-version = "0.0.4"
+version = "0.0.5"
description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀"
optional = false
python-versions = ">=3.8"
files = [
- {file = "fastapi_cli-0.0.4-py3-none-any.whl", hash = "sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809"},
- {file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"},
+ {file = "fastapi_cli-0.0.5-py3-none-any.whl", hash = "sha256:e94d847524648c748a5350673546bbf9bcaeb086b33c24f2e82e021436866a46"},
+ {file = "fastapi_cli-0.0.5.tar.gz", hash = "sha256:d30e1239c6f46fcb95e606f02cdda59a1e2fa778a54b64686b3ff27f6211ff9f"},
]
[package.dependencies]
typer = ">=0.12.3"
+uvicorn = {version = ">=0.15.0", extras = ["standard"]}
[package.extras]
-standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"]
+standard = ["uvicorn[standard] (>=0.15.0)"]
[[package]]
name = "fastapi-jwt-auth"
@@ -989,61 +1003,61 @@ test = ["objgraph", "psutil"]
[[package]]
name = "grpcio"
-version = "1.64.1"
+version = "1.65.4"
description = "HTTP/2-based RPC framework"
optional = false
python-versions = ">=3.8"
files = [
- {file = "grpcio-1.64.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:55697ecec192bc3f2f3cc13a295ab670f51de29884ca9ae6cd6247df55df2502"},
- {file = "grpcio-1.64.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3b64ae304c175671efdaa7ec9ae2cc36996b681eb63ca39c464958396697daff"},
- {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:bac71b4b28bc9af61efcdc7630b166440bbfbaa80940c9a697271b5e1dabbc61"},
- {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c024ffc22d6dc59000faf8ad781696d81e8e38f4078cb0f2630b4a3cf231a90"},
- {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7cd5c1325f6808b8ae31657d281aadb2a51ac11ab081ae335f4f7fc44c1721d"},
- {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0a2813093ddb27418a4c99f9b1c223fab0b053157176a64cc9db0f4557b69bd9"},
- {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2981c7365a9353f9b5c864595c510c983251b1ab403e05b1ccc70a3d9541a73b"},
- {file = "grpcio-1.64.1-cp310-cp310-win32.whl", hash = "sha256:1262402af5a511c245c3ae918167eca57342c72320dffae5d9b51840c4b2f86d"},
- {file = "grpcio-1.64.1-cp310-cp310-win_amd64.whl", hash = "sha256:19264fc964576ddb065368cae953f8d0514ecc6cb3da8903766d9fb9d4554c33"},
- {file = "grpcio-1.64.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:58b1041e7c870bb30ee41d3090cbd6f0851f30ae4eb68228955d973d3efa2e61"},
- {file = "grpcio-1.64.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bbc5b1d78a7822b0a84c6f8917faa986c1a744e65d762ef6d8be9d75677af2ca"},
- {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:5841dd1f284bd1b3d8a6eca3a7f062b06f1eec09b184397e1d1d43447e89a7ae"},
- {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8caee47e970b92b3dd948371230fcceb80d3f2277b3bf7fbd7c0564e7d39068e"},
- {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73819689c169417a4f978e562d24f2def2be75739c4bed1992435d007819da1b"},
- {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6503b64c8b2dfad299749cad1b595c650c91e5b2c8a1b775380fcf8d2cbba1e9"},
- {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1de403fc1305fd96cfa75e83be3dee8538f2413a6b1685b8452301c7ba33c294"},
- {file = "grpcio-1.64.1-cp311-cp311-win32.whl", hash = "sha256:d4d29cc612e1332237877dfa7fe687157973aab1d63bd0f84cf06692f04c0367"},
- {file = "grpcio-1.64.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e56462b05a6f860b72f0fa50dca06d5b26543a4e88d0396259a07dc30f4e5aa"},
- {file = "grpcio-1.64.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:4657d24c8063e6095f850b68f2d1ba3b39f2b287a38242dcabc166453e950c59"},
- {file = "grpcio-1.64.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:62b4e6eb7bf901719fce0ca83e3ed474ae5022bb3827b0a501e056458c51c0a1"},
- {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:ee73a2f5ca4ba44fa33b4d7d2c71e2c8a9e9f78d53f6507ad68e7d2ad5f64a22"},
- {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:198908f9b22e2672a998870355e226a725aeab327ac4e6ff3a1399792ece4762"},
- {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b9d0acaa8d835a6566c640f48b50054f422d03e77e49716d4c4e8e279665a1"},
- {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5e42634a989c3aa6049f132266faf6b949ec2a6f7d302dbb5c15395b77d757eb"},
- {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1a82e0b9b3022799c336e1fc0f6210adc019ae84efb7321d668129d28ee1efb"},
- {file = "grpcio-1.64.1-cp312-cp312-win32.whl", hash = "sha256:55260032b95c49bee69a423c2f5365baa9369d2f7d233e933564d8a47b893027"},
- {file = "grpcio-1.64.1-cp312-cp312-win_amd64.whl", hash = "sha256:c1a786ac592b47573a5bb7e35665c08064a5d77ab88a076eec11f8ae86b3e3f6"},
- {file = "grpcio-1.64.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:a011ac6c03cfe162ff2b727bcb530567826cec85eb8d4ad2bfb4bd023287a52d"},
- {file = "grpcio-1.64.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4d6dab6124225496010bd22690f2d9bd35c7cbb267b3f14e7a3eb05c911325d4"},
- {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a5e771d0252e871ce194d0fdcafd13971f1aae0ddacc5f25615030d5df55c3a2"},
- {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3c1b90ab93fed424e454e93c0ed0b9d552bdf1b0929712b094f5ecfe7a23ad"},
- {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20405cb8b13fd779135df23fabadc53b86522d0f1cba8cca0e87968587f50650"},
- {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0cc79c982ccb2feec8aad0e8fb0d168bcbca85bc77b080d0d3c5f2f15c24ea8f"},
- {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a3a035c37ce7565b8f4f35ff683a4db34d24e53dc487e47438e434eb3f701b2a"},
- {file = "grpcio-1.64.1-cp38-cp38-win32.whl", hash = "sha256:1257b76748612aca0f89beec7fa0615727fd6f2a1ad580a9638816a4b2eb18fd"},
- {file = "grpcio-1.64.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a12ddb1678ebc6a84ec6b0487feac020ee2b1659cbe69b80f06dbffdb249122"},
- {file = "grpcio-1.64.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:75dbbf415026d2862192fe1b28d71f209e2fd87079d98470db90bebe57b33179"},
- {file = "grpcio-1.64.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e3d9f8d1221baa0ced7ec7322a981e28deb23749c76eeeb3d33e18b72935ab62"},
- {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5f8b75f64d5d324c565b263c67dbe4f0af595635bbdd93bb1a88189fc62ed2e5"},
- {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c84ad903d0d94311a2b7eea608da163dace97c5fe9412ea311e72c3684925602"},
- {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940e3ec884520155f68a3b712d045e077d61c520a195d1a5932c531f11883489"},
- {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f10193c69fc9d3d726e83bbf0f3d316f1847c3071c8c93d8090cf5f326b14309"},
- {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac15b6c2c80a4d1338b04d42a02d376a53395ddf0ec9ab157cbaf44191f3ffdd"},
- {file = "grpcio-1.64.1-cp39-cp39-win32.whl", hash = "sha256:03b43d0ccf99c557ec671c7dede64f023c7da9bb632ac65dbc57f166e4970040"},
- {file = "grpcio-1.64.1-cp39-cp39-win_amd64.whl", hash = "sha256:ed6091fa0adcc7e4ff944090cf203a52da35c37a130efa564ded02b7aff63bcd"},
- {file = "grpcio-1.64.1.tar.gz", hash = "sha256:8d51dd1c59d5fa0f34266b80a3805ec29a1f26425c2a54736133f6d87fc4968a"},
+ {file = "grpcio-1.65.4-cp310-cp310-linux_armv7l.whl", hash = "sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c"},
+ {file = "grpcio-1.65.4-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a"},
+ {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8"},
+ {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82"},
+ {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e"},
+ {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de"},
+ {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d"},
+ {file = "grpcio-1.65.4-cp310-cp310-win32.whl", hash = "sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1"},
+ {file = "grpcio-1.65.4-cp310-cp310-win_amd64.whl", hash = "sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec"},
+ {file = "grpcio-1.65.4-cp311-cp311-linux_armv7l.whl", hash = "sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef"},
+ {file = "grpcio-1.65.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18"},
+ {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8"},
+ {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17"},
+ {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4"},
+ {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e"},
+ {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5"},
+ {file = "grpcio-1.65.4-cp311-cp311-win32.whl", hash = "sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b"},
+ {file = "grpcio-1.65.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558"},
+ {file = "grpcio-1.65.4-cp312-cp312-linux_armv7l.whl", hash = "sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56"},
+ {file = "grpcio-1.65.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2"},
+ {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e"},
+ {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74"},
+ {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63"},
+ {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a"},
+ {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28"},
+ {file = "grpcio-1.65.4-cp312-cp312-win32.whl", hash = "sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0"},
+ {file = "grpcio-1.65.4-cp312-cp312-win_amd64.whl", hash = "sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416"},
+ {file = "grpcio-1.65.4-cp38-cp38-linux_armv7l.whl", hash = "sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021"},
+ {file = "grpcio-1.65.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52"},
+ {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385"},
+ {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864"},
+ {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816"},
+ {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524"},
+ {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7"},
+ {file = "grpcio-1.65.4-cp38-cp38-win32.whl", hash = "sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a"},
+ {file = "grpcio-1.65.4-cp38-cp38-win_amd64.whl", hash = "sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f"},
+ {file = "grpcio-1.65.4-cp39-cp39-linux_armv7l.whl", hash = "sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733"},
+ {file = "grpcio-1.65.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4"},
+ {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe"},
+ {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1"},
+ {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b"},
+ {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2"},
+ {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257"},
+ {file = "grpcio-1.65.4-cp39-cp39-win32.whl", hash = "sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d"},
+ {file = "grpcio-1.65.4-cp39-cp39-win_amd64.whl", hash = "sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9"},
+ {file = "grpcio-1.65.4.tar.gz", hash = "sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39"},
]
[package.extras]
-protobuf = ["grpcio-tools (>=1.64.1)"]
+protobuf = ["grpcio-tools (>=1.65.4)"]
[[package]]
name = "h11"
@@ -1151,13 +1165,13 @@ socks = ["socksio (==1.*)"]
[[package]]
name = "huggingface-hub"
-version = "0.23.4"
+version = "0.24.5"
description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
optional = false
python-versions = ">=3.8.0"
files = [
- {file = "huggingface_hub-0.23.4-py3-none-any.whl", hash = "sha256:3a0b957aa87150addf0cc7bd71b4d954b78e749850e1e7fb29ebbd2db64ca037"},
- {file = "huggingface_hub-0.23.4.tar.gz", hash = "sha256:35d99016433900e44ae7efe1c209164a5a81dbbcd53a52f99c281dcd7ce22431"},
+ {file = "huggingface_hub-0.24.5-py3-none-any.whl", hash = "sha256:d93fb63b1f1a919a22ce91a14518974e81fc4610bf344dfe7572343ce8d3aced"},
+ {file = "huggingface_hub-0.24.5.tar.gz", hash = "sha256:7b45d6744dd53ce9cbf9880957de00e9d10a9ae837f1c9b7255fc8fa4e8264f3"},
]
[package.dependencies]
@@ -1170,17 +1184,17 @@ tqdm = ">=4.42.1"
typing-extensions = ">=3.7.4.3"
[package.extras]
-all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.3.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
+all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
cli = ["InquirerPy (==0.3.4)"]
-dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.3.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
+dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"]
hf-transfer = ["hf-transfer (>=0.1.4)"]
inference = ["aiohttp", "minijinja (>=1.0)"]
-quality = ["mypy (==1.5.1)", "ruff (>=0.3.0)"]
+quality = ["mypy (==1.5.1)", "ruff (>=0.5.0)"]
tensorflow = ["graphviz", "pydot", "tensorflow"]
tensorflow-testing = ["keras (<3.0)", "tensorflow"]
-testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"]
-torch = ["safetensors", "torch"]
+testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"]
+torch = ["safetensors[torch]", "torch"]
typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"]
[[package]]
@@ -1210,22 +1224,22 @@ files = [
[[package]]
name = "importlib-metadata"
-version = "7.1.0"
+version = "8.0.0"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.8"
files = [
- {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"},
- {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"},
+ {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"},
+ {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"},
]
[package.dependencies]
zipp = ">=0.5"
[package.extras]
-docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
perf = ["ipython"]
-testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"]
+test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"]
[[package]]
name = "importlib-resources"
@@ -1270,6 +1284,76 @@ MarkupSafe = ">=2.0"
[package.extras]
i18n = ["Babel (>=2.7)"]
+[[package]]
+name = "jiter"
+version = "0.5.0"
+description = "Fast iterable JSON parser."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jiter-0.5.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b599f4e89b3def9a94091e6ee52e1d7ad7bc33e238ebb9c4c63f211d74822c3f"},
+ {file = "jiter-0.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a063f71c4b06225543dddadbe09d203dc0c95ba352d8b85f1221173480a71d5"},
+ {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acc0d5b8b3dd12e91dd184b87273f864b363dfabc90ef29a1092d269f18c7e28"},
+ {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c22541f0b672f4d741382a97c65609332a783501551445ab2df137ada01e019e"},
+ {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:63314832e302cc10d8dfbda0333a384bf4bcfce80d65fe99b0f3c0da8945a91a"},
+ {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a25fbd8a5a58061e433d6fae6d5298777c0814a8bcefa1e5ecfff20c594bd749"},
+ {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:503b2c27d87dfff5ab717a8200fbbcf4714516c9d85558048b1fc14d2de7d8dc"},
+ {file = "jiter-0.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d1f3d27cce923713933a844872d213d244e09b53ec99b7a7fdf73d543529d6d"},
+ {file = "jiter-0.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c95980207b3998f2c3b3098f357994d3fd7661121f30669ca7cb945f09510a87"},
+ {file = "jiter-0.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afa66939d834b0ce063f57d9895e8036ffc41c4bd90e4a99631e5f261d9b518e"},
+ {file = "jiter-0.5.0-cp310-none-win32.whl", hash = "sha256:f16ca8f10e62f25fd81d5310e852df6649af17824146ca74647a018424ddeccf"},
+ {file = "jiter-0.5.0-cp310-none-win_amd64.whl", hash = "sha256:b2950e4798e82dd9176935ef6a55cf6a448b5c71515a556da3f6b811a7844f1e"},
+ {file = "jiter-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4c8e1ed0ef31ad29cae5ea16b9e41529eb50a7fba70600008e9f8de6376d553"},
+ {file = "jiter-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6f16e21276074a12d8421692515b3fd6d2ea9c94fd0734c39a12960a20e85f3"},
+ {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5280e68e7740c8c128d3ae5ab63335ce6d1fb6603d3b809637b11713487af9e6"},
+ {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:583c57fc30cc1fec360e66323aadd7fc3edeec01289bfafc35d3b9dcb29495e4"},
+ {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26351cc14507bdf466b5f99aba3df3143a59da75799bf64a53a3ad3155ecded9"},
+ {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829df14d656b3fb87e50ae8b48253a8851c707da9f30d45aacab2aa2ba2d614"},
+ {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42a4bdcf7307b86cb863b2fb9bb55029b422d8f86276a50487982d99eed7c6e"},
+ {file = "jiter-0.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04d461ad0aebf696f8da13c99bc1b3e06f66ecf6cfd56254cc402f6385231c06"},
+ {file = "jiter-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6375923c5f19888c9226582a124b77b622f8fd0018b843c45eeb19d9701c403"},
+ {file = "jiter-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cec323a853c24fd0472517113768c92ae0be8f8c384ef4441d3632da8baa646"},
+ {file = "jiter-0.5.0-cp311-none-win32.whl", hash = "sha256:aa1db0967130b5cab63dfe4d6ff547c88b2a394c3410db64744d491df7f069bb"},
+ {file = "jiter-0.5.0-cp311-none-win_amd64.whl", hash = "sha256:aa9d2b85b2ed7dc7697597dcfaac66e63c1b3028652f751c81c65a9f220899ae"},
+ {file = "jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9f664e7351604f91dcdd557603c57fc0d551bc65cc0a732fdacbf73ad335049a"},
+ {file = "jiter-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:044f2f1148b5248ad2c8c3afb43430dccf676c5a5834d2f5089a4e6c5bbd64df"},
+ {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:702e3520384c88b6e270c55c772d4bd6d7b150608dcc94dea87ceba1b6391248"},
+ {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:528d742dcde73fad9d63e8242c036ab4a84389a56e04efd854062b660f559544"},
+ {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf80e5fe6ab582c82f0c3331df27a7e1565e2dcf06265afd5173d809cdbf9ba"},
+ {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44dfc9ddfb9b51a5626568ef4e55ada462b7328996294fe4d36de02fce42721f"},
+ {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c451f7922992751a936b96c5f5b9bb9312243d9b754c34b33d0cb72c84669f4e"},
+ {file = "jiter-0.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:308fce789a2f093dca1ff91ac391f11a9f99c35369117ad5a5c6c4903e1b3e3a"},
+ {file = "jiter-0.5.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7f5ad4a7c6b0d90776fdefa294f662e8a86871e601309643de30bf94bb93a64e"},
+ {file = "jiter-0.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea189db75f8eca08807d02ae27929e890c7d47599ce3d0a6a5d41f2419ecf338"},
+ {file = "jiter-0.5.0-cp312-none-win32.whl", hash = "sha256:e3bbe3910c724b877846186c25fe3c802e105a2c1fc2b57d6688b9f8772026e4"},
+ {file = "jiter-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:a586832f70c3f1481732919215f36d41c59ca080fa27a65cf23d9490e75b2ef5"},
+ {file = "jiter-0.5.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f04bc2fc50dc77be9d10f73fcc4e39346402ffe21726ff41028f36e179b587e6"},
+ {file = "jiter-0.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f433a4169ad22fcb550b11179bb2b4fd405de9b982601914ef448390b2954f3"},
+ {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad4a6398c85d3a20067e6c69890ca01f68659da94d74c800298581724e426c7e"},
+ {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6baa88334e7af3f4d7a5c66c3a63808e5efbc3698a1c57626541ddd22f8e4fbf"},
+ {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ece0a115c05efca597c6d938f88c9357c843f8c245dbbb53361a1c01afd7148"},
+ {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:335942557162ad372cc367ffaf93217117401bf930483b4b3ebdb1223dbddfa7"},
+ {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:649b0ee97a6e6da174bffcb3c8c051a5935d7d4f2f52ea1583b5b3e7822fbf14"},
+ {file = "jiter-0.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f4be354c5de82157886ca7f5925dbda369b77344b4b4adf2723079715f823989"},
+ {file = "jiter-0.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5206144578831a6de278a38896864ded4ed96af66e1e63ec5dd7f4a1fce38a3a"},
+ {file = "jiter-0.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8120c60f8121ac3d6f072b97ef0e71770cc72b3c23084c72c4189428b1b1d3b6"},
+ {file = "jiter-0.5.0-cp38-none-win32.whl", hash = "sha256:6f1223f88b6d76b519cb033a4d3687ca157c272ec5d6015c322fc5b3074d8a5e"},
+ {file = "jiter-0.5.0-cp38-none-win_amd64.whl", hash = "sha256:c59614b225d9f434ea8fc0d0bec51ef5fa8c83679afedc0433905994fb36d631"},
+ {file = "jiter-0.5.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0af3838cfb7e6afee3f00dc66fa24695199e20ba87df26e942820345b0afc566"},
+ {file = "jiter-0.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:550b11d669600dbc342364fd4adbe987f14d0bbedaf06feb1b983383dcc4b961"},
+ {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:489875bf1a0ffb3cb38a727b01e6673f0f2e395b2aad3c9387f94187cb214bbf"},
+ {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b250ca2594f5599ca82ba7e68785a669b352156260c5362ea1b4e04a0f3e2389"},
+ {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ea18e01f785c6667ca15407cd6dabbe029d77474d53595a189bdc813347218e"},
+ {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:462a52be85b53cd9bffd94e2d788a09984274fe6cebb893d6287e1c296d50653"},
+ {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92cc68b48d50fa472c79c93965e19bd48f40f207cb557a8346daa020d6ba973b"},
+ {file = "jiter-0.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1c834133e59a8521bc87ebcad773608c6fa6ab5c7a022df24a45030826cf10bc"},
+ {file = "jiter-0.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab3a71ff31cf2d45cb216dc37af522d335211f3a972d2fe14ea99073de6cb104"},
+ {file = "jiter-0.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cccd3af9c48ac500c95e1bcbc498020c87e1781ff0345dd371462d67b76643eb"},
+ {file = "jiter-0.5.0-cp39-none-win32.whl", hash = "sha256:368084d8d5c4fc40ff7c3cc513c4f73e02c85f6009217922d0823a48ee7adf61"},
+ {file = "jiter-0.5.0-cp39-none-win_amd64.whl", hash = "sha256:ce03f7b4129eb72f1687fa11300fbf677b02990618428934662406d2a76742a1"},
+ {file = "jiter-0.5.0.tar.gz", hash = "sha256:1d916ba875bcab5c5f7d927df998c4cb694d27dceddf3392e58beaf10563368a"},
+]
+
[[package]]
name = "jmespath"
version = "1.0.1"
@@ -1930,65 +2014,66 @@ sympy = "*"
[[package]]
name = "openai"
-version = "1.35.13"
+version = "1.40.0"
description = "The official Python library for the openai API"
optional = false
python-versions = ">=3.7.1"
files = [
- {file = "openai-1.35.13-py3-none-any.whl", hash = "sha256:36ec3e93e0d1f243f69be85c89b9221a471c3e450dfd9df16c9829e3cdf63e60"},
- {file = "openai-1.35.13.tar.gz", hash = "sha256:c684f3945608baf7d2dcc0ef3ee6f3e27e4c66f21076df0b47be45d57e6ae6e4"},
+ {file = "openai-1.40.0-py3-none-any.whl", hash = "sha256:eb6909abaacd62ef28c275a5c175af29f607b40645b0a49d2856bbed62edb2e7"},
+ {file = "openai-1.40.0.tar.gz", hash = "sha256:1b7b316e27b2333b063ee62b6539b74267c7282498d9a02fc4ccb38a9c14336c"},
]
[package.dependencies]
anyio = ">=3.5.0,<5"
distro = ">=1.7.0,<2"
httpx = ">=0.23.0,<1"
+jiter = ">=0.4.0,<1"
pydantic = ">=1.9.0,<3"
sniffio = "*"
tqdm = ">4"
-typing-extensions = ">=4.7,<5"
+typing-extensions = ">=4.11,<5"
[package.extras]
datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"]
[[package]]
name = "opentelemetry-api"
-version = "1.25.0"
+version = "1.26.0"
description = "OpenTelemetry Python API"
optional = false
python-versions = ">=3.8"
files = [
- {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"},
- {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"},
+ {file = "opentelemetry_api-1.26.0-py3-none-any.whl", hash = "sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064"},
+ {file = "opentelemetry_api-1.26.0.tar.gz", hash = "sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce"},
]
[package.dependencies]
deprecated = ">=1.2.6"
-importlib-metadata = ">=6.0,<=7.1"
+importlib-metadata = ">=6.0,<=8.0.0"
[[package]]
name = "opentelemetry-exporter-otlp-proto-common"
-version = "1.25.0"
+version = "1.26.0"
description = "OpenTelemetry Protobuf encoding"
optional = false
python-versions = ">=3.8"
files = [
- {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"},
- {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"},
+ {file = "opentelemetry_exporter_otlp_proto_common-1.26.0-py3-none-any.whl", hash = "sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71"},
+ {file = "opentelemetry_exporter_otlp_proto_common-1.26.0.tar.gz", hash = "sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92"},
]
[package.dependencies]
-opentelemetry-proto = "1.25.0"
+opentelemetry-proto = "1.26.0"
[[package]]
name = "opentelemetry-exporter-otlp-proto-grpc"
-version = "1.25.0"
+version = "1.26.0"
description = "OpenTelemetry Collector Protobuf over gRPC Exporter"
optional = false
python-versions = ">=3.8"
files = [
- {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"},
- {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"},
+ {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0-py3-none-any.whl", hash = "sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280"},
+ {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0.tar.gz", hash = "sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae"},
]
[package.dependencies]
@@ -1996,19 +2081,19 @@ deprecated = ">=1.2.6"
googleapis-common-protos = ">=1.52,<2.0"
grpcio = ">=1.0.0,<2.0.0"
opentelemetry-api = ">=1.15,<2.0"
-opentelemetry-exporter-otlp-proto-common = "1.25.0"
-opentelemetry-proto = "1.25.0"
-opentelemetry-sdk = ">=1.25.0,<1.26.0"
+opentelemetry-exporter-otlp-proto-common = "1.26.0"
+opentelemetry-proto = "1.26.0"
+opentelemetry-sdk = ">=1.26.0,<1.27.0"
[[package]]
name = "opentelemetry-instrumentation"
-version = "0.46b0"
+version = "0.47b0"
description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"},
- {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"},
+ {file = "opentelemetry_instrumentation-0.47b0-py3-none-any.whl", hash = "sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5"},
+ {file = "opentelemetry_instrumentation-0.47b0.tar.gz", hash = "sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f"},
]
[package.dependencies]
@@ -2018,55 +2103,55 @@ wrapt = ">=1.0.0,<2.0.0"
[[package]]
name = "opentelemetry-instrumentation-asgi"
-version = "0.46b0"
+version = "0.47b0"
description = "ASGI instrumentation for OpenTelemetry"
optional = false
python-versions = ">=3.8"
files = [
- {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"},
- {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"},
+ {file = "opentelemetry_instrumentation_asgi-0.47b0-py3-none-any.whl", hash = "sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade"},
+ {file = "opentelemetry_instrumentation_asgi-0.47b0.tar.gz", hash = "sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a"},
]
[package.dependencies]
asgiref = ">=3.0,<4.0"
opentelemetry-api = ">=1.12,<2.0"
-opentelemetry-instrumentation = "0.46b0"
-opentelemetry-semantic-conventions = "0.46b0"
-opentelemetry-util-http = "0.46b0"
+opentelemetry-instrumentation = "0.47b0"
+opentelemetry-semantic-conventions = "0.47b0"
+opentelemetry-util-http = "0.47b0"
[package.extras]
instruments = ["asgiref (>=3.0,<4.0)"]
[[package]]
name = "opentelemetry-instrumentation-fastapi"
-version = "0.46b0"
+version = "0.47b0"
description = "OpenTelemetry FastAPI Instrumentation"
optional = false
python-versions = ">=3.8"
files = [
- {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"},
- {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"},
+ {file = "opentelemetry_instrumentation_fastapi-0.47b0-py3-none-any.whl", hash = "sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21"},
+ {file = "opentelemetry_instrumentation_fastapi-0.47b0.tar.gz", hash = "sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36"},
]
[package.dependencies]
opentelemetry-api = ">=1.12,<2.0"
-opentelemetry-instrumentation = "0.46b0"
-opentelemetry-instrumentation-asgi = "0.46b0"
-opentelemetry-semantic-conventions = "0.46b0"
-opentelemetry-util-http = "0.46b0"
+opentelemetry-instrumentation = "0.47b0"
+opentelemetry-instrumentation-asgi = "0.47b0"
+opentelemetry-semantic-conventions = "0.47b0"
+opentelemetry-util-http = "0.47b0"
[package.extras]
-instruments = ["fastapi (>=0.58,<1.0)"]
+instruments = ["fastapi (>=0.58,<1.0)", "fastapi-slim (>=0.111.0,<0.112.0)"]
[[package]]
name = "opentelemetry-proto"
-version = "1.25.0"
+version = "1.26.0"
description = "OpenTelemetry Python Proto"
optional = false
python-versions = ">=3.8"
files = [
- {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"},
- {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"},
+ {file = "opentelemetry_proto-1.26.0-py3-none-any.whl", hash = "sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725"},
+ {file = "opentelemetry_proto-1.26.0.tar.gz", hash = "sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e"},
]
[package.dependencies]
@@ -2074,43 +2159,44 @@ protobuf = ">=3.19,<5.0"
[[package]]
name = "opentelemetry-sdk"
-version = "1.25.0"
+version = "1.26.0"
description = "OpenTelemetry Python SDK"
optional = false
python-versions = ">=3.8"
files = [
- {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"},
- {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"},
+ {file = "opentelemetry_sdk-1.26.0-py3-none-any.whl", hash = "sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897"},
+ {file = "opentelemetry_sdk-1.26.0.tar.gz", hash = "sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85"},
]
[package.dependencies]
-opentelemetry-api = "1.25.0"
-opentelemetry-semantic-conventions = "0.46b0"
+opentelemetry-api = "1.26.0"
+opentelemetry-semantic-conventions = "0.47b0"
typing-extensions = ">=3.7.4"
[[package]]
name = "opentelemetry-semantic-conventions"
-version = "0.46b0"
+version = "0.47b0"
description = "OpenTelemetry Semantic Conventions"
optional = false
python-versions = ">=3.8"
files = [
- {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"},
- {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"},
+ {file = "opentelemetry_semantic_conventions-0.47b0-py3-none-any.whl", hash = "sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063"},
+ {file = "opentelemetry_semantic_conventions-0.47b0.tar.gz", hash = "sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e"},
]
[package.dependencies]
-opentelemetry-api = "1.25.0"
+deprecated = ">=1.2.6"
+opentelemetry-api = "1.26.0"
[[package]]
name = "opentelemetry-util-http"
-version = "0.46b0"
+version = "0.47b0"
description = "Web util for OpenTelemetry"
optional = false
python-versions = ">=3.8"
files = [
- {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"},
- {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"},
+ {file = "opentelemetry_util_http-0.47b0-py3-none-any.whl", hash = "sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19"},
+ {file = "opentelemetry_util_http-0.47b0.tar.gz", hash = "sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32"},
]
[[package]]
@@ -2252,22 +2338,22 @@ test = ["coverage", "flake8", "freezegun (==0.3.15)", "mock (>=2.0.0)", "pylint"
[[package]]
name = "protobuf"
-version = "4.25.3"
+version = "4.25.4"
description = ""
optional = false
python-versions = ">=3.8"
files = [
- {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"},
- {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"},
- {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"},
- {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"},
- {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"},
- {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"},
- {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"},
- {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"},
- {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"},
- {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"},
- {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"},
+ {file = "protobuf-4.25.4-cp310-abi3-win32.whl", hash = "sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4"},
+ {file = "protobuf-4.25.4-cp310-abi3-win_amd64.whl", hash = "sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d"},
+ {file = "protobuf-4.25.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b"},
+ {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835"},
+ {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040"},
+ {file = "protobuf-4.25.4-cp38-cp38-win32.whl", hash = "sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1"},
+ {file = "protobuf-4.25.4-cp38-cp38-win_amd64.whl", hash = "sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1"},
+ {file = "protobuf-4.25.4-cp39-cp39-win32.whl", hash = "sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca"},
+ {file = "protobuf-4.25.4-cp39-cp39-win_amd64.whl", hash = "sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f"},
+ {file = "protobuf-4.25.4-py3-none-any.whl", hash = "sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978"},
+ {file = "protobuf-4.25.4.tar.gz", hash = "sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d"},
]
[[package]]
@@ -2500,20 +2586,20 @@ files = [
[[package]]
name = "pytest"
-version = "8.2.2"
+version = "8.3.2"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"},
- {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"},
+ {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"},
+ {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"},
]
[package.dependencies]
colorama = {version = "*", markers = "sys_platform == \"win32\""}
iniconfig = "*"
packaging = "*"
-pluggy = ">=1.5,<2.0"
+pluggy = ">=1.5,<2"
[package.extras]
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
@@ -2643,105 +2729,105 @@ files = [
[[package]]
name = "redis"
-version = "5.0.7"
+version = "5.0.8"
description = "Python client for Redis database and key-value store"
optional = false
python-versions = ">=3.7"
files = [
- {file = "redis-5.0.7-py3-none-any.whl", hash = "sha256:0e479e24da960c690be5d9b96d21f7b918a98c0cf49af3b6fafaa0753f93a0db"},
- {file = "redis-5.0.7.tar.gz", hash = "sha256:8f611490b93c8109b50adc317b31bfd84fff31def3475b92e7e80bf39f48175b"},
+ {file = "redis-5.0.8-py3-none-any.whl", hash = "sha256:56134ee08ea909106090934adc36f65c9bcbbaecea5b21ba704ba6fb561f8eb4"},
+ {file = "redis-5.0.8.tar.gz", hash = "sha256:0c5b10d387568dfe0698c6fad6615750c24170e548ca2deac10c649d463e9870"},
]
[package.extras]
-hiredis = ["hiredis (>=1.0.0)"]
+hiredis = ["hiredis (>1.0.0)"]
ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"]
[[package]]
name = "regex"
-version = "2024.5.15"
+version = "2024.7.24"
description = "Alternative regular expression module, to replace re."
optional = false
python-versions = ">=3.8"
files = [
- {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a81e3cfbae20378d75185171587cbf756015ccb14840702944f014e0d93ea09f"},
- {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b59138b219ffa8979013be7bc85bb60c6f7b7575df3d56dc1e403a438c7a3f6"},
- {file = "regex-2024.5.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0bd000c6e266927cb7a1bc39d55be95c4b4f65c5be53e659537537e019232b1"},
- {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eaa7ddaf517aa095fa8da0b5015c44d03da83f5bd49c87961e3c997daed0de7"},
- {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba68168daedb2c0bab7fd7e00ced5ba90aebf91024dea3c88ad5063c2a562cca"},
- {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e8d717bca3a6e2064fc3a08df5cbe366369f4b052dcd21b7416e6d71620dca1"},
- {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1337b7dbef9b2f71121cdbf1e97e40de33ff114801263b275aafd75303bd62b5"},
- {file = "regex-2024.5.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9ebd0a36102fcad2f03696e8af4ae682793a5d30b46c647eaf280d6cfb32796"},
- {file = "regex-2024.5.15-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9efa1a32ad3a3ea112224897cdaeb6aa00381627f567179c0314f7b65d354c62"},
- {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1595f2d10dff3d805e054ebdc41c124753631b6a471b976963c7b28543cf13b0"},
- {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b802512f3e1f480f41ab5f2cfc0e2f761f08a1f41092d6718868082fc0d27143"},
- {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a0981022dccabca811e8171f913de05720590c915b033b7e601f35ce4ea7019f"},
- {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:19068a6a79cf99a19ccefa44610491e9ca02c2be3305c7760d3831d38a467a6f"},
- {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1b5269484f6126eee5e687785e83c6b60aad7663dafe842b34691157e5083e53"},
- {file = "regex-2024.5.15-cp310-cp310-win32.whl", hash = "sha256:ada150c5adfa8fbcbf321c30c751dc67d2f12f15bd183ffe4ec7cde351d945b3"},
- {file = "regex-2024.5.15-cp310-cp310-win_amd64.whl", hash = "sha256:ac394ff680fc46b97487941f5e6ae49a9f30ea41c6c6804832063f14b2a5a145"},
- {file = "regex-2024.5.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f5b1dff3ad008dccf18e652283f5e5339d70bf8ba7c98bf848ac33db10f7bc7a"},
- {file = "regex-2024.5.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c6a2b494a76983df8e3d3feea9b9ffdd558b247e60b92f877f93a1ff43d26656"},
- {file = "regex-2024.5.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a32b96f15c8ab2e7d27655969a23895eb799de3665fa94349f3b2fbfd547236f"},
- {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10002e86e6068d9e1c91eae8295ef690f02f913c57db120b58fdd35a6bb1af35"},
- {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec54d5afa89c19c6dd8541a133be51ee1017a38b412b1321ccb8d6ddbeb4cf7d"},
- {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10e4ce0dca9ae7a66e6089bb29355d4432caed736acae36fef0fdd7879f0b0cb"},
- {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e507ff1e74373c4d3038195fdd2af30d297b4f0950eeda6f515ae3d84a1770f"},
- {file = "regex-2024.5.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1f059a4d795e646e1c37665b9d06062c62d0e8cc3c511fe01315973a6542e40"},
- {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0721931ad5fe0dda45d07f9820b90b2148ccdd8e45bb9e9b42a146cb4f695649"},
- {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:833616ddc75ad595dee848ad984d067f2f31be645d603e4d158bba656bbf516c"},
- {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:287eb7f54fc81546346207c533ad3c2c51a8d61075127d7f6d79aaf96cdee890"},
- {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:19dfb1c504781a136a80ecd1fff9f16dddf5bb43cec6871778c8a907a085bb3d"},
- {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:119af6e56dce35e8dfb5222573b50c89e5508d94d55713c75126b753f834de68"},
- {file = "regex-2024.5.15-cp311-cp311-win32.whl", hash = "sha256:1c1c174d6ec38d6c8a7504087358ce9213d4332f6293a94fbf5249992ba54efa"},
- {file = "regex-2024.5.15-cp311-cp311-win_amd64.whl", hash = "sha256:9e717956dcfd656f5055cc70996ee2cc82ac5149517fc8e1b60261b907740201"},
- {file = "regex-2024.5.15-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:632b01153e5248c134007209b5c6348a544ce96c46005d8456de1d552455b014"},
- {file = "regex-2024.5.15-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e64198f6b856d48192bf921421fdd8ad8eb35e179086e99e99f711957ffedd6e"},
- {file = "regex-2024.5.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68811ab14087b2f6e0fc0c2bae9ad689ea3584cad6917fc57be6a48bbd012c49"},
- {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ec0c2fea1e886a19c3bee0cd19d862b3aa75dcdfb42ebe8ed30708df64687a"},
- {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0c0c0003c10f54a591d220997dd27d953cd9ccc1a7294b40a4be5312be8797b"},
- {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2431b9e263af1953c55abbd3e2efca67ca80a3de8a0437cb58e2421f8184717a"},
- {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a605586358893b483976cffc1723fb0f83e526e8f14c6e6614e75919d9862cf"},
- {file = "regex-2024.5.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391d7f7f1e409d192dba8bcd42d3e4cf9e598f3979cdaed6ab11288da88cb9f2"},
- {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9ff11639a8d98969c863d4617595eb5425fd12f7c5ef6621a4b74b71ed8726d5"},
- {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4eee78a04e6c67e8391edd4dad3279828dd66ac4b79570ec998e2155d2e59fd5"},
- {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8fe45aa3f4aa57faabbc9cb46a93363edd6197cbc43523daea044e9ff2fea83e"},
- {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d0a3d8d6acf0c78a1fff0e210d224b821081330b8524e3e2bc5a68ef6ab5803d"},
- {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c486b4106066d502495b3025a0a7251bf37ea9540433940a23419461ab9f2a80"},
- {file = "regex-2024.5.15-cp312-cp312-win32.whl", hash = "sha256:c49e15eac7c149f3670b3e27f1f28a2c1ddeccd3a2812cba953e01be2ab9b5fe"},
- {file = "regex-2024.5.15-cp312-cp312-win_amd64.whl", hash = "sha256:673b5a6da4557b975c6c90198588181029c60793835ce02f497ea817ff647cb2"},
- {file = "regex-2024.5.15-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:87e2a9c29e672fc65523fb47a90d429b70ef72b901b4e4b1bd42387caf0d6835"},
- {file = "regex-2024.5.15-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c3bea0ba8b73b71b37ac833a7f3fd53825924165da6a924aec78c13032f20850"},
- {file = "regex-2024.5.15-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bfc4f82cabe54f1e7f206fd3d30fda143f84a63fe7d64a81558d6e5f2e5aaba9"},
- {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5bb9425fe881d578aeca0b2b4b3d314ec88738706f66f219c194d67179337cb"},
- {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64c65783e96e563103d641760664125e91bd85d8e49566ee560ded4da0d3e704"},
- {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf2430df4148b08fb4324b848672514b1385ae3807651f3567871f130a728cc3"},
- {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5397de3219a8b08ae9540c48f602996aa6b0b65d5a61683e233af8605c42b0f2"},
- {file = "regex-2024.5.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:455705d34b4154a80ead722f4f185b04c4237e8e8e33f265cd0798d0e44825fa"},
- {file = "regex-2024.5.15-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b2b6f1b3bb6f640c1a92be3bbfbcb18657b125b99ecf141fb3310b5282c7d4ed"},
- {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3ad070b823ca5890cab606c940522d05d3d22395d432f4aaaf9d5b1653e47ced"},
- {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5b5467acbfc153847d5adb21e21e29847bcb5870e65c94c9206d20eb4e99a384"},
- {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e6662686aeb633ad65be2a42b4cb00178b3fbf7b91878f9446075c404ada552f"},
- {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:2b4c884767504c0e2401babe8b5b7aea9148680d2e157fa28f01529d1f7fcf67"},
- {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3cd7874d57f13bf70078f1ff02b8b0aa48d5b9ed25fc48547516c6aba36f5741"},
- {file = "regex-2024.5.15-cp38-cp38-win32.whl", hash = "sha256:e4682f5ba31f475d58884045c1a97a860a007d44938c4c0895f41d64481edbc9"},
- {file = "regex-2024.5.15-cp38-cp38-win_amd64.whl", hash = "sha256:d99ceffa25ac45d150e30bd9ed14ec6039f2aad0ffa6bb87a5936f5782fc1569"},
- {file = "regex-2024.5.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13cdaf31bed30a1e1c2453ef6015aa0983e1366fad2667657dbcac7b02f67133"},
- {file = "regex-2024.5.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cac27dcaa821ca271855a32188aa61d12decb6fe45ffe3e722401fe61e323cd1"},
- {file = "regex-2024.5.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7dbe2467273b875ea2de38ded4eba86cbcbc9a1a6d0aa11dcf7bd2e67859c435"},
- {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f18a9a3513a99c4bef0e3efd4c4a5b11228b48aa80743be822b71e132ae4f5"},
- {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d347a741ea871c2e278fde6c48f85136c96b8659b632fb57a7d1ce1872547600"},
- {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1878b8301ed011704aea4c806a3cadbd76f84dece1ec09cc9e4dc934cfa5d4da"},
- {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4babf07ad476aaf7830d77000874d7611704a7fcf68c9c2ad151f5d94ae4bfc4"},
- {file = "regex-2024.5.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35cb514e137cb3488bce23352af3e12fb0dbedd1ee6e60da053c69fb1b29cc6c"},
- {file = "regex-2024.5.15-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cdd09d47c0b2efee9378679f8510ee6955d329424c659ab3c5e3a6edea696294"},
- {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:72d7a99cd6b8f958e85fc6ca5b37c4303294954eac1376535b03c2a43eb72629"},
- {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a094801d379ab20c2135529948cb84d417a2169b9bdceda2a36f5f10977ebc16"},
- {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c0c18345010870e58238790a6779a1219b4d97bd2e77e1140e8ee5d14df071aa"},
- {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:16093f563098448ff6b1fa68170e4acbef94e6b6a4e25e10eae8598bb1694b5d"},
- {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e38a7d4e8f633a33b4c7350fbd8bad3b70bf81439ac67ac38916c4a86b465456"},
- {file = "regex-2024.5.15-cp39-cp39-win32.whl", hash = "sha256:71a455a3c584a88f654b64feccc1e25876066c4f5ef26cd6dd711308aa538694"},
- {file = "regex-2024.5.15-cp39-cp39-win_amd64.whl", hash = "sha256:cab12877a9bdafde5500206d1020a584355a97884dfd388af3699e9137bf7388"},
- {file = "regex-2024.5.15.tar.gz", hash = "sha256:d3ee02d9e5f482cc8309134a91eeaacbdd2261ba111b0fef3748eeb4913e6a2c"},
+ {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b0d3f567fafa0633aee87f08b9276c7062da9616931382993c03808bb68ce"},
+ {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3426de3b91d1bc73249042742f45c2148803c111d1175b283270177fdf669024"},
+ {file = "regex-2024.7.24-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f273674b445bcb6e4409bf8d1be67bc4b58e8b46fd0d560055d515b8830063cd"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23acc72f0f4e1a9e6e9843d6328177ae3074b4182167e34119ec7233dfeccf53"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65fd3d2e228cae024c411c5ccdffae4c315271eee4a8b839291f84f796b34eca"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c414cbda77dbf13c3bc88b073a1a9f375c7b0cb5e115e15d4b73ec3a2fbc6f59"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7a89eef64b5455835f5ed30254ec19bf41f7541cd94f266ab7cbd463f00c41"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19c65b00d42804e3fbea9708f0937d157e53429a39b7c61253ff15670ff62cb5"},
+ {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a5486ca56c8869070a966321d5ab416ff0f83f30e0e2da1ab48815c8d165d46"},
+ {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f51f9556785e5a203713f5efd9c085b4a45aecd2a42573e2b5041881b588d1f"},
+ {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a4997716674d36a82eab3e86f8fa77080a5d8d96a389a61ea1d0e3a94a582cf7"},
+ {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c0abb5e4e8ce71a61d9446040c1e86d4e6d23f9097275c5bd49ed978755ff0fe"},
+ {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:18300a1d78cf1290fa583cd8b7cde26ecb73e9f5916690cf9d42de569c89b1ce"},
+ {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:416c0e4f56308f34cdb18c3f59849479dde5b19febdcd6e6fa4d04b6c31c9faa"},
+ {file = "regex-2024.7.24-cp310-cp310-win32.whl", hash = "sha256:fb168b5924bef397b5ba13aabd8cf5df7d3d93f10218d7b925e360d436863f66"},
+ {file = "regex-2024.7.24-cp310-cp310-win_amd64.whl", hash = "sha256:6b9fc7e9cc983e75e2518496ba1afc524227c163e43d706688a6bb9eca41617e"},
+ {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281"},
+ {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b"},
+ {file = "regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a"},
+ {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73"},
+ {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2"},
+ {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e"},
+ {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51"},
+ {file = "regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364"},
+ {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee"},
+ {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c"},
+ {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce"},
+ {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1"},
+ {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e"},
+ {file = "regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c"},
+ {file = "regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52"},
+ {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86"},
+ {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad"},
+ {file = "regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9"},
+ {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289"},
+ {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9"},
+ {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c"},
+ {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440"},
+ {file = "regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610"},
+ {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5"},
+ {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799"},
+ {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05"},
+ {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94"},
+ {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38"},
+ {file = "regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc"},
+ {file = "regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908"},
+ {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:66b4c0731a5c81921e938dcf1a88e978264e26e6ac4ec96a4d21ae0354581ae0"},
+ {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:88ecc3afd7e776967fa16c80f974cb79399ee8dc6c96423321d6f7d4b881c92b"},
+ {file = "regex-2024.7.24-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64bd50cf16bcc54b274e20235bf8edbb64184a30e1e53873ff8d444e7ac656b2"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb462f0e346fcf41a901a126b50f8781e9a474d3927930f3490f38a6e73b6950"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a82465ebbc9b1c5c50738536fdfa7cab639a261a99b469c9d4c7dcbb2b3f1e57"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68a8f8c046c6466ac61a36b65bb2395c74451df2ffb8458492ef49900efed293"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac8e84fff5d27420f3c1e879ce9929108e873667ec87e0c8eeb413a5311adfe"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba2537ef2163db9e6ccdbeb6f6424282ae4dea43177402152c67ef869cf3978b"},
+ {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:43affe33137fcd679bdae93fb25924979517e011f9dea99163f80b82eadc7e53"},
+ {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c9bb87fdf2ab2370f21e4d5636e5317775e5d51ff32ebff2cf389f71b9b13750"},
+ {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:945352286a541406f99b2655c973852da7911b3f4264e010218bbc1cc73168f2"},
+ {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8bc593dcce679206b60a538c302d03c29b18e3d862609317cb560e18b66d10cf"},
+ {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3f3b6ca8eae6d6c75a6cff525c8530c60e909a71a15e1b731723233331de4169"},
+ {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c51edc3541e11fbe83f0c4d9412ef6c79f664a3745fab261457e84465ec9d5a8"},
+ {file = "regex-2024.7.24-cp38-cp38-win32.whl", hash = "sha256:d0a07763776188b4db4c9c7fb1b8c494049f84659bb387b71c73bbc07f189e96"},
+ {file = "regex-2024.7.24-cp38-cp38-win_amd64.whl", hash = "sha256:8fd5afd101dcf86a270d254364e0e8dddedebe6bd1ab9d5f732f274fa00499a5"},
+ {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0ffe3f9d430cd37d8fa5632ff6fb36d5b24818c5c986893063b4e5bdb84cdf24"},
+ {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25419b70ba00a16abc90ee5fce061228206173231f004437730b67ac77323f0d"},
+ {file = "regex-2024.7.24-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:33e2614a7ce627f0cdf2ad104797d1f68342d967de3695678c0cb84f530709f8"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33a0021893ede5969876052796165bab6006559ab845fd7b515a30abdd990dc"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04ce29e2c5fedf296b1a1b0acc1724ba93a36fb14031f3abfb7abda2806c1535"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b16582783f44fbca6fcf46f61347340c787d7530d88b4d590a397a47583f31dd"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:836d3cc225b3e8a943d0b02633fb2f28a66e281290302a79df0e1eaa984ff7c1"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438d9f0f4bc64e8dea78274caa5af971ceff0f8771e1a2333620969936ba10be"},
+ {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:973335b1624859cb0e52f96062a28aa18f3a5fc77a96e4a3d6d76e29811a0e6e"},
+ {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c5e69fd3eb0b409432b537fe3c6f44ac089c458ab6b78dcec14478422879ec5f"},
+ {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fbf8c2f00904eaf63ff37718eb13acf8e178cb940520e47b2f05027f5bb34ce3"},
+ {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2757ace61bc4061b69af19e4689fa4416e1a04840f33b441034202b5cd02d4"},
+ {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:44fc61b99035fd9b3b9453f1713234e5a7c92a04f3577252b45feefe1b327759"},
+ {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:84c312cdf839e8b579f504afcd7b65f35d60b6285d892b19adea16355e8343c9"},
+ {file = "regex-2024.7.24-cp39-cp39-win32.whl", hash = "sha256:ca5b2028c2f7af4e13fb9fc29b28d0ce767c38c7facdf64f6c2cd040413055f1"},
+ {file = "regex-2024.7.24-cp39-cp39-win_amd64.whl", hash = "sha256:7c479f5ae937ec9985ecaf42e2e10631551d909f203e31308c12d703922742f9"},
+ {file = "regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506"},
]
[[package]]
@@ -2849,13 +2935,13 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"]
[[package]]
name = "sentry-sdk"
-version = "2.9.0"
+version = "2.12.0"
description = "Python client for Sentry (https://sentry.io)"
optional = false
python-versions = ">=3.6"
files = [
- {file = "sentry_sdk-2.9.0-py2.py3-none-any.whl", hash = "sha256:0bea5fa8b564cc0d09f2e6f55893e8f70286048b0ffb3a341d5b695d1af0e6ee"},
- {file = "sentry_sdk-2.9.0.tar.gz", hash = "sha256:4c85bad74df9767976afb3eeddc33e0e153300e887d637775a753a35ef99bee6"},
+ {file = "sentry_sdk-2.12.0-py2.py3-none-any.whl", hash = "sha256:7a8d5163d2ba5c5f4464628c6b68f85e86972f7c636acc78aed45c61b98b7a5e"},
+ {file = "sentry_sdk-2.12.0.tar.gz", hash = "sha256:8763840497b817d44c49b3fe3f5f7388d083f2337ffedf008b2cdb63b5c86dc6"},
]
[package.dependencies]
@@ -2886,7 +2972,7 @@ langchain = ["langchain (>=0.0.210)"]
loguru = ["loguru (>=0.5)"]
openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"]
opentelemetry = ["opentelemetry-distro (>=0.35b0)"]
-opentelemetry-experimental = ["opentelemetry-instrumentation-aio-pika (==0.46b0)", "opentelemetry-instrumentation-aiohttp-client (==0.46b0)", "opentelemetry-instrumentation-aiopg (==0.46b0)", "opentelemetry-instrumentation-asgi (==0.46b0)", "opentelemetry-instrumentation-asyncio (==0.46b0)", "opentelemetry-instrumentation-asyncpg (==0.46b0)", "opentelemetry-instrumentation-aws-lambda (==0.46b0)", "opentelemetry-instrumentation-boto (==0.46b0)", "opentelemetry-instrumentation-boto3sqs (==0.46b0)", "opentelemetry-instrumentation-botocore (==0.46b0)", "opentelemetry-instrumentation-cassandra (==0.46b0)", "opentelemetry-instrumentation-celery (==0.46b0)", "opentelemetry-instrumentation-confluent-kafka (==0.46b0)", "opentelemetry-instrumentation-dbapi (==0.46b0)", "opentelemetry-instrumentation-django (==0.46b0)", "opentelemetry-instrumentation-elasticsearch (==0.46b0)", "opentelemetry-instrumentation-falcon (==0.46b0)", "opentelemetry-instrumentation-fastapi (==0.46b0)", "opentelemetry-instrumentation-flask (==0.46b0)", "opentelemetry-instrumentation-grpc (==0.46b0)", "opentelemetry-instrumentation-httpx (==0.46b0)", "opentelemetry-instrumentation-jinja2 (==0.46b0)", "opentelemetry-instrumentation-kafka-python (==0.46b0)", "opentelemetry-instrumentation-logging (==0.46b0)", "opentelemetry-instrumentation-mysql (==0.46b0)", "opentelemetry-instrumentation-mysqlclient (==0.46b0)", "opentelemetry-instrumentation-pika (==0.46b0)", "opentelemetry-instrumentation-psycopg (==0.46b0)", "opentelemetry-instrumentation-psycopg2 (==0.46b0)", "opentelemetry-instrumentation-pymemcache (==0.46b0)", "opentelemetry-instrumentation-pymongo (==0.46b0)", "opentelemetry-instrumentation-pymysql (==0.46b0)", "opentelemetry-instrumentation-pyramid (==0.46b0)", "opentelemetry-instrumentation-redis (==0.46b0)", "opentelemetry-instrumentation-remoulade (==0.46b0)", "opentelemetry-instrumentation-requests (==0.46b0)", "opentelemetry-instrumentation-sklearn (==0.46b0)", "opentelemetry-instrumentation-sqlalchemy (==0.46b0)", "opentelemetry-instrumentation-sqlite3 (==0.46b0)", "opentelemetry-instrumentation-starlette (==0.46b0)", "opentelemetry-instrumentation-system-metrics (==0.46b0)", "opentelemetry-instrumentation-threading (==0.46b0)", "opentelemetry-instrumentation-tornado (==0.46b0)", "opentelemetry-instrumentation-tortoiseorm (==0.46b0)", "opentelemetry-instrumentation-urllib (==0.46b0)", "opentelemetry-instrumentation-urllib3 (==0.46b0)", "opentelemetry-instrumentation-wsgi (==0.46b0)"]
+opentelemetry-experimental = ["opentelemetry-distro"]
pure-eval = ["asttokens", "executing", "pure-eval"]
pymongo = ["pymongo (>=3.1)"]
pyspark = ["pyspark (>=2.4.4)"]
@@ -2900,18 +2986,19 @@ tornado = ["tornado (>=6)"]
[[package]]
name = "setuptools"
-version = "70.3.0"
+version = "72.1.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
- {file = "setuptools-70.3.0-py3-none-any.whl", hash = "sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc"},
- {file = "setuptools-70.3.0.tar.gz", hash = "sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5"},
+ {file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"},
+ {file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"},
]
[package.extras]
+core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
-test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
name = "shellingham"
@@ -2948,60 +3035,60 @@ files = [
[[package]]
name = "sqlalchemy"
-version = "2.0.31"
+version = "2.0.32"
description = "Database Abstraction Library"
optional = false
python-versions = ">=3.7"
files = [
- {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2a213c1b699d3f5768a7272de720387ae0122f1becf0901ed6eaa1abd1baf6c"},
- {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9fea3d0884e82d1e33226935dac990b967bef21315cbcc894605db3441347443"},
- {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ad7f221d8a69d32d197e5968d798217a4feebe30144986af71ada8c548e9fa"},
- {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2bee229715b6366f86a95d497c347c22ddffa2c7c96143b59a2aa5cc9eebbc"},
- {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cd5b94d4819c0c89280b7c6109c7b788a576084bf0a480ae17c227b0bc41e109"},
- {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:750900a471d39a7eeba57580b11983030517a1f512c2cb287d5ad0fcf3aebd58"},
- {file = "SQLAlchemy-2.0.31-cp310-cp310-win32.whl", hash = "sha256:7bd112be780928c7f493c1a192cd8c5fc2a2a7b52b790bc5a84203fb4381c6be"},
- {file = "SQLAlchemy-2.0.31-cp310-cp310-win_amd64.whl", hash = "sha256:5a48ac4d359f058474fadc2115f78a5cdac9988d4f99eae44917f36aa1476327"},
- {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f68470edd70c3ac3b6cd5c2a22a8daf18415203ca1b036aaeb9b0fb6f54e8298"},
- {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e2c38c2a4c5c634fe6c3c58a789712719fa1bf9b9d6ff5ebfce9a9e5b89c1ca"},
- {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd15026f77420eb2b324dcb93551ad9c5f22fab2c150c286ef1dc1160f110203"},
- {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2196208432deebdfe3b22185d46b08f00ac9d7b01284e168c212919891289396"},
- {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:352b2770097f41bff6029b280c0e03b217c2dcaddc40726f8f53ed58d8a85da4"},
- {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56d51ae825d20d604583f82c9527d285e9e6d14f9a5516463d9705dab20c3740"},
- {file = "SQLAlchemy-2.0.31-cp311-cp311-win32.whl", hash = "sha256:6e2622844551945db81c26a02f27d94145b561f9d4b0c39ce7bfd2fda5776dac"},
- {file = "SQLAlchemy-2.0.31-cp311-cp311-win_amd64.whl", hash = "sha256:ccaf1b0c90435b6e430f5dd30a5aede4764942a695552eb3a4ab74ed63c5b8d3"},
- {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3b74570d99126992d4b0f91fb87c586a574a5872651185de8297c6f90055ae42"},
- {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f77c4f042ad493cb8595e2f503c7a4fe44cd7bd59c7582fd6d78d7e7b8ec52c"},
- {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd1591329333daf94467e699e11015d9c944f44c94d2091f4ac493ced0119449"},
- {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74afabeeff415e35525bf7a4ecdab015f00e06456166a2eba7590e49f8db940e"},
- {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b9c01990d9015df2c6f818aa8f4297d42ee71c9502026bb074e713d496e26b67"},
- {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66f63278db425838b3c2b1c596654b31939427016ba030e951b292e32b99553e"},
- {file = "SQLAlchemy-2.0.31-cp312-cp312-win32.whl", hash = "sha256:0b0f658414ee4e4b8cbcd4a9bb0fd743c5eeb81fc858ca517217a8013d282c96"},
- {file = "SQLAlchemy-2.0.31-cp312-cp312-win_amd64.whl", hash = "sha256:fa4b1af3e619b5b0b435e333f3967612db06351217c58bfb50cee5f003db2a5a"},
- {file = "SQLAlchemy-2.0.31-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f43e93057cf52a227eda401251c72b6fbe4756f35fa6bfebb5d73b86881e59b0"},
- {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d337bf94052856d1b330d5fcad44582a30c532a2463776e1651bd3294ee7e58b"},
- {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c06fb43a51ccdff3b4006aafee9fcf15f63f23c580675f7734245ceb6b6a9e05"},
- {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:b6e22630e89f0e8c12332b2b4c282cb01cf4da0d26795b7eae16702a608e7ca1"},
- {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:79a40771363c5e9f3a77f0e28b3302801db08040928146e6808b5b7a40749c88"},
- {file = "SQLAlchemy-2.0.31-cp37-cp37m-win32.whl", hash = "sha256:501ff052229cb79dd4c49c402f6cb03b5a40ae4771efc8bb2bfac9f6c3d3508f"},
- {file = "SQLAlchemy-2.0.31-cp37-cp37m-win_amd64.whl", hash = "sha256:597fec37c382a5442ffd471f66ce12d07d91b281fd474289356b1a0041bdf31d"},
- {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dc6d69f8829712a4fd799d2ac8d79bdeff651c2301b081fd5d3fe697bd5b4ab9"},
- {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:23b9fbb2f5dd9e630db70fbe47d963c7779e9c81830869bd7d137c2dc1ad05fb"},
- {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21c97efcbb9f255d5c12a96ae14da873233597dfd00a3a0c4ce5b3e5e79704"},
- {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a6a9837589c42b16693cf7bf836f5d42218f44d198f9343dd71d3164ceeeac"},
- {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc251477eae03c20fae8db9c1c23ea2ebc47331bcd73927cdcaecd02af98d3c3"},
- {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2fd17e3bb8058359fa61248c52c7b09a97cf3c820e54207a50af529876451808"},
- {file = "SQLAlchemy-2.0.31-cp38-cp38-win32.whl", hash = "sha256:c76c81c52e1e08f12f4b6a07af2b96b9b15ea67ccdd40ae17019f1c373faa227"},
- {file = "SQLAlchemy-2.0.31-cp38-cp38-win_amd64.whl", hash = "sha256:4b600e9a212ed59355813becbcf282cfda5c93678e15c25a0ef896b354423238"},
- {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b6cf796d9fcc9b37011d3f9936189b3c8074a02a4ed0c0fbbc126772c31a6d4"},
- {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:78fe11dbe37d92667c2c6e74379f75746dc947ee505555a0197cfba9a6d4f1a4"},
- {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc47dc6185a83c8100b37acda27658fe4dbd33b7d5e7324111f6521008ab4fe"},
- {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a41514c1a779e2aa9a19f67aaadeb5cbddf0b2b508843fcd7bafdf4c6864005"},
- {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:afb6dde6c11ea4525318e279cd93c8734b795ac8bb5dda0eedd9ebaca7fa23f1"},
- {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3f9faef422cfbb8fd53716cd14ba95e2ef655400235c3dfad1b5f467ba179c8c"},
- {file = "SQLAlchemy-2.0.31-cp39-cp39-win32.whl", hash = "sha256:fc6b14e8602f59c6ba893980bea96571dd0ed83d8ebb9c4479d9ed5425d562e9"},
- {file = "SQLAlchemy-2.0.31-cp39-cp39-win_amd64.whl", hash = "sha256:3cb8a66b167b033ec72c3812ffc8441d4e9f5f78f5e31e54dcd4c90a4ca5bebc"},
- {file = "SQLAlchemy-2.0.31-py3-none-any.whl", hash = "sha256:69f3e3c08867a8e4856e92d7afb618b95cdee18e0bc1647b77599722c9a28911"},
- {file = "SQLAlchemy-2.0.31.tar.gz", hash = "sha256:b607489dd4a54de56984a0c7656247504bd5523d9d0ba799aef59d4add009484"},
+ {file = "SQLAlchemy-2.0.32-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0c9045ecc2e4db59bfc97b20516dfdf8e41d910ac6fb667ebd3a79ea54084619"},
+ {file = "SQLAlchemy-2.0.32-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1467940318e4a860afd546ef61fefb98a14d935cd6817ed07a228c7f7c62f389"},
+ {file = "SQLAlchemy-2.0.32-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5954463675cb15db8d4b521f3566a017c8789222b8316b1e6934c811018ee08b"},
+ {file = "SQLAlchemy-2.0.32-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:167e7497035c303ae50651b351c28dc22a40bb98fbdb8468cdc971821b1ae533"},
+ {file = "SQLAlchemy-2.0.32-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b27dfb676ac02529fb6e343b3a482303f16e6bc3a4d868b73935b8792edb52d0"},
+ {file = "SQLAlchemy-2.0.32-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bf2360a5e0f7bd75fa80431bf8ebcfb920c9f885e7956c7efde89031695cafb8"},
+ {file = "SQLAlchemy-2.0.32-cp310-cp310-win32.whl", hash = "sha256:306fe44e754a91cd9d600a6b070c1f2fadbb4a1a257b8781ccf33c7067fd3e4d"},
+ {file = "SQLAlchemy-2.0.32-cp310-cp310-win_amd64.whl", hash = "sha256:99db65e6f3ab42e06c318f15c98f59a436f1c78179e6a6f40f529c8cc7100b22"},
+ {file = "SQLAlchemy-2.0.32-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21b053be28a8a414f2ddd401f1be8361e41032d2ef5884b2f31d31cb723e559f"},
+ {file = "SQLAlchemy-2.0.32-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b178e875a7a25b5938b53b006598ee7645172fccafe1c291a706e93f48499ff5"},
+ {file = "SQLAlchemy-2.0.32-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723a40ee2cc7ea653645bd4cf024326dea2076673fc9d3d33f20f6c81db83e1d"},
+ {file = "SQLAlchemy-2.0.32-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:295ff8689544f7ee7e819529633d058bd458c1fd7f7e3eebd0f9268ebc56c2a0"},
+ {file = "SQLAlchemy-2.0.32-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49496b68cd190a147118af585173ee624114dfb2e0297558c460ad7495f9dfe2"},
+ {file = "SQLAlchemy-2.0.32-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:acd9b73c5c15f0ec5ce18128b1fe9157ddd0044abc373e6ecd5ba376a7e5d961"},
+ {file = "SQLAlchemy-2.0.32-cp311-cp311-win32.whl", hash = "sha256:9365a3da32dabd3e69e06b972b1ffb0c89668994c7e8e75ce21d3e5e69ddef28"},
+ {file = "SQLAlchemy-2.0.32-cp311-cp311-win_amd64.whl", hash = "sha256:8bd63d051f4f313b102a2af1cbc8b80f061bf78f3d5bd0843ff70b5859e27924"},
+ {file = "SQLAlchemy-2.0.32-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bab3db192a0c35e3c9d1560eb8332463e29e5507dbd822e29a0a3c48c0a8d92"},
+ {file = "SQLAlchemy-2.0.32-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:19d98f4f58b13900d8dec4ed09dd09ef292208ee44cc9c2fe01c1f0a2fe440e9"},
+ {file = "SQLAlchemy-2.0.32-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd33c61513cb1b7371fd40cf221256456d26a56284e7d19d1f0b9f1eb7dd7e8"},
+ {file = "SQLAlchemy-2.0.32-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6ba0497c1d066dd004e0f02a92426ca2df20fac08728d03f67f6960271feec"},
+ {file = "SQLAlchemy-2.0.32-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2b6be53e4fde0065524f1a0a7929b10e9280987b320716c1509478b712a7688c"},
+ {file = "SQLAlchemy-2.0.32-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:916a798f62f410c0b80b63683c8061f5ebe237b0f4ad778739304253353bc1cb"},
+ {file = "SQLAlchemy-2.0.32-cp312-cp312-win32.whl", hash = "sha256:31983018b74908ebc6c996a16ad3690301a23befb643093fcfe85efd292e384d"},
+ {file = "SQLAlchemy-2.0.32-cp312-cp312-win_amd64.whl", hash = "sha256:4363ed245a6231f2e2957cccdda3c776265a75851f4753c60f3004b90e69bfeb"},
+ {file = "SQLAlchemy-2.0.32-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b8afd5b26570bf41c35c0121801479958b4446751a3971fb9a480c1afd85558e"},
+ {file = "SQLAlchemy-2.0.32-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c750987fc876813f27b60d619b987b057eb4896b81117f73bb8d9918c14f1cad"},
+ {file = "SQLAlchemy-2.0.32-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ada0102afff4890f651ed91120c1120065663506b760da4e7823913ebd3258be"},
+ {file = "SQLAlchemy-2.0.32-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:78c03d0f8a5ab4f3034c0e8482cfcc415a3ec6193491cfa1c643ed707d476f16"},
+ {file = "SQLAlchemy-2.0.32-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:3bd1cae7519283ff525e64645ebd7a3e0283f3c038f461ecc1c7b040a0c932a1"},
+ {file = "SQLAlchemy-2.0.32-cp37-cp37m-win32.whl", hash = "sha256:01438ebcdc566d58c93af0171c74ec28efe6a29184b773e378a385e6215389da"},
+ {file = "SQLAlchemy-2.0.32-cp37-cp37m-win_amd64.whl", hash = "sha256:4979dc80fbbc9d2ef569e71e0896990bc94df2b9fdbd878290bd129b65ab579c"},
+ {file = "SQLAlchemy-2.0.32-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c742be912f57586ac43af38b3848f7688863a403dfb220193a882ea60e1ec3a"},
+ {file = "SQLAlchemy-2.0.32-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:62e23d0ac103bcf1c5555b6c88c114089587bc64d048fef5bbdb58dfd26f96da"},
+ {file = "SQLAlchemy-2.0.32-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:251f0d1108aab8ea7b9aadbd07fb47fb8e3a5838dde34aa95a3349876b5a1f1d"},
+ {file = "SQLAlchemy-2.0.32-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef18a84e5116340e38eca3e7f9eeaaef62738891422e7c2a0b80feab165905f"},
+ {file = "SQLAlchemy-2.0.32-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3eb6a97a1d39976f360b10ff208c73afb6a4de86dd2a6212ddf65c4a6a2347d5"},
+ {file = "SQLAlchemy-2.0.32-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0c1c9b673d21477cec17ab10bc4decb1322843ba35b481585facd88203754fc5"},
+ {file = "SQLAlchemy-2.0.32-cp38-cp38-win32.whl", hash = "sha256:c41a2b9ca80ee555decc605bd3c4520cc6fef9abde8fd66b1cf65126a6922d65"},
+ {file = "SQLAlchemy-2.0.32-cp38-cp38-win_amd64.whl", hash = "sha256:8a37e4d265033c897892279e8adf505c8b6b4075f2b40d77afb31f7185cd6ecd"},
+ {file = "SQLAlchemy-2.0.32-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:52fec964fba2ef46476312a03ec8c425956b05c20220a1a03703537824b5e8e1"},
+ {file = "SQLAlchemy-2.0.32-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:328429aecaba2aee3d71e11f2477c14eec5990fb6d0e884107935f7fb6001632"},
+ {file = "SQLAlchemy-2.0.32-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85a01b5599e790e76ac3fe3aa2f26e1feba56270023d6afd5550ed63c68552b3"},
+ {file = "SQLAlchemy-2.0.32-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaf04784797dcdf4c0aa952c8d234fa01974c4729db55c45732520ce12dd95b4"},
+ {file = "SQLAlchemy-2.0.32-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4488120becf9b71b3ac718f4138269a6be99a42fe023ec457896ba4f80749525"},
+ {file = "SQLAlchemy-2.0.32-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:14e09e083a5796d513918a66f3d6aedbc131e39e80875afe81d98a03312889e6"},
+ {file = "SQLAlchemy-2.0.32-cp39-cp39-win32.whl", hash = "sha256:0d322cc9c9b2154ba7e82f7bf25ecc7c36fbe2d82e2933b3642fc095a52cfc78"},
+ {file = "SQLAlchemy-2.0.32-cp39-cp39-win_amd64.whl", hash = "sha256:7dd8583df2f98dea28b5cd53a1beac963f4f9d087888d75f22fcc93a07cf8d84"},
+ {file = "SQLAlchemy-2.0.32-py3-none-any.whl", hash = "sha256:e567a8793a692451f706b363ccf3c45e056b67d90ead58c3bc9471af5d212202"},
+ {file = "SQLAlchemy-2.0.32.tar.gz", hash = "sha256:c1b88cc8b02b6a5f0efb0345a03672d4c897dc7d92585176f88c67346f565ea8"},
]
[package.dependencies]
@@ -3095,13 +3182,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7
[[package]]
name = "sympy"
-version = "1.13.0"
+version = "1.13.1"
description = "Computer algebra system (CAS) in Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "sympy-1.13.0-py3-none-any.whl", hash = "sha256:6b0b32a4673fb91bd3cac3b55406c8e01d53ae22780be467301cc452f6680c92"},
- {file = "sympy-1.13.0.tar.gz", hash = "sha256:3b6af8f4d008b9a1a6a4268b335b984b23835f26d1d60b0526ebc71d48a25f57"},
+ {file = "sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8"},
+ {file = "sympy-1.13.1.tar.gz", hash = "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f"},
]
[package.dependencies]
@@ -3296,13 +3383,13 @@ testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests", "ruff"]
[[package]]
name = "tqdm"
-version = "4.66.4"
+version = "4.66.5"
description = "Fast, Extensible Progress Meter"
optional = false
python-versions = ">=3.7"
files = [
- {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"},
- {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"},
+ {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"},
+ {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"},
]
[package.dependencies]
@@ -3357,93 +3444,6 @@ files = [
mypy-extensions = ">=0.3.0"
typing-extensions = ">=3.7.4"
-[[package]]
-name = "ujson"
-version = "5.10.0"
-description = "Ultra fast JSON encoder and decoder for Python"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "ujson-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd"},
- {file = "ujson-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf"},
- {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22cffecf73391e8abd65ef5f4e4dd523162a3399d5e84faa6aebbf9583df86d6"},
- {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26b0e2d2366543c1bb4fbd457446f00b0187a2bddf93148ac2da07a53fe51569"},
- {file = "ujson-5.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caf270c6dba1be7a41125cd1e4fc7ba384bf564650beef0df2dd21a00b7f5770"},
- {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a245d59f2ffe750446292b0094244df163c3dc96b3ce152a2c837a44e7cda9d1"},
- {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94a87f6e151c5f483d7d54ceef83b45d3a9cca7a9cb453dbdbb3f5a6f64033f5"},
- {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:29b443c4c0a113bcbb792c88bea67b675c7ca3ca80c3474784e08bba01c18d51"},
- {file = "ujson-5.10.0-cp310-cp310-win32.whl", hash = "sha256:c18610b9ccd2874950faf474692deee4223a994251bc0a083c114671b64e6518"},
- {file = "ujson-5.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:924f7318c31874d6bb44d9ee1900167ca32aa9b69389b98ecbde34c1698a250f"},
- {file = "ujson-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a5b366812c90e69d0f379a53648be10a5db38f9d4ad212b60af00bd4048d0f00"},
- {file = "ujson-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:502bf475781e8167f0f9d0e41cd32879d120a524b22358e7f205294224c71126"},
- {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b91b5d0d9d283e085e821651184a647699430705b15bf274c7896f23fe9c9d8"},
- {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:129e39af3a6d85b9c26d5577169c21d53821d8cf68e079060602e861c6e5da1b"},
- {file = "ujson-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f77b74475c462cb8b88680471193064d3e715c7c6074b1c8c412cb526466efe9"},
- {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ec0ca8c415e81aa4123501fee7f761abf4b7f386aad348501a26940beb1860f"},
- {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab13a2a9e0b2865a6c6db9271f4b46af1c7476bfd51af1f64585e919b7c07fd4"},
- {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:57aaf98b92d72fc70886b5a0e1a1ca52c2320377360341715dd3933a18e827b1"},
- {file = "ujson-5.10.0-cp311-cp311-win32.whl", hash = "sha256:2987713a490ceb27edff77fb184ed09acdc565db700ee852823c3dc3cffe455f"},
- {file = "ujson-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:f00ea7e00447918ee0eff2422c4add4c5752b1b60e88fcb3c067d4a21049a720"},
- {file = "ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5"},
- {file = "ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e"},
- {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043"},
- {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1"},
- {file = "ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3"},
- {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21"},
- {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2"},
- {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e"},
- {file = "ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e"},
- {file = "ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc"},
- {file = "ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287"},
- {file = "ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e"},
- {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557"},
- {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988"},
- {file = "ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816"},
- {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20"},
- {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0"},
- {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f"},
- {file = "ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165"},
- {file = "ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539"},
- {file = "ujson-5.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a984a3131da7f07563057db1c3020b1350a3e27a8ec46ccbfbf21e5928a43050"},
- {file = "ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73814cd1b9db6fc3270e9d8fe3b19f9f89e78ee9d71e8bd6c9a626aeaeaf16bd"},
- {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61e1591ed9376e5eddda202ec229eddc56c612b61ac6ad07f96b91460bb6c2fb"},
- {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2c75269f8205b2690db4572a4a36fe47cd1338e4368bc73a7a0e48789e2e35a"},
- {file = "ujson-5.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7223f41e5bf1f919cd8d073e35b229295aa8e0f7b5de07ed1c8fddac63a6bc5d"},
- {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc2fd6b3067c0782e7002ac3b38cf48608ee6366ff176bbd02cf969c9c20fe"},
- {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:232cc85f8ee3c454c115455195a205074a56ff42608fd6b942aa4c378ac14dd7"},
- {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cc6139531f13148055d691e442e4bc6601f6dba1e6d521b1585d4788ab0bfad4"},
- {file = "ujson-5.10.0-cp38-cp38-win32.whl", hash = "sha256:e7ce306a42b6b93ca47ac4a3b96683ca554f6d35dd8adc5acfcd55096c8dfcb8"},
- {file = "ujson-5.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:e82d4bb2138ab05e18f089a83b6564fee28048771eb63cdecf4b9b549de8a2cc"},
- {file = "ujson-5.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dfef2814c6b3291c3c5f10065f745a1307d86019dbd7ea50e83504950136ed5b"},
- {file = "ujson-5.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4734ee0745d5928d0ba3a213647f1c4a74a2a28edc6d27b2d6d5bd9fa4319e27"},
- {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47ebb01bd865fdea43da56254a3930a413f0c5590372a1241514abae8aa7c76"},
- {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee5e97c2496874acbf1d3e37b521dd1f307349ed955e62d1d2f05382bc36dd5"},
- {file = "ujson-5.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7490655a2272a2d0b072ef16b0b58ee462f4973a8f6bbe64917ce5e0a256f9c0"},
- {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba17799fcddaddf5c1f75a4ba3fd6441f6a4f1e9173f8a786b42450851bd74f1"},
- {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2aff2985cef314f21d0fecc56027505804bc78802c0121343874741650a4d3d1"},
- {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ad88ac75c432674d05b61184178635d44901eb749786c8eb08c102330e6e8996"},
- {file = "ujson-5.10.0-cp39-cp39-win32.whl", hash = "sha256:2544912a71da4ff8c4f7ab5606f947d7299971bdd25a45e008e467ca638d13c9"},
- {file = "ujson-5.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ff201d62b1b177a46f113bb43ad300b424b7847f9c5d38b1b4ad8f75d4a282a"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b6fee72fa77dc172a28f21693f64d93166534c263adb3f96c413ccc85ef6e64"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:61d0af13a9af01d9f26d2331ce49bb5ac1fb9c814964018ac8df605b5422dcb3"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecb24f0bdd899d368b715c9e6664166cf694d1e57be73f17759573a6986dd95a"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbd8fd427f57a03cff3ad6574b5e299131585d9727c8c366da4624a9069ed746"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beeaf1c48e32f07d8820c705ff8e645f8afa690cca1544adba4ebfa067efdc88"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:baed37ea46d756aca2955e99525cc02d9181de67f25515c468856c38d52b5f3b"},
- {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7663960f08cd5a2bb152f5ee3992e1af7690a64c0e26d31ba7b3ff5b2ee66337"},
- {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8640fb4072d36b08e95a3a380ba65779d356b2fee8696afeb7794cf0902d0a1"},
- {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78778a3aa7aafb11e7ddca4e29f46bc5139131037ad628cc10936764282d6753"},
- {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0111b27f2d5c820e7f2dbad7d48e3338c824e7ac4d2a12da3dc6061cc39c8e6"},
- {file = "ujson-5.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c66962ca7565605b355a9ed478292da628b8f18c0f2793021ca4425abf8b01e5"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba43cc34cce49cf2d4bc76401a754a81202d8aa926d0e2b79f0ee258cb15d3a4"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ac56eb983edce27e7f51d05bc8dd820586c6e6be1c5216a6809b0c668bb312b8"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44bd4b23a0e723bf8b10628288c2c7c335161d6840013d4d5de20e48551773b"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c10f4654e5326ec14a46bcdeb2b685d4ada6911050aa8baaf3501e57024b804"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0de4971a89a762398006e844ae394bd46991f7c385d7a6a3b93ba229e6dac17e"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e1402f0564a97d2a52310ae10a64d25bcef94f8dd643fcf5d310219d915484f7"},
- {file = "ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1"},
-]
-
[[package]]
name = "urllib3"
version = "2.2.2"
@@ -3914,5 +3914,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools",
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
-content-hash = "49b6ed93cf151eaeb5d1c05770ca3c3ed9b3c2a9a471b12df46f009b0f7737d9"
-
+content-hash = "57b26bb271a05da6f57b3991f72eae66593a78df70767c4defcbc352371a0bd1"
From 40ef2d0cec63123379524e5ae56de1181be334ca Mon Sep 17 00:00:00 2001
From: swve
Date: Wed, 7 Aug 2024 19:48:38 +0200
Subject: [PATCH 22/25] feat: grading, mark as done and grade showing
---
apps/api/src/routers/courses/assignments.py | 59 +++-
.../courses/activities/assignments.py | 296 +++++++++++++++++-
apps/api/src/services/trail/trail.py | 2 +-
.../activity/[activityid]/activity.tsx | 158 +++++++---
.../Subs/TaskTypes/TaskFileObject.tsx | 2 +-
.../subpages/Modals/EvaluateAssignment.tsx | 58 +++-
apps/web/services/courses/assignments.ts | 91 +++++-
7 files changed, 572 insertions(+), 94 deletions(-)
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index 91de1cbd..808234ff 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -20,7 +20,10 @@ from src.services.courses.activities.assignments import (
delete_assignment_submission,
delete_assignment_task,
delete_assignment_task_submission,
+ get_grade_assignment_submission,
+ grade_assignment_submission,
handle_assignment_task_submission,
+ mark_activity_as_done_for_user,
put_assignment_task_reference_file,
put_assignment_task_submission_file,
read_assignment,
@@ -263,7 +266,9 @@ async def api_handle_assignment_task_submissions(
)
-@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/user/{user_id}")
+@router.get(
+ "/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/user/{user_id}"
+)
async def api_read_user_assignment_task_submissions(
request: Request,
assignment_task_uuid: str,
@@ -410,7 +415,7 @@ async def api_update_user_assignment_submissions(
@router.delete("/{assignment_uuid}/submissions/{user_id}")
async def api_delete_user_assignment_submissions(
request: Request,
- assignment_id: str,
+ assignment_uuid: str,
user_id: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
@@ -419,5 +424,53 @@ async def api_delete_user_assignment_submissions(
Delete submissions for an assignment from a user
"""
return await delete_assignment_submission(
- request, assignment_id, user_id, current_user, db_session
+ request, user_id, assignment_uuid, current_user, db_session
+ )
+@router.get("/{assignment_uuid}/submissions/{user_id}/grade")
+async def api_get_submission_grade(
+ request: Request,
+ assignment_uuid: str,
+ user_id: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Grade submissions for an assignment from a user
+ """
+
+ return await get_grade_assignment_submission(
+ request, user_id, assignment_uuid, current_user, db_session
+ )
+
+@router.post("/{assignment_uuid}/submissions/{user_id}/grade")
+async def api_final_grade_submission(
+ request: Request,
+ assignment_uuid: str,
+ user_id: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Grade submissions for an assignment from a user
+ """
+
+ return await grade_assignment_submission(
+ request, user_id, assignment_uuid, current_user, db_session
+ )
+
+
+@router.post("/{assignment_uuid}/submissions/{user_id}/done")
+async def api_submission_mark_as_done(
+ request: Request,
+ assignment_uuid: str,
+ user_id: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Grade submissions for an assignment from a user
+ """
+
+ return await mark_activity_as_done_for_user(
+ request, user_id, assignment_uuid, current_user, db_session
)
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index c66ffb3e..7b6153e2 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -29,7 +29,9 @@ from src.db.courses.assignments import (
)
from src.db.courses.courses import Course
from src.db.organizations import Organization
-from src.db.users import AnonymousUser, PublicUser
+from src.db.trail_runs import TrailRun
+from src.db.trail_steps import TrailStep
+from src.db.users import AnonymousUser, PublicUser, User
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship_and_usergroups,
authorization_verify_if_element_is_public,
@@ -39,6 +41,7 @@ from src.services.courses.activities.uploads.sub_file import upload_submission_f
from src.services.courses.activities.uploads.tasks_ref_files import (
upload_reference_file,
)
+from src.services.trail.trail import check_trail_presence
## > Assignments CRUD
@@ -1097,6 +1100,80 @@ async def create_assignment_submission(
db_session.add(assignment_user_submission)
db_session.commit()
+ # User
+ statement = select(User).where(User.id == current_user.id)
+ user = db_session.exec(statement).first()
+
+ if not user:
+ raise HTTPException(
+ status_code=404,
+ detail="User not found",
+ )
+
+ # Activity
+ statement = select(Activity).where(Activity.id == assignment.activity_id)
+ activity = db_session.exec(statement).first()
+
+ if not activity:
+ raise HTTPException(
+ status_code=404,
+ detail="Activity not found",
+ )
+
+ # Add TrailStep
+ trail = await check_trail_presence(
+ org_id=course.org_id,
+ user_id=user.id,
+ request=request,
+ user=user,
+ db_session=db_session,
+ )
+
+ statement = select(TrailRun).where(
+ TrailRun.trail_id == trail.id,
+ TrailRun.course_id == course.id,
+ TrailRun.user_id == user.id,
+ )
+ trailrun = db_session.exec(statement).first()
+
+ if not trailrun:
+ trailrun = TrailRun(
+ trail_id=trail.id if trail.id is not None else 0,
+ course_id=course.id if course.id is not None else 0,
+ org_id=course.org_id,
+ user_id=user.id,
+ creation_date=str(datetime.now()),
+ update_date=str(datetime.now()),
+ )
+ db_session.add(trailrun)
+ db_session.commit()
+ db_session.refresh(trailrun)
+
+ statement = select(TrailStep).where(
+ TrailStep.trailrun_id == trailrun.id,
+ TrailStep.activity_id == activity.id,
+ TrailStep.user_id == user.id,
+ )
+ trailstep = db_session.exec(statement).first()
+
+ if not trailstep:
+ trailstep = TrailStep(
+ trailrun_id=trailrun.id if trailrun.id is not None else 0,
+ activity_id=activity.id if activity.id is not None else 0,
+ course_id=course.id if course.id is not None else 0,
+ trail_id=trail.id if trail.id is not None else 0,
+ org_id=course.org_id,
+ complete=True,
+ teacher_verified=False,
+ grade="",
+ user_id=user.id,
+ creation_date=str(datetime.now()),
+ update_date=str(datetime.now()),
+ )
+ db_session.add(trailstep)
+ db_session.commit()
+ db_session.refresh(trailstep)
+
# return assignment user submission read
return AssignmentUserSubmissionRead.model_validate(assignment_user_submission)
@@ -1262,14 +1339,24 @@ async def update_assignment_submission(
async def delete_assignment_submission(
request: Request,
user_id: str,
- assignment_id: str,
+ assignment_uuid: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
# Check if assignment user submission exists
statement = select(AssignmentUserSubmission).where(
AssignmentUserSubmission.user_id == user_id,
- AssignmentUserSubmission.assignment_id == assignment_id,
+ AssignmentUserSubmission.assignment_id == assignment.id,
)
assignment_user_submission = db_session.exec(statement).first()
@@ -1279,18 +1366,6 @@ async def delete_assignment_submission(
detail="Assignment User Submission not found",
)
- # Check if assignment exists
- statement = select(Assignment).where(
- Assignment.id == assignment_user_submission.assignment_id
- )
- assignment = db_session.exec(statement).first()
-
- if not assignment:
- raise HTTPException(
- status_code=404,
- detail="Assignment not found",
- )
-
# Check if course exists
statement = select(Course).where(Course.id == assignment.course_id)
course = db_session.exec(statement).first()
@@ -1311,6 +1386,197 @@ async def delete_assignment_submission(
return {"message": "Assignment User Submission deleted"}
+## > Assignments Submissions Grading
+async def grade_assignment_submission(
+ request: Request,
+ user_id: str,
+ assignment_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if assignment user submission exists
+ statement = select(AssignmentUserSubmission).where(
+ AssignmentUserSubmission.user_id == user_id,
+ AssignmentUserSubmission.assignment_id == assignment.id,
+ )
+ assignment_user_submission = db_session.exec(statement).first()
+
+ if not assignment_user_submission:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment User Submission not found",
+ )
+
+ # Get all the task submissions for the user
+ task_subs = select(AssignmentTaskSubmission).where(
+ AssignmentTaskSubmission.user_id == user_id,
+ AssignmentTaskSubmission.activity_id == assignment.activity_id,
+ )
+ task_submissions = db_session.exec(task_subs).all()
+
+ # Calculate the grade
+ grade = 0
+ for task_submission in task_submissions:
+ grade += task_submission.grade
+
+ # Update the assignment user submission
+ assignment_user_submission.grade = grade
+
+ # Insert Assignment User Submission in DB
+ db_session.add(assignment_user_submission)
+ db_session.commit()
+ db_session.refresh(assignment_user_submission)
+
+ # Change the status of the submission
+ assignment_user_submission.submission_status = AssignmentUserSubmissionStatus.GRADED
+
+ # Insert Assignment User Submission in DB
+ db_session.add(assignment_user_submission)
+ db_session.commit()
+ db_session.refresh(assignment_user_submission)
+
+ # return OK
+ return {
+ "message": "Assignment User Submission graded with the grade of " + str(grade)
+ }
+
+
+async def get_grade_assignment_submission(
+ request: Request,
+ user_id: str,
+ assignment_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+
+ # Check if assignment exists
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if assignment user submission exists
+ statement = select(AssignmentUserSubmission).where(
+ AssignmentUserSubmission.user_id == user_id,
+ AssignmentUserSubmission.assignment_id == assignment.id,
+ )
+ assignment_user_submission = db_session.exec(statement).first()
+
+ if not assignment_user_submission:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment User Submission not found",
+ )
+
+ # Get the max grade value from the sum of every assignmenttask
+ statement = select(AssignmentTask).where(
+ AssignmentTask.assignment_id == assignment.id
+ )
+ assignment_tasks = db_session.exec(statement).all()
+ max_grade = 0
+
+ for task in assignment_tasks:
+ max_grade += task.max_grade_value
+
+ # Now get the grade from the user submission
+ statement = select(AssignmentUserSubmission).where(
+ AssignmentUserSubmission.user_id == user_id,
+ AssignmentUserSubmission.assignment_id == assignment.id,
+ )
+ assignment_user_submission = db_session.exec(statement).first()
+
+ if not assignment_user_submission:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment User Submission not found",
+ )
+
+ # return the grade
+ return {
+ "grade": int(assignment_user_submission.grade),
+ "max_grade": max_grade,
+ "grading_type": assignment.grading_type,
+ }
+
+
+async def mark_activity_as_done_for_user(
+ request: Request,
+ user_id: str,
+ assignment_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Get Assignment
+ statement = select(Assignment).where(Assignment.assignment_uuid == assignment_uuid)
+ assignment = db_session.exec(statement).first()
+
+ if not assignment:
+ raise HTTPException(
+ status_code=404,
+ detail="Assignment not found",
+ )
+
+ # Check if activity exists
+ statement = select(Activity).where(Activity.id == assignment.activity_id)
+ activity = db_session.exec(statement).first()
+
+ if not activity:
+ raise HTTPException(
+ status_code=404,
+ detail="Activity not found",
+ )
+
+ # Check if user exists
+ statement = select(User).where(User.id == user_id)
+ user = db_session.exec(statement).first()
+
+ if not user:
+ raise HTTPException(
+ status_code=404,
+ detail="User not found",
+ )
+
+ # Check if user is enrolled in the course
+ trailsteps = select(TrailStep).where(
+ TrailStep.activity_id == activity.id,
+ TrailStep.user_id == user_id,
+ )
+ trailstep = db_session.exec(trailsteps).first()
+
+ if not trailstep:
+ raise HTTPException(
+ status_code=404,
+ detail="User not enrolled in the course",
+ )
+
+ # Mark activity as done
+ trailstep.complete = True
+ trailstep.update_date = str(datetime.now())
+
+ # Insert TrailStep in DB
+ db_session.add(trailstep)
+ db_session.commit()
+ db_session.refresh(trailstep)
+
+ # return OK
+ return {"message": "Activity marked as done for user"}
+
+
## 🔒 RBAC Utils ##
diff --git a/apps/api/src/services/trail/trail.py b/apps/api/src/services/trail/trail.py
index 3101ceca..7daebdea 100644
--- a/apps/api/src/services/trail/trail.py
+++ b/apps/api/src/services/trail/trail.py
@@ -244,7 +244,7 @@ async def add_activity_to_trail(
course_id=course.id if course.id is not None else 0,
trail_id=trail.id if trail.id is not None else 0,
org_id=course.org_id,
- complete=False,
+ complete=True,
teacher_verified=False,
grade="",
user_id=user.id,
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
index d441b31c..45ea5944 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
@@ -3,7 +3,7 @@ import Link from 'next/link'
import { getAPIUrl, getUriWithOrg } from '@services/config/config'
import Canva from '@components/Objects/Activities/DynamicCanva/DynamicCanva'
import VideoActivity from '@components/Objects/Activities/Video/Video'
-import { BookOpenCheck, Check, MoreVertical, UserRoundPen } from 'lucide-react'
+import { BookOpenCheck, Check, CheckCircle, MoreVertical, UserRoundPen } from 'lucide-react'
import { markActivityAsComplete } from '@services/courses/activity'
import DocumentPdfActivity from '@components/Objects/Activities/DocumentPdf/DocumentPdf'
import ActivityIndicators from '@components/Pages/Courses/ActivityIndicators'
@@ -17,7 +17,7 @@ import AIActivityAsk from '@components/Objects/Activities/AI/AIActivityAsk'
import AIChatBotProvider from '@components/Contexts/AI/AIChatBotContext'
import { useLHSession } from '@components/Contexts/LHSessionContext'
import React, { useEffect } from 'react'
-import { getAssignmentFromActivityUUID, submitAssignmentForGrading } from '@services/courses/assignments'
+import { getAssignmentFromActivityUUID, getFinalGrade, submitAssignmentForGrading } from '@services/courses/assignments'
import AssignmentStudentActivity from '@components/Objects/Activities/Assignment/AssignmentStudentActivity'
import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext'
import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext'
@@ -79,7 +79,7 @@ function ActivityClient(props: ActivityClientProps) {
setBgColor('bg-zinc-950');
}
}
- , [activity,pathname ])
+ , [activity, pathname])
return (
<>
@@ -127,37 +127,37 @@ function ActivityClient(props: ActivityClientProps) {
- {activity && activity.published == true && (
-
- {activity.activity_type != 'TYPE_ASSIGNMENT' &&
- <>
-
-
-
- >
- }
- {activity.activity_type == 'TYPE_ASSIGNMENT' &&
- <>
-
-
-
+ {activity.activity_type != 'TYPE_ASSIGNMENT' &&
+ <>
+
+
+
-
- >
- }
+ >
+ }
+ {activity.activity_type == 'TYPE_ASSIGNMENT' &&
+ <>
+
+
+
+
+ >
+ }
-
- )}
+
+ )}
{activity && activity.published == false && (
@@ -240,7 +240,7 @@ export function MarkStatus(props: {
)
if (run) {
return run.steps.find(
- (step: any) => step.activity_id == props.activity.id
+ (step: any) => (step.activity_id == props.activity.id) && (step.complete == true)
)
}
}
@@ -252,7 +252,7 @@ export function MarkStatus(props: {
{' '}
-
Already completed
+
Complete
) : (
{
if (props.assignment) {
@@ -296,38 +297,91 @@ function AssignmentTools(props: {
}
}
+ const getGradingBasedOnMethod = async () => {
+ const res = await getFinalGrade(
+ session.data?.user?.id,
+ props.assignment?.assignment_uuid,
+ session.data?.tokens?.access_token
+ );
+
+ if (res.success) {
+ const { grade, max_grade, grading_type } = res.data;
+ let displayGrade;
+
+ switch (grading_type) {
+ case 'ALPHABET':
+ displayGrade = convertNumericToAlphabet(grade, max_grade);
+ break;
+ case 'NUMERIC':
+ displayGrade = `${grade}/${max_grade}`;
+ break;
+ case 'PERCENTAGE':
+ const percentage = (grade / max_grade) * 100;
+ displayGrade = `${percentage.toFixed(2)}%`;
+ break;
+ default:
+ displayGrade = 'Unknown grading type';
+ }
+
+ // Use displayGrade here, e.g., update state or display it
+ setFinalGrade(displayGrade);
+ } else {
+ }
+ };
+
+ // Helper function to convert numeric grade to alphabet grade
+ function convertNumericToAlphabet(grade : any, maxGrade : any) {
+ const percentage = (grade / maxGrade) * 100;
+ if (percentage >= 90) return 'A';
+ if (percentage >= 80) return 'B';
+ if (percentage >= 70) return 'C';
+ if (percentage >= 60) return 'D';
+ return 'F';
+ }
+
useEffect(() => {
+ getGradingBasedOnMethod();
}
, [submission, props.assignment])
- return <>
- {submission && submission.length == 0 && (
+ if (!submission || submission.length === 0) {
+ return (
-
-
- {' '}
- Submit for grading
-
}
- functionToExecute={() => submitForGradingUI()}
+
+
+ Submit for grading
+
+ }
+ functionToExecute={submitForGradingUI}
status="info"
/>
- )}
- {submission && submission.length > 0 && (
-
-
-
- {' '}
- Grading in progress
-
)
- }
- >
+ )
+ }
+
+ if (submission[0].submission_status === 'SUBMITTED') {
+ return (
+
+
+ Grading in progress
+
+ )
+ }
+
+ if (submission[0].submission_status === 'GRADED') {
+ return (
+
+
+ Graded {finalGrade}
+
+ )
+ }
+
+ // Default return in case none of the conditions are met
+ return null
}
export default ActivityClient
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
index 5a5c8d6d..31360191 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx
@@ -195,7 +195,7 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta
-
Please download the file and grade it manually, then input the grade below
+
Please download the file and grade it manually, then input the grade above
{userSubmissions.fileUUID && !isLoading && assignmentTaskUUID && (
{assignments && assignments?.assignment_tasks?.sort((a: any, b: any) => a.id - b.id).map((task: any, index: number) => {
@@ -53,18 +84,29 @@ function EvaluateAssignment({ user_id }: any) {
-
+
{task.assignment_type === 'QUIZ' && }
- {task.assignment_type === 'FILE_SUBMISSION' && }
+ {task.assignment_type === 'FILE_SUBMISSION' && }
)
})}
-
-
)
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
index 3e558801..e7ea35ce 100644
--- a/apps/web/services/courses/assignments.ts
+++ b/apps/web/services/courses/assignments.ts
@@ -165,13 +165,12 @@ export async function updateReferenceFile(
assignmentUUID: string,
access_token: string
) {
+ // Send file thumbnail as form data
+ const formData = new FormData()
- // Send file thumbnail as form data
- const formData = new FormData()
-
- if (file) {
- formData.append('reference_file', file)
- }
+ if (file) {
+ formData.append('reference_file', file)
+ }
const result: any = await fetch(
`${getAPIUrl()}assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/ref_file`,
RequestBodyFormWithAuthHeader('POST', formData, null, access_token)
@@ -180,20 +179,18 @@ export async function updateReferenceFile(
return res
}
-
export async function updateSubFile(
file: any,
assignmentTaskUUID: string,
assignmentUUID: string,
access_token: string
) {
+ // Send file thumbnail as form data
+ const formData = new FormData()
- // Send file thumbnail as form data
- const formData = new FormData()
-
- if (file) {
- formData.append('sub_file', file)
- }
+ if (file) {
+ formData.append('sub_file', file)
+ }
const result: any = await fetch(
`${getAPIUrl()}assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/sub_file`,
RequestBodyFormWithAuthHeader('POST', formData, null, access_token)
@@ -214,4 +211,70 @@ export async function submitAssignmentForGrading(
)
const res = await getResponseMetadata(result)
return res
-}
\ No newline at end of file
+}
+
+export async function deleteUserSubmission(
+ user_id: string,
+ assignmentUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/submissions/${user_id}`,
+ RequestBodyWithAuthHeader('DELETE', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
+
+export async function putUserSubmission(
+ body: any,
+ user_id: string,
+ assignmentUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/submissions/${user_id}`,
+ RequestBodyWithAuthHeader('PUT', body, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
+
+export async function putFinalGrade(
+ user_id: string,
+ assignmentUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/submissions/${user_id}/grade`,
+ RequestBodyWithAuthHeader('POST', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
+
+export async function getFinalGrade(
+ user_id: string,
+ assignmentUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/submissions/${user_id}/grade`,
+ RequestBodyWithAuthHeader('GET', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
+
+export async function markActivityAsDoneForUser(
+ user_id: string,
+ assignmentUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/${assignmentUUID}/submissions/${user_id}/done`,
+ RequestBodyWithAuthHeader('POST', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
From 364c24e15d5493c39feaf19ba4b7553d5be9f6d7 Mon Sep 17 00:00:00 2001
From: swve
Date: Wed, 7 Aug 2024 23:47:18 +0200
Subject: [PATCH 23/25] feat: enable assignments page
---
apps/api/src/routers/courses/assignments.py | 19 +++
.../courses/activities/assignments.py | 34 ++++
.../assignments/[assignmentuuid]/page.tsx | 5 +-
.../orgs/[orgslug]/dash/assignments/page.tsx | 160 +++++++++++++++++-
apps/web/services/courses/assignments.ts | 12 ++
apps/web/styles/globals.css | 5 +
6 files changed, 232 insertions(+), 3 deletions(-)
diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py
index 808234ff..277ee134 100644
--- a/apps/api/src/routers/courses/assignments.py
+++ b/apps/api/src/routers/courses/assignments.py
@@ -20,6 +20,7 @@ from src.services.courses.activities.assignments import (
delete_assignment_submission,
delete_assignment_task,
delete_assignment_task_submission,
+ get_assignments_from_course,
get_grade_assignment_submission,
grade_assignment_submission,
handle_assignment_task_submission,
@@ -426,6 +427,8 @@ async def api_delete_user_assignment_submissions(
return await delete_assignment_submission(
request, user_id, assignment_uuid, current_user, db_session
)
+
+
@router.get("/{assignment_uuid}/submissions/{user_id}/grade")
async def api_get_submission_grade(
request: Request,
@@ -442,6 +445,7 @@ async def api_get_submission_grade(
request, user_id, assignment_uuid, current_user, db_session
)
+
@router.post("/{assignment_uuid}/submissions/{user_id}/grade")
async def api_final_grade_submission(
request: Request,
@@ -474,3 +478,18 @@ async def api_submission_mark_as_done(
return await mark_activity_as_done_for_user(
request, user_id, assignment_uuid, current_user, db_session
)
+
+
+@router.get("/course/{course_uuid}")
+async def api_get_assignments(
+ request: Request,
+ course_uuid: str,
+ current_user: PublicUser = Depends(get_current_user),
+ db_session=Depends(get_db_session),
+):
+ """
+ Get assignments for a course
+ """
+ return await get_assignments_from_course(
+ request, course_uuid, current_user, db_session
+ )
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index 7b6153e2..bf790ed4 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -1576,6 +1576,40 @@ async def mark_activity_as_done_for_user(
# return OK
return {"message": "Activity marked as done for user"}
+async def get_assignments_from_course(
+ request: Request,
+ course_uuid: str,
+ current_user: PublicUser | AnonymousUser,
+ db_session: Session,
+):
+ # Find course
+ statement = select(Course).where(Course.course_uuid == course_uuid)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+ # Get Activities
+ statement = select(Activity).where(Activity.course_id == course.id)
+ activities = db_session.exec(statement).all()
+
+ # Get Assignments
+ assignments = []
+ for activity in activities:
+ statement = select(Assignment).where(Assignment.activity_id == activity.id)
+ assignment = db_session.exec(statement).first()
+ if assignment:
+ assignments.append(assignment)
+
+ # RBAC check
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+
+ # return assignments read
+ return [AssignmentRead.model_validate(assignment) for assignment in assignments]
+
## 🔒 RBAC Utils ##
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
index b4056e04..f4c0fdf0 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx
@@ -10,7 +10,7 @@ import { mutate } from 'swr';
import { getAPIUrl } from '@services/config/config';
import toast from 'react-hot-toast';
import Link from 'next/link';
-import { useParams } from 'next/navigation';
+import { useParams, useSearchParams } from 'next/navigation';
import { updateActivity } from '@services/courses/activities';
// Lazy Loading
import dynamic from 'next/dynamic';
@@ -19,7 +19,8 @@ const AssignmentSubmissionsSubPage = dynamic(() => import('./subpages/Assignment
function AssignmentEdit() {
const params = useParams<{ assignmentuuid: string; }>()
- const [selectedSubPage, setSelectedSubPage] = React.useState('editor')
+ const searchParams = useSearchParams()
+ const [selectedSubPage, setSelectedSubPage] = React.useState( searchParams.get('subpage') || 'editor')
return (
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
index c54c9cc9..5a92a45c 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
@@ -1,9 +1,167 @@
+'use client';
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import { useOrg } from '@components/Contexts/OrgContext';
+import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'
+import { getAPIUrl, getUriWithOrg } from '@services/config/config';
+import { getAssignmentsFromACourse } from '@services/courses/assignments';
+import { getCourseThumbnailMediaDirectory } from '@services/media/media';
+import { swrFetcher } from '@services/utils/ts/requests';
+import { Book, EllipsisVertical, GalleryVertical, GalleryVerticalEnd, Layers2, PenBox, UserRoundPen } from 'lucide-react';
+import Link from 'next/link';
import React from 'react'
+import useSWR from 'swr';
function AssignmentsHome() {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const org = useOrg() as any;
+ const [courseAssignments, setCourseAssignments] = React.useState([])
+
+ const { data: courses } = useSWR(`${getAPIUrl()}courses/org_slug/${org?.slug}/page/1/limit/50`, (url) => swrFetcher(url, access_token))
+
+ async function getAvailableAssignmentsForCourse(course_uuid: string) {
+ const res = await getAssignmentsFromACourse(course_uuid, access_token)
+ return res.data
+ }
+
+ function removeAssignmentPrefix(assignment_uuid: string) {
+ return assignment_uuid.replace('assignment_', '')
+ }
+
+ function removeCoursePrefix(course_uuid: string) {
+ return course_uuid.replace('course_', '')
+ }
+
+
+ React.useEffect(() => {
+ if (courses) {
+ const course_uuids = courses.map((course: any) => course.course_uuid)
+ const courseAssignmentsPromises = course_uuids.map((course_uuid: string) => getAvailableAssignmentsForCourse(course_uuid))
+ Promise.all(courseAssignmentsPromises).then((results) => {
+ setCourseAssignments(results)
+ })
+ }
+ }, [courses])
+
+
return (
- AssignmentsHome
+
+
+
+
+
Assignments
+
+
+ {courseAssignments.map((assignments: any, index: number) => (
+
+
+
+
+
+
+
Course
+
{courses[index].name}
+
+
+
+
+
+
Course Editor
+
+
+
+
+ {assignments && assignments.map((assignment: any) => (
+
+
+
+
{assignment.title}
+
{assignment.description}
+
+
+
+
+
+
+
Editor
+
+
+
+
Submissions
+
+
+
+ ))}
+
+
+ ))}
+
+
+
+
+
)
}
+const MiniThumbnail = (props: { course: any }) => {
+ const org = useOrg() as any
+
+ // function to remove "course_" from the course_uuid
+ function removeCoursePrefix(course_uuid: string) {
+ return course_uuid.replace('course_', '')
+ }
+
+ return (
+
+ {props.course.thumbnail_image ? (
+
+ ) : (
+
+ )}
+
+ )
+}
+
+
export default AssignmentsHome
\ No newline at end of file
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
index e7ea35ce..0d301036 100644
--- a/apps/web/services/courses/assignments.ts
+++ b/apps/web/services/courses/assignments.ts
@@ -278,3 +278,15 @@ export async function markActivityAsDoneForUser(
const res = await getResponseMetadata(result)
return res
}
+
+export async function getAssignmentsFromACourse(
+ courseUUID: string,
+ access_token: string
+) {
+ const result: any = await fetch(
+ `${getAPIUrl()}assignments/course/${courseUUID}`,
+ RequestBodyWithAuthHeader('GET', null, null, access_token)
+ )
+ const res = await getResponseMetadata(result)
+ return res
+}
diff --git a/apps/web/styles/globals.css b/apps/web/styles/globals.css
index 393a85b8..6b8d69b3 100644
--- a/apps/web/styles/globals.css
+++ b/apps/web/styles/globals.css
@@ -9,6 +9,11 @@
@apply shadow-md shadow-gray-300/25 outline outline-1 outline-neutral-200/40
}
+.light-shadow {
+ @apply shadow-lg shadow-gray-300/15 outline outline-1 outline-neutral-200/30
+}
+
+
.custom-dots-bg {
@apply bg-fixed;
background-image: radial-gradient(#4744446b 1px, transparent 1px),
From 360c6b1e1a9638c7062245a541120a3339339ce3 Mon Sep 17 00:00:00 2001
From: swve
Date: Thu, 8 Aug 2024 00:28:33 +0200
Subject: [PATCH 24/25] feat: Update RBAC checks for assignments
---
.../courses/activities/assignments.py | 36 ++++++++++++++-----
.../orgs/[orgslug]/dash/assignments/page.tsx | 11 +++++-
2 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py
index bf790ed4..a10d5f44 100644
--- a/apps/api/src/services/courses/activities/assignments.py
+++ b/apps/api/src/services/courses/activities/assignments.py
@@ -1,7 +1,3 @@
-####################################################
-# CRUD
-####################################################
-
from datetime import datetime
from typing import Literal
from uuid import uuid4
@@ -553,7 +549,7 @@ async def put_assignment_task_submission_file(
org = db_session.exec(org_statement).first()
# RBAC check
- await rbac_check(request, course.course_uuid, current_user, "read", db_session)
+ await rbac_check(request, course.course_uuid, current_user, "update", db_session)
# Upload reference file
if sub_file and sub_file.filename and activity and org:
@@ -948,7 +944,7 @@ async def update_assignment_task_submission(
)
# RBAC check
- await rbac_check(request, course.course_uuid, current_user, "update", db_session)
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
# Update only the fields that were passed in
for var, value in vars(assignment_task_submission_object).items():
@@ -1083,7 +1079,7 @@ async def create_assignment_submission(
)
# RBAC check
- await rbac_check(request, course.course_uuid, current_user, "create", db_session)
+ await rbac_check(request, course.course_uuid, current_user, "update", db_session)
# Create Assignment User Submission
assignment_user_submission = AssignmentUserSubmission(
@@ -1319,7 +1315,7 @@ async def update_assignment_submission(
)
# RBAC check
- await rbac_check(request, course.course_uuid, current_user, "update", db_session)
+ await rbac_check(request, course.course_uuid, current_user, "read", db_session)
# Update only the fields that were passed in
for var, value in vars(assignment_user_submission_object).items():
@@ -1404,6 +1400,18 @@ async def grade_assignment_submission(
status_code=404,
detail="Assignment not found",
)
+
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+
+ await rbac_check(request, course.course_uuid, current_user, "update", db_session)
# Check if assignment user submission exists
statement = select(AssignmentUserSubmission).where(
@@ -1535,6 +1543,18 @@ async def mark_activity_as_done_for_user(
statement = select(Activity).where(Activity.id == assignment.activity_id)
activity = db_session.exec(statement).first()
+ statement = select(Course).where(Course.id == assignment.course_id)
+ course = db_session.exec(statement).first()
+
+ if not course:
+ raise HTTPException(
+ status_code=404,
+ detail="Course not found",
+ )
+
+
+ await rbac_check(request, course.course_uuid, current_user, "update", db_session)
+
if not activity:
raise HTTPException(
status_code=404,
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
index 5a92a45c..67500c6b 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
@@ -6,7 +6,7 @@ import { getAPIUrl, getUriWithOrg } from '@services/config/config';
import { getAssignmentsFromACourse } from '@services/courses/assignments';
import { getCourseThumbnailMediaDirectory } from '@services/media/media';
import { swrFetcher } from '@services/utils/ts/requests';
-import { Book, EllipsisVertical, GalleryVertical, GalleryVerticalEnd, Layers2, PenBox, UserRoundPen } from 'lucide-react';
+import { Book, EllipsisVertical, GalleryVertical, GalleryVerticalEnd, Info, Layers2, PenBox, UserRoundPen } from 'lucide-react';
import Link from 'next/link';
import React from 'react'
import useSWR from 'swr';
@@ -113,6 +113,15 @@ function AssignmentsHome() {
))}
+
+ {assignments.length === 0 && (
+ <>
+
+
+
No assignments available for this course, create course assignments from the course editor
+
+ >
+ )}
))}
From dc1673c053cf87263418a217b954ddef1b3f62fa Mon Sep 17 00:00:00 2001
From: swve
Date: Thu, 8 Aug 2024 21:07:29 +0200
Subject: [PATCH 25/25] fix: UI bugs
---
.../activity/[activityid]/activity.tsx | 16 +++++++++-------
.../app/orgs/[orgslug]/dash/assignments/page.tsx | 7 +++----
.../Activities/Assignment/AssignmentBoxUI.tsx | 13 ++++++++-----
apps/web/services/courses/assignments.ts | 2 +-
4 files changed, 21 insertions(+), 17 deletions(-)
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
index 45ea5944..91e0aac7 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
@@ -21,7 +21,7 @@ import { getAssignmentFromActivityUUID, getFinalGrade, submitAssignmentForGradin
import AssignmentStudentActivity from '@components/Objects/Activities/Assignment/AssignmentStudentActivity'
import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext'
import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext'
-import AssignmentSubmissionProvider, { AssignmentSubmissionContext, useAssignmentSubmission } from '@components/Contexts/Assignments/AssignmentSubmissionContext'
+import AssignmentSubmissionProvider, { useAssignmentSubmission } from '@components/Contexts/Assignments/AssignmentSubmissionContext'
import toast from 'react-hot-toast'
import { mutate } from 'swr'
import ConfirmationModal from '@components/StyledElements/ConfirmationModal/ConfirmationModal'
@@ -303,11 +303,11 @@ function AssignmentTools(props: {
props.assignment?.assignment_uuid,
session.data?.tokens?.access_token
);
-
+
if (res.success) {
const { grade, max_grade, grading_type } = res.data;
let displayGrade;
-
+
switch (grading_type) {
case 'ALPHABET':
displayGrade = convertNumericToAlphabet(grade, max_grade);
@@ -322,15 +322,15 @@ function AssignmentTools(props: {
default:
displayGrade = 'Unknown grading type';
}
-
+
// Use displayGrade here, e.g., update state or display it
setFinalGrade(displayGrade);
} else {
}
};
-
+
// Helper function to convert numeric grade to alphabet grade
- function convertNumericToAlphabet(grade : any, maxGrade : any) {
+ function convertNumericToAlphabet(grade: any, maxGrade: any) {
const percentage = (grade / maxGrade) * 100;
if (percentage >= 90) return 'A';
if (percentage >= 80) return 'B';
@@ -340,7 +340,9 @@ function AssignmentTools(props: {
}
useEffect(() => {
- getGradingBasedOnMethod();
+ if ( submission && submission.length > 0 && submission[0].submission_status === 'GRADED') {
+ getGradingBasedOnMethod();
+ }
}
, [submission, props.assignment])
diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
index 67500c6b..020fb5ce 100644
--- a/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/assignments/page.tsx
@@ -59,10 +59,9 @@ function AssignmentsHome() {
-
Course
+
Course
{courses[index].name}
-
Assignment
{assignment.title}
- {assignment.description}
+ {assignment.description}
@@ -121,7 +120,7 @@ function AssignmentsHome() {
No assignments available for this course, create course assignments from the course editor
>
- )}
+ )}
))}
diff --git a/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
index efd842ba..73070c8a 100644
--- a/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
+++ b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx
@@ -20,9 +20,10 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
const [customGrade, setCustomGrade] = React.useState(0)
const submission = useAssignmentSubmission() as any
useEffect(() => {
+ console.log(submission)
}
, [submission])
-
+
return (
@@ -88,10 +89,11 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
{/* Grading button */}
{view === 'grading' &&
gradeFC && gradeFC()}
className='flex px-0.5 py-0.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
Current points : {currentPoints}
-
+
gradeFC && gradeFC()}
+ className='bg-gradient-to-bl text-orange-700 bg-orange-300/20 hover:bg-orange-300/10 items-center flex rounded-md px-2 py-1 space-x-2'>
Grade
@@ -101,13 +103,14 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
{/* CustomGrading button */}
{view === 'custom-grading' && maxPoints &&
gradeCustomFC && gradeCustomFC(customGrade)}
className='flex px-0.5 py-0.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
Current points : {currentPoints}
setCustomGrade(parseInt(e.target.value))}
placeholder={maxPoints.toString()} className='w-[100px] light-shadow text-sm py-0.5 outline outline-gray-200 rounded-lg px-2' type="number" />
-
+
gradeCustomFC && gradeCustomFC(customGrade)}
+ className='bg-gradient-to-bl text-orange-700 bg-orange-300/20 hover:bg-orange-300/10 items-center flex rounded-md px-2 py-1 space-x-2'>
Grade
diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts
index 0d301036..432adf50 100644
--- a/apps/web/services/courses/assignments.ts
+++ b/apps/web/services/courses/assignments.ts
@@ -7,7 +7,7 @@ import {
export async function createAssignment(body: any, access_token: string) {
const result: any = await fetch(
- `${getAPIUrl()}assignments`,
+ `${getAPIUrl()}assignments/`,
RequestBodyWithAuthHeader('POST', body, null, access_token)
)
const res = await getResponseMetadata(result)