Merge branch 'dev' into screenshotone

screenshotone
Aarushi 2025-01-30 13:39:58 +00:00 committed by GitHub
commit 0b53f8dc4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 1046 additions and 531 deletions

18
.deepsource.toml Normal file
View File

@ -0,0 +1,18 @@
version = 1
test_patterns = ["**/*.spec.ts","**/*_test.py","**/*_tests.py","**/test_*.py"]
exclude_patterns = ["classic/**"]
[[analyzers]]
name = "javascript"
[analyzers.meta]
plugins = ["react"]
environment = ["nodejs"]
[[analyzers]]
name = "python"
[analyzers.meta]
runtime_version = "3.x.x"

View File

@ -37,6 +37,25 @@ jobs:
run: |
yarn lint
type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "21"
- name: Install dependencies
run: |
yarn install --frozen-lockfile
- name: Run tsc check
run: |
yarn type-check
test:
runs-on: ubuntu-latest
strategy:

View File

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
[[package]]
name = "aiohappyeyeballs"
@ -6,7 +6,6 @@ version = "2.4.0"
description = "Happy Eyeballs for asyncio"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "aiohappyeyeballs-2.4.0-py3-none-any.whl", hash = "sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd"},
{file = "aiohappyeyeballs-2.4.0.tar.gz", hash = "sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2"},
@ -18,7 +17,6 @@ version = "3.10.5"
description = "Async http client/server framework (asyncio)"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3"},
{file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6"},
@ -131,7 +129,6 @@ version = "1.3.1"
description = "aiosignal: a list of registered asynchronous callbacks"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"},
{file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"},
@ -146,7 +143,6 @@ version = "0.7.0"
description = "Reusable constraint types to use with typing.Annotated"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
@ -158,7 +154,6 @@ version = "4.4.0"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"},
{file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"},
@ -181,12 +176,10 @@ version = "4.0.3"
description = "Timeout context manager for asyncio programs"
optional = false
python-versions = ">=3.7"
groups = ["main", "dev"]
files = [
{file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
{file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
]
markers = {main = "python_version < \"3.11\"", dev = "python_full_version < \"3.11.3\""}
[[package]]
name = "attrs"
@ -194,7 +187,6 @@ version = "24.2.0"
description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
{file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
@ -214,7 +206,6 @@ version = "5.5.0"
description = "Extensible memoizing collections and decorators"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"},
{file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"},
@ -226,7 +217,6 @@ version = "2024.8.30"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"},
{file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"},
@ -238,7 +228,6 @@ version = "3.3.2"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7.0"
groups = ["main"]
files = [
{file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"},
{file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"},
@ -338,7 +327,6 @@ version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
groups = ["main"]
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
@ -350,7 +338,6 @@ version = "1.2.14"
description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
groups = ["main"]
files = [
{file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"},
{file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"},
@ -368,7 +355,6 @@ version = "2.1.0"
description = "A library to handle automated deprecations"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"},
{file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"},
@ -383,8 +369,6 @@ version = "1.2.2"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
groups = ["main"]
markers = "python_version < \"3.11\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
@ -399,7 +383,6 @@ version = "1.2.2"
description = "Dictionary with auto-expiring values for caching purposes"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "expiringdict-1.2.2-py3-none-any.whl", hash = "sha256:09a5d20bc361163e6432a874edd3179676e935eb81b925eccef48d409a8a45e8"},
{file = "expiringdict-1.2.2.tar.gz", hash = "sha256:300fb92a7e98f15b05cf9a856c1415b3bc4f2e132be07daa326da6414c23ee09"},
@ -414,7 +397,6 @@ version = "1.4.1"
description = "A list-like structure which implements collections.abc.MutableSequence"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"},
{file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"},
@ -501,7 +483,6 @@ version = "2.19.2"
description = "Google API client core library"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "google_api_core-2.19.2-py3-none-any.whl", hash = "sha256:53ec0258f2837dd53bbd3d3df50f5359281b3cc13f800c941dd15a9b5a415af4"},
{file = "google_api_core-2.19.2.tar.gz", hash = "sha256:ca07de7e8aa1c98a8bfca9321890ad2340ef7f2eb136e558cee68f24b94b0a8f"},
@ -533,7 +514,6 @@ version = "2.34.0"
description = "Google Authentication Library"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "google_auth-2.34.0-py2.py3-none-any.whl", hash = "sha256:72fd4733b80b6d777dcde515628a9eb4a577339437012874ea286bca7261ee65"},
{file = "google_auth-2.34.0.tar.gz", hash = "sha256:8eb87396435c19b20d32abd2f984e31c191a15284af72eb922f10e5bde9c04cc"},
@ -557,7 +537,6 @@ version = "1.4.5"
description = "Google Cloud Appengine Logging API client library"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "google_cloud_appengine_logging-1.4.5-py2.py3-none-any.whl", hash = "sha256:344e0244404049b42164e4d6dc718ca2c81b393d066956e7cb85fd9407ed9c48"},
{file = "google_cloud_appengine_logging-1.4.5.tar.gz", hash = "sha256:de7d766e5d67b19fc5833974b505b32d2a5bbdfb283fd941e320e7cfdae4cb83"},
@ -575,7 +554,6 @@ version = "0.3.0"
description = "Google Cloud Audit Protos"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "google_cloud_audit_log-0.3.0-py2.py3-none-any.whl", hash = "sha256:8340793120a1d5aa143605def8704ecdcead15106f754ef1381ae3bab533722f"},
{file = "google_cloud_audit_log-0.3.0.tar.gz", hash = "sha256:901428b257020d8c1d1133e0fa004164a555e5a395c7ca3cdbb8486513df3a65"},
@ -591,7 +569,6 @@ version = "2.4.1"
description = "Google Cloud API client core library"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"},
{file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"},
@ -610,7 +587,6 @@ version = "3.11.3"
description = "Stackdriver Logging API client library"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "google_cloud_logging-3.11.3-py2.py3-none-any.whl", hash = "sha256:b8ec23f2998f76a58f8492db26a0f4151dd500425c3f08448586b85972f3c494"},
{file = "google_cloud_logging-3.11.3.tar.gz", hash = "sha256:0a73cd94118875387d4535371d9e9426861edef8e44fba1261e86782d5b8d54f"},
@ -636,7 +612,6 @@ version = "1.65.0"
description = "Common protobufs used in Google APIs"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "googleapis_common_protos-1.65.0-py2.py3-none-any.whl", hash = "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63"},
{file = "googleapis_common_protos-1.65.0.tar.gz", hash = "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0"},
@ -655,7 +630,6 @@ version = "2.11.1"
description = "Python Client Library for Supabase Auth"
optional = false
python-versions = "<4.0,>=3.9"
groups = ["main"]
files = [
{file = "gotrue-2.11.1-py3-none-any.whl", hash = "sha256:1b2d915bdc65fd0ad608532759ce9c72fa2e910145c1e6901f2188519e7bcd2d"},
{file = "gotrue-2.11.1.tar.gz", hash = "sha256:5594ceee60bd873e5f4fdd028b08dece3906f6013b6ed08e7786b71c0092fed0"},
@ -671,7 +645,6 @@ version = "0.13.1"
description = "IAM API client library"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "grpc-google-iam-v1-0.13.1.tar.gz", hash = "sha256:3ff4b2fd9d990965e410965253c0da6f66205d5a8291c4c31c6ebecca18a9001"},
{file = "grpc_google_iam_v1-0.13.1-py2.py3-none-any.whl", hash = "sha256:c3e86151a981811f30d5e7330f271cee53e73bb87755e88cc3b6f0c7b5fe374e"},
@ -688,7 +661,6 @@ version = "1.66.1"
description = "HTTP/2-based RPC framework"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "grpcio-1.66.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:4877ba180591acdf127afe21ec1c7ff8a5ecf0fe2600f0d3c50e8c4a1cbc6492"},
{file = "grpcio-1.66.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3750c5a00bd644c75f4507f77a804d0189d97a107eb1481945a0cf3af3e7a5ac"},
@ -747,7 +719,6 @@ version = "1.66.1"
description = "Status proto mapping for gRPC"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "grpcio_status-1.66.1-py3-none-any.whl", hash = "sha256:cf9ed0b4a83adbe9297211c95cb5488b0cd065707e812145b842c85c4782ff02"},
{file = "grpcio_status-1.66.1.tar.gz", hash = "sha256:b3f7d34ccc46d83fea5261eea3786174459f763c31f6e34f1d24eba6d515d024"},
@ -764,7 +735,6 @@ version = "0.14.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
@ -776,7 +746,6 @@ version = "4.1.0"
description = "HTTP/2 State-Machine based protocol implementation"
optional = false
python-versions = ">=3.6.1"
groups = ["main"]
files = [
{file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"},
{file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"},
@ -792,7 +761,6 @@ version = "4.0.0"
description = "Pure-Python HPACK header compression"
optional = false
python-versions = ">=3.6.1"
groups = ["main"]
files = [
{file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"},
{file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"},
@ -804,7 +772,6 @@ version = "1.0.5"
description = "A minimal low-level HTTP client."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"},
{file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"},
@ -826,7 +793,6 @@ version = "0.27.2"
description = "The next generation HTTP client."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"},
{file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"},
@ -853,7 +819,6 @@ version = "6.0.1"
description = "HTTP/2 framing layer for Python"
optional = false
python-versions = ">=3.6.1"
groups = ["main"]
files = [
{file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"},
{file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"},
@ -865,7 +830,6 @@ version = "3.8"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"},
{file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"},
@ -877,7 +841,6 @@ version = "8.4.0"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"},
{file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"},
@ -897,7 +860,6 @@ version = "2.0.0"
description = "brain-dead simple config-ini parsing"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
@ -909,7 +871,6 @@ version = "6.1.0"
description = "multidict implementation"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"},
{file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"},
@ -1014,7 +975,6 @@ version = "1.27.0"
description = "OpenTelemetry Python API"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "opentelemetry_api-1.27.0-py3-none-any.whl", hash = "sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7"},
{file = "opentelemetry_api-1.27.0.tar.gz", hash = "sha256:ed673583eaa5f81b5ce5e86ef7cdaf622f88ef65f0b9aab40b843dcae5bef342"},
@ -1030,7 +990,6 @@ version = "24.1"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
@ -1042,7 +1001,6 @@ version = "1.5.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
@ -1058,7 +1016,6 @@ version = "0.19.1"
description = "PostgREST client for Python. This library provides an ORM interface to PostgREST."
optional = false
python-versions = "<4.0,>=3.9"
groups = ["main"]
files = [
{file = "postgrest-0.19.1-py3-none-any.whl", hash = "sha256:a8e7be4e1abc69fd8eee5a49d7dc3a76dfbffbd778beed0b2bd7accb3f4f3a2a"},
{file = "postgrest-0.19.1.tar.gz", hash = "sha256:d8fa88953cced4f45efa0f412056c364f64ece8a35b5b35f458a7e58c133fbca"},
@ -1076,7 +1033,6 @@ version = "1.24.0"
description = "Beautiful, Pythonic protocol buffers."
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "proto-plus-1.24.0.tar.gz", hash = "sha256:30b72a5ecafe4406b0d339db35b56c4059064e69227b8c3bda7462397f966445"},
{file = "proto_plus-1.24.0-py3-none-any.whl", hash = "sha256:402576830425e5f6ce4c2a6702400ac79897dab0b4343821aa5188b0fab81a12"},
@ -1094,7 +1050,6 @@ version = "5.28.0"
description = ""
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "protobuf-5.28.0-cp310-abi3-win32.whl", hash = "sha256:66c3edeedb774a3508ae70d87b3a19786445fe9a068dd3585e0cefa8a77b83d0"},
{file = "protobuf-5.28.0-cp310-abi3-win_amd64.whl", hash = "sha256:6d7cc9e60f976cf3e873acb9a40fed04afb5d224608ed5c1a105db4a3f09c5b6"},
@ -1115,7 +1070,6 @@ version = "0.6.1"
description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"},
{file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"},
@ -1127,7 +1081,6 @@ version = "0.4.1"
description = "A collection of ASN.1-based protocols modules"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"},
{file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"},
@ -1142,7 +1095,6 @@ version = "2.10.5"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"},
{file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"},
@ -1163,7 +1115,6 @@ version = "2.27.2"
description = "Core functionality for Pydantic validation and serialization"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"},
{file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"},
@ -1276,7 +1227,6 @@ version = "2.7.1"
description = "Settings management using Pydantic"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd"},
{file = "pydantic_settings-2.7.1.tar.gz", hash = "sha256:10c9caad35e64bfb3c2fbf70a078c0e25cc92499782e5200747f942a065dec93"},
@ -1297,7 +1247,6 @@ version = "2.10.1"
description = "JSON Web Token implementation in Python"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"},
{file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"},
@ -1315,7 +1264,6 @@ version = "8.3.3"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"},
{file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"},
@ -1338,7 +1286,6 @@ version = "0.25.2"
description = "Pytest support for asyncio"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075"},
{file = "pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f"},
@ -1357,7 +1304,6 @@ version = "3.14.0"
description = "Thin-wrapper around the mock package for easier use with pytest"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"},
{file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"},
@ -1375,7 +1321,6 @@ version = "2.9.0.post0"
description = "Extensions to the standard Python datetime module"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"]
files = [
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
@ -1390,7 +1335,6 @@ version = "1.0.1"
description = "Read key-value pairs from a .env file and set them as environment variables"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
{file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
@ -1405,7 +1349,6 @@ version = "2.0.2"
description = ""
optional = false
python-versions = "<4.0,>=3.9"
groups = ["main"]
files = [
{file = "realtime-2.0.2-py3-none-any.whl", hash = "sha256:2634c915bc38807f2013f21e8bcc4d2f79870dfd81460ddb9393883d0489928a"},
{file = "realtime-2.0.2.tar.gz", hash = "sha256:519da9325b3b8102139d51785013d592f6b2403d81fa21d838a0b0234723ed7d"},
@ -1423,7 +1366,6 @@ version = "5.2.1"
description = "Python client for Redis database and key-value store"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
{file = "redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"},
{file = "redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f"},
@ -1442,7 +1384,6 @@ version = "2.32.3"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
@ -1464,7 +1405,6 @@ version = "4.9"
description = "Pure-Python RSA implementation"
optional = false
python-versions = ">=3.6,<4"
groups = ["main"]
files = [
{file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"},
{file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"},
@ -1475,30 +1415,29 @@ pyasn1 = ">=0.1.3"
[[package]]
name = "ruff"
version = "0.9.2"
version = "0.9.3"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
groups = ["dev"]
files = [
{file = "ruff-0.9.2-py3-none-linux_armv6l.whl", hash = "sha256:80605a039ba1454d002b32139e4970becf84b5fee3a3c3bf1c2af6f61a784347"},
{file = "ruff-0.9.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b9aab82bb20afd5f596527045c01e6ae25a718ff1784cb92947bff1f83068b00"},
{file = "ruff-0.9.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fbd337bac1cfa96be615f6efcd4bc4d077edbc127ef30e2b8ba2a27e18c054d4"},
{file = "ruff-0.9.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b35259b0cbf8daa22a498018e300b9bb0174c2bbb7bcba593935158a78054d"},
{file = "ruff-0.9.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b6a9701d1e371bf41dca22015c3f89769da7576884d2add7317ec1ec8cb9c3c"},
{file = "ruff-0.9.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cc53e68b3c5ae41e8faf83a3b89f4a5d7b2cb666dff4b366bb86ed2a85b481f"},
{file = "ruff-0.9.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8efd9da7a1ee314b910da155ca7e8953094a7c10d0c0a39bfde3fcfd2a015684"},
{file = "ruff-0.9.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3292c5a22ea9a5f9a185e2d131dc7f98f8534a32fb6d2ee7b9944569239c648d"},
{file = "ruff-0.9.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a605fdcf6e8b2d39f9436d343d1f0ff70c365a1e681546de0104bef81ce88df"},
{file = "ruff-0.9.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c547f7f256aa366834829a08375c297fa63386cbe5f1459efaf174086b564247"},
{file = "ruff-0.9.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d18bba3d3353ed916e882521bc3e0af403949dbada344c20c16ea78f47af965e"},
{file = "ruff-0.9.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b338edc4610142355ccf6b87bd356729b62bf1bc152a2fad5b0c7dc04af77bfe"},
{file = "ruff-0.9.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:492a5e44ad9b22a0ea98cf72e40305cbdaf27fac0d927f8bc9e1df316dcc96eb"},
{file = "ruff-0.9.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:af1e9e9fe7b1f767264d26b1075ac4ad831c7db976911fa362d09b2d0356426a"},
{file = "ruff-0.9.2-py3-none-win32.whl", hash = "sha256:71cbe22e178c5da20e1514e1e01029c73dc09288a8028a5d3446e6bba87a5145"},
{file = "ruff-0.9.2-py3-none-win_amd64.whl", hash = "sha256:c5e1d6abc798419cf46eed03f54f2e0c3adb1ad4b801119dedf23fcaf69b55b5"},
{file = "ruff-0.9.2-py3-none-win_arm64.whl", hash = "sha256:a1b63fa24149918f8b37cef2ee6fff81f24f0d74b6f0bdc37bc3e1f2143e41c6"},
{file = "ruff-0.9.2.tar.gz", hash = "sha256:b5eceb334d55fae5f316f783437392642ae18e16dcf4f1858d55d3c2a0f8f5d0"},
{file = "ruff-0.9.3-py3-none-linux_armv6l.whl", hash = "sha256:7f39b879064c7d9670197d91124a75d118d00b0990586549949aae80cdc16624"},
{file = "ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a187171e7c09efa4b4cc30ee5d0d55a8d6c5311b3e1b74ac5cb96cc89bafc43c"},
{file = "ruff-0.9.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c59ab92f8e92d6725b7ded9d4a31be3ef42688a115c6d3da9457a5bda140e2b4"},
{file = "ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc153c25e715be41bb228bc651c1e9b1a88d5c6e5ed0194fa0dfea02b026439"},
{file = "ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646909a1e25e0dc28fbc529eab8eb7bb583079628e8cbe738192853dbbe43af5"},
{file = "ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a5a46e09355695fbdbb30ed9889d6cf1c61b77b700a9fafc21b41f097bfbba4"},
{file = "ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c4bb09d2bbb394e3730d0918c00276e79b2de70ec2a5231cd4ebb51a57df9ba1"},
{file = "ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96a87ec31dc1044d8c2da2ebbed1c456d9b561e7d087734336518181b26b3aa5"},
{file = "ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb7554aca6f842645022fe2d301c264e6925baa708b392867b7a62645304df4"},
{file = "ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cabc332b7075a914ecea912cd1f3d4370489c8018f2c945a30bcc934e3bc06a6"},
{file = "ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:33866c3cc2a575cbd546f2cd02bdd466fed65118e4365ee538a3deffd6fcb730"},
{file = "ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:006e5de2621304c8810bcd2ee101587712fa93b4f955ed0985907a36c427e0c2"},
{file = "ruff-0.9.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ba6eea4459dbd6b1be4e6bfc766079fb9b8dd2e5a35aff6baee4d9b1514ea519"},
{file = "ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:90230a6b8055ad47d3325e9ee8f8a9ae7e273078a66401ac66df68943ced029b"},
{file = "ruff-0.9.3-py3-none-win32.whl", hash = "sha256:eabe5eb2c19a42f4808c03b82bd313fc84d4e395133fb3fc1b1516170a31213c"},
{file = "ruff-0.9.3-py3-none-win_amd64.whl", hash = "sha256:040ceb7f20791dfa0e78b4230ee9dce23da3b64dd5848e40e3bf3ab76468dcf4"},
{file = "ruff-0.9.3-py3-none-win_arm64.whl", hash = "sha256:800d773f6d4d33b0a3c60e2c6ae8f4c202ea2de056365acfa519aa48acf28e0b"},
{file = "ruff-0.9.3.tar.gz", hash = "sha256:8293f89985a090ebc3ed1064df31f3b4b56320cdfcec8b60d3295bddb955c22a"},
]
[[package]]
@ -1507,7 +1446,6 @@ version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
groups = ["main"]
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
@ -1519,7 +1457,6 @@ version = "1.3.1"
description = "Sniff out which async library your code is running under"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
@ -1531,7 +1468,6 @@ version = "0.11.0"
description = "Supabase Storage client for Python."
optional = false
python-versions = "<4.0,>=3.9"
groups = ["main"]
files = [
{file = "storage3-0.11.0-py3-none-any.whl", hash = "sha256:de2d8f9c9103ca91a9a9d0d69d80b07a3ab6f647b93e023e6a1a97d3607b9728"},
{file = "storage3-0.11.0.tar.gz", hash = "sha256:243583f2180686c0f0a19e6117d8a9796fd60c0ca72ec567d62b75a5af0d57a1"},
@ -1547,7 +1483,6 @@ version = "0.4.15"
description = "An Enum that inherits from str."
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659"},
{file = "StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff"},
@ -1564,7 +1499,6 @@ version = "2.11.0"
description = "Supabase client for Python."
optional = false
python-versions = "<4.0,>=3.9"
groups = ["main"]
files = [
{file = "supabase-2.11.0-py3-none-any.whl", hash = "sha256:67a0da498895f4cd6554935e2854b4c41f87b297b78fb9c9414902a382041406"},
{file = "supabase-2.11.0.tar.gz", hash = "sha256:2a906f7909fd9a50f944cd9332ce66c684e2d37c0864284d34c5815e6c63cc01"},
@ -1584,7 +1518,6 @@ version = "0.9.2"
description = "Library for Supabase Functions"
optional = false
python-versions = "<4.0,>=3.9"
groups = ["main"]
files = [
{file = "supafunc-0.9.2-py3-none-any.whl", hash = "sha256:be5ee9f53842c4b0ba5f4abfb5bddf9f9e37e69e755ec0526852bb15af9d2ff5"},
{file = "supafunc-0.9.2.tar.gz", hash = "sha256:f5164114a3e65e7e552539f3f1050aa3d4970885abdd7405555c17fd216e2da1"},
@ -1600,8 +1533,6 @@ version = "2.1.0"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version < \"3.11\""
files = [
{file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"},
{file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"},
@ -1613,7 +1544,6 @@ version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
@ -1625,7 +1555,6 @@ version = "2.2.2"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"},
{file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"},
@ -1643,7 +1572,6 @@ version = "12.0"
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"},
{file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"},
@ -1725,7 +1653,6 @@ version = "1.16.0"
description = "Module for decorators, wrappers and monkey patching."
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"},
{file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"},
@ -1805,7 +1732,6 @@ version = "1.11.1"
description = "Yet another URL library"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "yarl-1.11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:400cd42185f92de559d29eeb529e71d80dfbd2f45c36844914a4a34297ca6f00"},
{file = "yarl-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8258c86f47e080a258993eed877d579c71da7bda26af86ce6c2d2d072c11320d"},
@ -1911,7 +1837,6 @@ version = "3.20.1"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "zipp-3.20.1-py3-none-any.whl", hash = "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064"},
{file = "zipp-3.20.1.tar.gz", hash = "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"},
@ -1926,6 +1851,6 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools",
type = ["pytest-mypy"]
[metadata]
lock-version = "2.1"
lock-version = "2.0"
python-versions = ">=3.10,<4.0"
content-hash = "53a31ce3d94999d9267f2a229c53a9d97d96c9413843bfdcb7ef0c0c21723e49"
content-hash = "62c4ef3f1ae73546a66783a2dc0672e664ce415a7b0514a7b92fc9fe1a23239e"

View File

@ -21,7 +21,7 @@ supabase = "^2.11.0"
[tool.poetry.group.dev.dependencies]
redis = "^5.2.1"
ruff = "^0.9.2"
ruff = "^0.9.3"
[build-system]
requires = ["poetry-core"]

View File

@ -252,3 +252,31 @@ class TextSplitBlock(Block):
if input_data.strip:
texts = [text.strip() for text in texts]
yield "texts", texts
class TextReplaceBlock(Block):
class Input(BlockSchema):
text: str = SchemaField(description="The text to replace.")
old: str = SchemaField(description="The old text to replace.")
new: str = SchemaField(description="The new text to replace with.")
class Output(BlockSchema):
output: str = SchemaField(description="The text with the replaced text.")
def __init__(self):
super().__init__(
id="7e7c87ab-3469-4bcc-9abe-67705091b713",
description="This block is used to replace a text with a new text.",
categories={BlockCategory.TEXT},
input_schema=TextReplaceBlock.Input,
output_schema=TextReplaceBlock.Output,
test_input=[
{"text": "Hello, World!", "old": "Hello", "new": "Hi"},
],
test_output=[
("output", "Hi, World!"),
],
)
def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "output", input_data.text.replace(input_data.old, input_data.new)

View File

@ -132,12 +132,14 @@ class UserCreditBase(ABC):
},
)
transaction_balance = (
transactions[0].get("_sum", {}).get("amount", 0) + snapshot_balance
int(transactions[0].get("_sum", {}).get("amount", 0) + snapshot_balance)
if transactions
else snapshot_balance
)
transaction_time = (
transactions[0].get("_max", {}).get("createdAt", datetime_min)
datetime.fromisoformat(
str(transactions[0].get("_max", {}).get("createdAt", datetime_min))
)
if transactions
else snapshot_time
)
@ -360,12 +362,21 @@ class UserCredit(UserCreditBase):
)
async def top_up_intent(self, user_id: str, amount: int) -> str:
if amount < 500 or amount % 100 != 0:
raise ValueError(
f"Top up amount must be at least 500 credits and multiple of 100 but is {amount}"
)
if not (user := await get_user_by_id(user_id)):
raise ValueError(f"User not found: {user_id}")
# Create checkout session
# https://docs.stripe.com/checkout/quickstart?client=react
# unit_amount param is always in the smallest currency unit (so cents for usd)
# which is equal to amount of credits
checkout_session = stripe.checkout.Session.create(
customer=await get_stripe_customer_id(user_id),
customer_email=user.email,
line_items=[
{
"price_data": {
@ -385,6 +396,7 @@ class UserCredit(UserCreditBase):
+ "/marketplace/credits?topup=success",
cancel_url=settings.config.platform_base_url
+ "/marketplace/credits?topup=cancel",
return_url=settings.config.platform_base_url + "/marketplace/credits",
)
await self._add_transaction(
@ -517,10 +529,10 @@ async def get_stripe_customer_id(user_id: str) -> str:
return customer.id
async def set_auto_top_up(user_id: str, threshold: int, amount: int):
async def set_auto_top_up(user_id: str, config: AutoTopUpConfig):
await User.prisma().update(
where={"id": user_id},
data={"topUpConfig": Json({"threshold": threshold, "amount": amount})},
data={"topUpConfig": Json(config.model_dump())},
)

View File

@ -59,5 +59,4 @@ class UpdatePermissionsRequest(pydantic.BaseModel):
class RequestTopUp(pydantic.BaseModel):
amount: int
"""Amount of credits to top up."""
credit_amount: int

View File

@ -151,7 +151,9 @@ async def get_user_credits(
async def request_top_up(
request: RequestTopUp, user_id: Annotated[str, Depends(get_user_id)]
):
checkout_url = await _user_credit_model.top_up_intent(user_id, request.amount)
checkout_url = await _user_credit_model.top_up_intent(
user_id, request.credit_amount
)
return {"checkout_url": checkout_url}
@ -183,7 +185,9 @@ async def configure_user_auto_top_up(
else:
await _user_credit_model.top_up_credits(user_id, 0)
await set_auto_top_up(user_id, threshold=request.threshold, amount=request.amount)
await set_auto_top_up(
user_id, AutoTopUpConfig(threshold=request.threshold, amount=request.amount)
)
return "Auto top-up settings updated"

View File

@ -173,14 +173,14 @@ files = [
[[package]]
name = "anthropic"
version = "0.40.0"
version = "0.45.2"
description = "The official Python library for the anthropic API"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "anthropic-0.40.0-py3-none-any.whl", hash = "sha256:442028ae8790ff9e3b6f8912043918755af1230d193904ae2ef78cc22995280c"},
{file = "anthropic-0.40.0.tar.gz", hash = "sha256:3efeca6d9e97813f93ed34322c6c7ea2279bf0824cd0aa71b59ce222665e2b87"},
{file = "anthropic-0.45.2-py3-none-any.whl", hash = "sha256:ecd746f7274451dfcb7e1180571ead624c7e1195d1d46cb7c70143d2aedb4d35"},
{file = "anthropic-0.45.2.tar.gz", hash = "sha256:32a18b9ecd12c91b2be4cae6ca2ab46a06937b5aa01b21308d97a6d29794fb5e"},
]
[package.dependencies]
@ -190,7 +190,7 @@ httpx = ">=0.23.0,<1"
jiter = ">=0.4.0,<1"
pydantic = ">=1.9.0,<3"
sniffio = "*"
typing-extensions = ">=4.7,<5"
typing-extensions = ">=4.10,<5"
[package.extras]
bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"]
@ -1015,14 +1015,14 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"]
[[package]]
name = "google-api-python-client"
version = "2.159.0"
version = "2.160.0"
description = "Google API Client Library for Python"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "google_api_python_client-2.159.0-py2.py3-none-any.whl", hash = "sha256:baef0bb631a60a0bd7c0bf12a5499e3a40cd4388484de7ee55c1950bf820a0cf"},
{file = "google_api_python_client-2.159.0.tar.gz", hash = "sha256:55197f430f25c907394b44fa078545ffef89d33fd4dca501b7db9f0d8e224bd6"},
{file = "google_api_python_client-2.160.0-py2.py3-none-any.whl", hash = "sha256:63d61fb3e4cf3fb31a70a87f45567c22f6dfe87bbfa27252317e3e2c42900db4"},
{file = "google_api_python_client-2.160.0.tar.gz", hash = "sha256:a8ccafaecfa42d15d5b5c3134ced8de08380019717fc9fb1ed510ca58eca3b7e"},
]
[package.dependencies]
@ -1393,14 +1393,14 @@ test = ["objgraph", "psutil"]
[[package]]
name = "groq"
version = "0.13.1"
version = "0.15.0"
description = "The official Python library for the groq API"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "groq-0.13.1-py3-none-any.whl", hash = "sha256:0c5d1d6df93de55de705fe73729b79baaa0c871f7575d6aa64b2962b56101b3e"},
{file = "groq-0.13.1.tar.gz", hash = "sha256:588fd5bee984f4eb46ec89552778d5698b9e9614435defef868645c19463cbcc"},
{file = "groq-0.15.0-py3-none-any.whl", hash = "sha256:c200558b67fee4b4f2bb89cc166337e3419a68c23280065770f8f8b0729c79ef"},
{file = "groq-0.15.0.tar.gz", hash = "sha256:9ad08ba6156c67d0975595a8515b517f22ff63158e063c55192e161ed3648af1"},
]
[package.dependencies]
@ -2151,14 +2151,14 @@ files = [
[[package]]
name = "mem0ai"
version = "0.1.44"
version = "0.1.48"
description = "Long-term memory for AI Agents"
optional = false
python-versions = "<4.0,>=3.9"
groups = ["main"]
files = [
{file = "mem0ai-0.1.44-py3-none-any.whl", hash = "sha256:32260a2cd935035a1b16ce04ad2e4510a5bd97618709466e2d06303e0eb8d9d4"},
{file = "mem0ai-0.1.44.tar.gz", hash = "sha256:93214272915d94f673d370bb8fe7a8bfc21806267e65700b471bec454dcdfa5c"},
{file = "mem0ai-0.1.48-py3-none-any.whl", hash = "sha256:23d1bd591c36da9e1f9f013d6f87a79ef9eb1495ac27b1e380af7f819b07fee0"},
{file = "mem0ai-0.1.48.tar.gz", hash = "sha256:f5cceb768fa2898e59d55d3d472ccb983e3d9ae82ccba1d435545e16853dbeb6"},
]
[package.dependencies]
@ -2439,14 +2439,14 @@ pydantic = ">=2.9.0,<3.0.0"
[[package]]
name = "openai"
version = "1.60.0"
version = "1.60.2"
description = "The official Python library for the openai API"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "openai-1.60.0-py3-none-any.whl", hash = "sha256:df06c43be8018274980ac363da07d4b417bd835ead1c66e14396f6f15a0d5dda"},
{file = "openai-1.60.0.tar.gz", hash = "sha256:7fa536cd4b644718645b874d2706e36dbbef38b327e42ca0623275da347ee1a9"},
{file = "openai-1.60.2-py3-none-any.whl", hash = "sha256:993bd11b96900b9098179c728026f016b4982ded7ee30dfcf4555eab1171fff9"},
{file = "openai-1.60.2.tar.gz", hash = "sha256:a8f843e10f2855713007f491d96afb2694b11b5e02cb97c7d01a0be60bc5bb51"},
]
[package.dependencies]
@ -3451,14 +3451,14 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments
[[package]]
name = "pytest-asyncio"
version = "0.25.2"
version = "0.25.3"
description = "Pytest support for asyncio"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075"},
{file = "pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f"},
{file = "pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3"},
{file = "pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a"},
]
[package.dependencies]
@ -3959,14 +3959,14 @@ files = [
[[package]]
name = "sentry-sdk"
version = "2.19.2"
version = "2.20.0"
description = "Python client for Sentry (https://sentry.io)"
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "sentry_sdk-2.19.2-py2.py3-none-any.whl", hash = "sha256:ebdc08228b4d131128e568d696c210d846e5b9d70aa0327dec6b1272d9d40b84"},
{file = "sentry_sdk-2.19.2.tar.gz", hash = "sha256:467df6e126ba242d39952375dd816fbee0f217d119bf454a8ce74cf1e7909e8d"},
{file = "sentry_sdk-2.20.0-py2.py3-none-any.whl", hash = "sha256:c359a1edf950eb5e80cffd7d9111f3dbeef57994cb4415df37d39fda2cf22364"},
{file = "sentry_sdk-2.20.0.tar.gz", hash = "sha256:afa82713a92facf847df3c6f63cec71eb488d826a50965def3d7722aa6f0fdab"},
]
[package.dependencies]
@ -4011,6 +4011,7 @@ sqlalchemy = ["sqlalchemy (>=1.2)"]
starlette = ["starlette (>=0.19.1)"]
starlite = ["starlite (>=1.48)"]
tornado = ["tornado (>=6)"]
unleash = ["UnleashClient (>=6.0.1)"]
[[package]]
name = "serpent"
@ -4229,14 +4230,14 @@ test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"]
[[package]]
name = "stripe"
version = "11.4.1"
version = "11.5.0"
description = "Python bindings for the Stripe API"
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "stripe-11.4.1-py2.py3-none-any.whl", hash = "sha256:8aa47a241de0355c383c916c4ef7273ab666f096a44ee7081e357db4a36f0cce"},
{file = "stripe-11.4.1.tar.gz", hash = "sha256:7ddd251b622d490fe57d78487855dc9f4d95b1bb113607e81fd377037a133d5a"},
{file = "stripe-11.5.0-py2.py3-none-any.whl", hash = "sha256:3b2cd47ed3002328249bff5cacaee38d5e756c3899ab425d3bd07acdaf32534a"},
{file = "stripe-11.5.0.tar.gz", hash = "sha256:bc3e0358ffc23d5ecfa8aafec1fa4f048ee8107c3237bcb00003e68c8c96fa02"},
]
[package.dependencies]
@ -4245,14 +4246,14 @@ typing-extensions = {version = ">=4.5.0", markers = "python_version >= \"3.7\""}
[[package]]
name = "supabase"
version = "2.11.0"
version = "2.12.0"
description = "Supabase client for Python."
optional = false
python-versions = "<4.0,>=3.9"
groups = ["main"]
files = [
{file = "supabase-2.11.0-py3-none-any.whl", hash = "sha256:67a0da498895f4cd6554935e2854b4c41f87b297b78fb9c9414902a382041406"},
{file = "supabase-2.11.0.tar.gz", hash = "sha256:2a906f7909fd9a50f944cd9332ce66c684e2d37c0864284d34c5815e6c63cc01"},
{file = "supabase-2.12.0-py3-none-any.whl", hash = "sha256:f8896f3314179fdf27f8bb8357947493ec32b98dcdac7114208aaf21cd59ce35"},
{file = "supabase-2.12.0.tar.gz", hash = "sha256:284612c3e94ff4ed2f18c985f5eba4d6e17b5e2bf16a9a24290bb83c9c217078"},
]
[package.dependencies]
@ -5034,4 +5035,4 @@ type = ["pytest-mypy"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.10,<3.13"
content-hash = "38a5c750ddca1a6264fd98b7ee74d199c2bbf57d3acc189264bd9f8ec90febc2"
content-hash = "7d37edf4fd4e1935811629fef29d463fa61f904d520aa497de2969fadeba92ec"

View File

@ -10,7 +10,7 @@ packages = [{ include = "backend", format = "sdist" }]
[tool.poetry.dependencies]
python = ">=3.10,<3.13"
aio-pika = "^9.5.4"
anthropic = "^0.40.0"
anthropic = "^0.45.2"
apscheduler = "^3.11.0"
autogpt-libs = { path = "../autogpt_libs", develop = true }
click = "^8.1.7"
@ -19,14 +19,14 @@ e2b-code-interpreter = "^1.0.1"
fastapi = "^0.115.5"
feedparser = "^6.0.11"
flake8 = "^7.0.0"
google-api-python-client = "^2.154.0"
google-api-python-client = "^2.160.0"
google-auth-oauthlib = "^1.2.1"
groq = "^0.13.1"
groq = "^0.15.0"
jinja2 = "^3.1.4"
jsonref = "^1.1.0"
jsonschema = "^4.22.0"
ollama = "^0.4.1"
openai = "^1.57.4"
openai = "^1.60.2"
praw = "~7.8.1"
prisma = "^0.15.0"
psutil = "^6.1.0"
@ -34,13 +34,13 @@ pydantic = "^2.9.2"
pydantic-settings = "^2.3.4"
pyro5 = "^5.15"
pytest = "^8.2.1"
pytest-asyncio = "^0.25.0"
pytest-asyncio = "^0.25.3"
python-dotenv = "^1.0.1"
redis = "^5.2.0"
sentry-sdk = "2.19.2"
sentry-sdk = "2.20.0"
strenum = "^0.4.9"
stripe = "^11.3.0"
supabase = "2.11.0"
stripe = "^11.5.0"
supabase = "2.12.0"
tenacity = "^9.0.0"
tweepy = "^4.14.0"
uvicorn = { extras = ["standard"], version = "^0.34.0" }
@ -55,7 +55,7 @@ sqlalchemy = "^2.0.36"
psycopg2-binary = "^2.9.10"
google-cloud-storage = "^2.18.2"
launchdarkly-server-sdk = "^9.8.0"
mem0ai = "^0.1.44"
mem0ai = "^0.1.48"
moviepy = "^2.1.2"
[tool.poetry.group.dev.dependencies]

View File

@ -92,17 +92,23 @@ async def test_block_credit_reset(server: SpinTestServer):
month2 = 2
# set the calendar to month 2 but use current time from now
user_credit.time_now = lambda: datetime.now(timezone.utc).replace(month=month2)
user_credit.time_now = lambda: datetime.now(timezone.utc).replace(
month=month2, day=1
)
month2credit = await user_credit.get_credits(DEFAULT_USER_ID)
# Month 1 result should only affect month 1
user_credit.time_now = lambda: datetime.now(timezone.utc).replace(month=month1)
user_credit.time_now = lambda: datetime.now(timezone.utc).replace(
month=month1, day=1
)
month1credit = await user_credit.get_credits(DEFAULT_USER_ID)
await top_up(100)
assert await user_credit.get_credits(DEFAULT_USER_ID) == month1credit + 100
# Month 2 balance is unaffected
user_credit.time_now = lambda: datetime.now(timezone.utc).replace(month=month2)
user_credit.time_now = lambda: datetime.now(timezone.utc).replace(
month=month2, day=1
)
assert await user_credit.get_credits(DEFAULT_USER_ID) == month2credit

View File

@ -1,18 +1,18 @@
import { withRoleAccess } from "@/lib/withRoleAccess";
import React from "react";
import { getReviewableAgents } from "@/components/admin/marketplace/actions";
import AdminMarketplaceAgentList from "@/components/admin/marketplace/AdminMarketplaceAgentList";
import AdminFeaturedAgentsControl from "@/components/admin/marketplace/AdminFeaturedAgentsControl";
// import { getReviewableAgents } from "@/components/admin/marketplace/actions";
// import AdminMarketplaceAgentList from "@/components/admin/marketplace/AdminMarketplaceAgentList";
// import AdminFeaturedAgentsControl from "@/components/admin/marketplace/AdminFeaturedAgentsControl";
import { Separator } from "@/components/ui/separator";
async function AdminMarketplace() {
const reviewableAgents = await getReviewableAgents();
// const reviewableAgents = await getReviewableAgents();
return (
<>
<AdminMarketplaceAgentList agents={reviewableAgents.items} />
<Separator className="my-4" />
<AdminFeaturedAgentsControl className="mt-4" />
{/* <AdminMarketplaceAgentList agents={reviewableAgents.items} />
<Separator className="my-4" />
<AdminFeaturedAgentsControl className="mt-4" /> */}
</>
);
}

View File

@ -179,6 +179,7 @@ export default function PrivatePage() {
{
oauth2: "OAuth2 credentials",
api_key: "API key",
user_password: "Username & password",
}[cred.type]
}{" "}
- <code>{cred.id}</code>

View File

@ -151,11 +151,7 @@ function SearchResults({
<div className="min-h-[500px] max-w-[1440px]">
{showAgents && agentsCount > 0 && (
<div className="mt-[36px]">
<AgentsSection
agents={agents}
sectionTitle="Agents"
className="font-[Large-Poppins] text-[18px] font-semibold leading-[28px]"
/>
<AgentsSection agents={agents} sectionTitle="Agents" />
</div>
)}

View File

@ -109,78 +109,80 @@ export default function ResetPasswordPage() {
}
return (
<AuthCard>
<AuthHeader>Reset Password</AuthHeader>
{user ? (
<form onSubmit={changePasswordForm.handleSubmit(onChangePassword)}>
<Form {...changePasswordForm}>
<FormField
control={changePasswordForm.control}
name="password"
render={({ field }) => (
<FormItem className="mb-6">
<FormLabel>Password</FormLabel>
<FormControl>
<PasswordInput {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={changePasswordForm.control}
name="confirmPassword"
render={({ field }) => (
<FormItem className="mb-6">
<FormLabel>Confirm Password</FormLabel>
<FormControl>
<PasswordInput {...field} />
</FormControl>
<FormDescription className="text-sm font-normal leading-tight text-slate-500">
Password needs to be at least 6 characters long
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<AuthButton
onClick={() => onChangePassword(changePasswordForm.getValues())}
isLoading={isLoading}
type="submit"
>
Update password
</AuthButton>
<AuthFeedback message={feedback} isError={isError} />
</Form>
</form>
) : (
<form onSubmit={sendEmailForm.handleSubmit(onSendEmail)}>
<Form {...sendEmailForm}>
<FormField
control={sendEmailForm.control}
name="email"
render={({ field }) => (
<FormItem className="mb-6">
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="m@example.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<AuthButton
onClick={() => onSendEmail(sendEmailForm.getValues())}
isLoading={isLoading}
disabled={disabled}
type="submit"
>
Send reset email
</AuthButton>
<AuthFeedback message={feedback} isError={isError} />
</Form>
</form>
)}
</AuthCard>
<div className="flex min-h-screen items-center justify-center">
<AuthCard>
<AuthHeader>Reset Password</AuthHeader>
{user ? (
<form onSubmit={changePasswordForm.handleSubmit(onChangePassword)}>
<Form {...changePasswordForm}>
<FormField
control={changePasswordForm.control}
name="password"
render={({ field }) => (
<FormItem className="mb-6">
<FormLabel>Password</FormLabel>
<FormControl>
<PasswordInput {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={changePasswordForm.control}
name="confirmPassword"
render={({ field }) => (
<FormItem className="mb-6">
<FormLabel>Confirm Password</FormLabel>
<FormControl>
<PasswordInput {...field} />
</FormControl>
<FormDescription className="text-sm font-normal leading-tight text-slate-500">
Password needs to be at least 6 characters long
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<AuthButton
onClick={() => onChangePassword(changePasswordForm.getValues())}
isLoading={isLoading}
type="submit"
>
Update password
</AuthButton>
<AuthFeedback message={feedback} isError={isError} />
</Form>
</form>
) : (
<form onSubmit={sendEmailForm.handleSubmit(onSendEmail)}>
<Form {...sendEmailForm}>
<FormField
control={sendEmailForm.control}
name="email"
render={({ field }) => (
<FormItem className="mb-6">
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="m@example.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<AuthButton
onClick={() => onSendEmail(sendEmailForm.getValues())}
isLoading={isLoading}
disabled={disabled}
type="submit"
>
Send reset email
</AuthButton>
<AuthFeedback message={feedback} isError={isError} />
</Form>
</form>
)}
</AuthCard>
</div>
);
}

View File

@ -250,7 +250,7 @@ const FlowEditor: React.FC<{
if (deletedNodeData) {
history.push({
type: "DELETE_NODE",
payload: { node: deletedNodeData },
payload: { node: deletedNodeData.data },
undo: () => addNodes(deletedNodeData),
redo: () => deleteElements({ nodes: [{ id: nodeID }] }),
});
@ -660,7 +660,7 @@ const FlowEditor: React.FC<{
onNodeDragStop={onNodeDragEnd}
onNodeDragStart={onNodeDragStart}
deleteKeyCode={["Backspace", "Delete"]}
minZoom={0.2}
minZoom={0.1}
maxZoom={2}
className="dark:bg-slate-900"
>

View File

@ -9,6 +9,7 @@ import RunnerOutputUI from "./runner-ui/RunnerOutputUI";
import { Node } from "@xyflow/react";
import { filterBlocksByType } from "@/lib/utils";
import { BlockIORootSchema, BlockUIType } from "@/lib/autogpt-server-api/types";
import { CustomNode } from "./CustomNode";
interface HardcodedValues {
name: any;
@ -27,7 +28,7 @@ export interface InputItem {
interface RunnerUIWrapperProps {
nodes: Node[];
setNodes: React.Dispatch<React.SetStateAction<Node[]>>;
setNodes: React.Dispatch<React.SetStateAction<CustomNode[]>>;
setIsScheduling: React.Dispatch<React.SetStateAction<boolean>>;
isRunning: boolean;
isScheduling: boolean;

View File

@ -10,7 +10,6 @@ const meta = {
},
tags: ["autodocs"],
argTypes: {
onRunAgent: { action: "run agent clicked" },
name: { control: "text" },
creator: { control: "text" },
shortDescription: { control: "text" },
@ -28,8 +27,8 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
onRunAgent: () => console.log("Run agent clicked"),
name: "AI Video Generator",
storeListingVersionId: "123",
creator: "Toran Richards",
shortDescription:
"Transform ideas into breathtaking images with this AI-powered Image Generator.",

View File

@ -15,40 +15,64 @@ type Story = StoryObj<typeof AgentTable>;
const sampleAgents: AgentTableRowProps[] = [
{
id: "agent-1",
id: 43,
agentName: "Super Coder",
description: "An AI agent that writes clean, efficient code",
imageSrc:
imageSrc: [
"https://ddz4ak4pa3d19.cloudfront.net/cache/53/b2/53b2bc7d7900f0e1e60bf64ebf38032d.jpg",
],
dateSubmitted: "2023-05-15",
status: "approved",
runs: 1500,
rating: 4.8,
onEdit: () => console.log("Edit Super Coder"),
agent_id: "43",
agent_version: 1,
sub_heading: "Super Coder",
date_submitted: "2023-05-15",
onEditSubmission: () => console.log("Edit Super Coder"),
onDeleteSubmission: () => console.log("Delete Super Coder"),
selectedAgents: new Set(),
setSelectedAgents: () => {},
},
{
id: "agent-2",
id: 44,
agentName: "Data Analyzer",
description: "Processes and analyzes large datasets with ease",
imageSrc:
imageSrc: [
"https://ddz4ak4pa3d19.cloudfront.net/cache/40/f7/40f7bc97c952f8df0f9c88d29defe8d4.jpg",
],
dateSubmitted: "2023-05-10",
status: "awaiting_review",
runs: 1200,
rating: 4.5,
onEdit: () => console.log("Edit Data Analyzer"),
agent_id: "44",
agent_version: 1,
sub_heading: "Data Analyzer",
date_submitted: "2023-05-10",
onEditSubmission: () => console.log("Edit Data Analyzer"),
onDeleteSubmission: () => console.log("Delete Data Analyzer"),
selectedAgents: new Set(),
setSelectedAgents: () => {},
},
{
id: "agent-3",
id: 45,
agentName: "UI Designer",
description: "Creates beautiful and intuitive user interfaces",
imageSrc:
imageSrc: [
"https://ddz4ak4pa3d19.cloudfront.net/cache/14/9e/149ebb9014aa8c0097e72ed89845af0e.jpg",
],
dateSubmitted: "2023-05-05",
status: "draft",
runs: 800,
rating: 4.2,
onEdit: () => console.log("Edit UI Designer"),
agent_id: "45",
agent_version: 1,
sub_heading: "UI Designer",
date_submitted: "2023-05-05",
onEditSubmission: () => console.log("Edit UI Designer"),
onDeleteSubmission: () => console.log("Delete UI Designer"),
selectedAgents: new Set(),
setSelectedAgents: () => {},
},
];

View File

@ -16,13 +16,13 @@ export const Default: Story = {
args: {
agentName: "Super Coder",
description: "An AI agent that writes clean, efficient code",
imageSrc:
imageSrc: [
"https://ddz4ak4pa3d19.cloudfront.net/cache/53/b2/53b2bc7d7900f0e1e60bf64ebf38032d.jpg",
],
dateSubmitted: "2023-05-15",
status: "ACTIVE" as StatusType,
runs: 1500,
rating: 4.8,
onEdit: () => console.log("Edit Super Coder"),
},
};

View File

@ -4,6 +4,7 @@ import * as React from "react";
import Image from "next/image";
import { IconStarFilled, IconMore } from "@/components/ui/icons";
import { Status, StatusType } from "./Status";
import { StoreSubmissionRequest } from "@/lib/autogpt-server-api";
export interface AgentTableCardProps {
agent_id: string;

View File

@ -11,7 +11,6 @@ const meta = {
tags: ["autodocs"],
argTypes: {
title: { control: "text" },
heading: { control: "text" },
description: { control: "text" },
buttonText: { control: "text" },
onButtonClick: { action: "buttonClicked" },
@ -24,7 +23,6 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
title: "Want to contribute?",
heading: "We're always looking for more Creators!",
description: "Join our ever-growing community of hackers and tinkerers",
buttonText: "Become a Creator",
onButtonClick: () => console.log("Button clicked"),
@ -34,7 +32,6 @@ export const Default: Story = {
export const CustomText: Story = {
args: {
title: "Become a Creator Today!",
heading: "Join Our Creator Community",
description: "Share your ideas and build amazing AI agents with us",
buttonText: "Start Creating",
onButtonClick: () => console.log("Custom button clicked"),

View File

@ -15,7 +15,6 @@ const meta = {
bio: { control: "text" },
agentsUploaded: { control: "number" },
onClick: { action: "clicked" },
avatarSrc: { control: "text" },
},
} satisfies Meta<typeof CreatorCard>;
@ -24,49 +23,49 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
index: 0,
creatorName: "John Doe",
creatorImage:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
bio: "AI enthusiast and developer with a passion for creating innovative agents.",
agentsUploaded: 15,
onClick: () => console.log("Default CreatorCard clicked"),
avatarSrc: "https://github.com/shadcn.png",
},
};
export const NewCreator: Story = {
args: {
index: 1,
creatorName: "Jane Smith",
creatorImage:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
bio: "Excited to start my journey in AI agent development!",
agentsUploaded: 1,
onClick: () => console.log("NewCreator CreatorCard clicked"),
avatarSrc: "https://example.com/avatar2.jpg",
},
};
export const ExperiencedCreator: Story = {
args: {
index: 2,
creatorName: "Alex Johnson",
creatorImage:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
bio: "Veteran AI researcher with a focus on natural language processing and machine learning.",
agentsUploaded: 50,
onClick: () => console.log("ExperiencedCreator CreatorCard clicked"),
avatarSrc: "https://example.com/avatar3.jpg",
},
};
export const WithInteraction: Story = {
args: {
index: 3,
creatorName: "Sam Brown",
creatorImage:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
bio: "Exploring the frontiers of AI and its applications in everyday life.",
agentsUploaded: 30,
onClick: () => console.log("WithInteraction CreatorCard clicked"),
avatarSrc: "https://example.com/avatar4.jpg",
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

View File

@ -21,51 +21,48 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
links: {
website: "https://example.com",
linkedin: "https://linkedin.com/in/johndoe",
github: "https://github.com/johndoe",
other: ["https://twitter.com/johndoe", "https://medium.com/@johndoe"],
},
links: [
"https://example.com",
"https://linkedin.com/in/johndoe",
"https://github.com/johndoe",
"https://twitter.com/johndoe",
"https://medium.com/@johndoe",
],
},
};
export const WebsiteOnly: Story = {
args: {
links: {
website: "https://example.com",
},
links: ["https://example.com"],
},
};
export const SocialLinks: Story = {
args: {
links: {
linkedin: "https://linkedin.com/in/janedoe",
github: "https://github.com/janedoe",
other: ["https://twitter.com/janedoe"],
},
links: [
"https://linkedin.com/in/janedoe",
"https://github.com/janedoe",
"https://twitter.com/janedoe",
],
},
};
export const NoLinks: Story = {
args: {
links: {},
links: [],
},
};
export const MultipleOtherLinks: Story = {
args: {
links: {
website: "https://example.com",
linkedin: "https://linkedin.com/in/creator",
github: "https://github.com/creator",
other: [
"https://twitter.com/creator",
"https://medium.com/@creator",
"https://youtube.com/@creator",
"https://tiktok.com/@creator",
],
},
links: [
"https://example.com",
"https://linkedin.com/in/creator",
"https://github.com/creator",
"https://twitter.com/creator",
"https://medium.com/@creator",
"https://youtube.com/@creator",
"https://tiktok.com/@creator",
],
},
};

View File

@ -43,6 +43,7 @@ export const Default: Story = {
runs: 50000,
rating: 4.7,
onClick: () => console.log("Card clicked"),
backgroundColor: "bg-white",
},
};
@ -60,6 +61,7 @@ export const LowRating: Story = {
runs: 10000,
rating: 2.8,
onClick: () => console.log("Card clicked"),
backgroundColor: "bg-white",
},
};
@ -77,6 +79,7 @@ export const HighRuns: Story = {
runs: 1000000,
rating: 4.9,
onClick: () => console.log("Card clicked"),
backgroundColor: "bg-white",
},
};
@ -92,6 +95,7 @@ export const NoCreatorImage: Story = {
runs: 75000,
rating: 4.5,
onClick: () => console.log("Card clicked"),
backgroundColor: "bg-white",
},
};
@ -108,6 +112,7 @@ export const ShortDescription: Story = {
runs: 50000,
rating: 4.2,
onClick: () => console.log("Card clicked"),
backgroundColor: "bg-white",
},
};
@ -125,6 +130,7 @@ export const WithInteraction: Story = {
runs: 200000,
rating: 4.6,
onClick: () => console.log("Card clicked"),
backgroundColor: "bg-white",
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

View File

@ -13,7 +13,6 @@ const meta = {
argTypes: {
userName: { control: "text" },
userEmail: { control: "text" },
activeLink: { control: "text" },
avatarSrc: { control: "text" },
menuItemGroups: { control: "object" },
},
@ -67,7 +66,6 @@ export const Default: Story = {
args: {
userName: "John Doe",
userEmail: "john.doe@example.com",
activeLink: "/marketplace",
avatarSrc: "https://avatars.githubusercontent.com/u/123456789?v=4",
menuItemGroups: defaultMenuItemGroups,
},
@ -77,7 +75,6 @@ export const NoAvatar: Story = {
args: {
userName: "Jane Smith",
userEmail: "jane.smith@example.com",
activeLink: "/library",
menuItemGroups: defaultMenuItemGroups,
},
};
@ -86,7 +83,6 @@ export const LongUserName: Story = {
args: {
userName: "Alexander Bartholomew Christopherson III",
userEmail: "alexander@example.com",
activeLink: "/builder",
avatarSrc: "https://avatars.githubusercontent.com/u/987654321?v=4",
menuItemGroups: defaultMenuItemGroups,
},

View File

@ -1,9 +1,10 @@
import type { Meta, StoryObj } from "@storybook/react";
import Navbar from "./Navbar";
import { Navbar } from "./Navbar";
import { userEvent, within } from "@storybook/test";
import { IconType } from "../ui/icons";
import { ProfileDetails } from "@/lib/autogpt-server-api/types";
import { jest } from "@jest/globals";
// You can't import this here, jest is not available in storybook and will crash it
// import { jest } from "@jest/globals";
// Mock the API responses
const mockProfileData: ProfileDetails = {
@ -19,14 +20,14 @@ const mockCreditData = {
};
// Mock the API module
jest.mock("@/lib/autogpt-server-api", () => {
return function () {
return {
getStoreProfile: () => Promise.resolve(mockProfileData),
getUserCredit: () => Promise.resolve(mockCreditData),
};
};
});
// jest.mock("@/lib/autogpt-server-api", () => {
// return function () {
// return {
// getStoreProfile: () => Promise.resolve(mockProfileData),
// getUserCredit: () => Promise.resolve(mockCreditData),
// };
// };
// });
const meta = {
title: "AGPT UI/Navbar",
@ -36,12 +37,12 @@ const meta = {
},
tags: ["autodocs"],
argTypes: {
isLoggedIn: { control: "boolean" },
avatarSrc: { control: "text" },
// isLoggedIn: { control: "boolean" },
// avatarSrc: { control: "text" },
links: { control: "object" },
activeLink: { control: "text" },
// activeLink: { control: "text" },
menuItemGroups: { control: "object" },
params: { control: { type: "object", defaultValue: { lang: "en" } } },
// params: { control: { type: "object", defaultValue: { lang: "en" } } },
},
} satisfies Meta<typeof Navbar>;
@ -90,11 +91,11 @@ const defaultLinks = [
export const Default: Story = {
args: {
params: { lang: "en" },
isLoggedIn: true,
// params: { lang: "en" },
// isLoggedIn: true,
links: defaultLinks,
activeLink: "/marketplace",
avatarSrc: mockProfileData.avatar_url,
// activeLink: "/marketplace",
// avatarSrc: mockProfileData.avatar_url,
menuItemGroups: defaultMenuItemGroups,
},
};
@ -102,21 +103,21 @@ export const Default: Story = {
export const WithActiveLink: Story = {
args: {
...Default.args,
activeLink: "/library",
// activeLink: "/library",
},
};
export const LongUserName: Story = {
args: {
...Default.args,
avatarSrc: "https://avatars.githubusercontent.com/u/987654321?v=4",
// avatarSrc: "https://avatars.githubusercontent.com/u/987654321?v=4",
},
};
export const NoAvatar: Story = {
args: {
...Default.args,
avatarSrc: undefined,
// avatarSrc: undefined,
},
};
@ -138,8 +139,8 @@ export const WithInteraction: Story = {
export const NotLoggedIn: Story = {
args: {
...Default.args,
isLoggedIn: false,
avatarSrc: undefined,
// isLoggedIn: false,
// avatarSrc: undefined,
},
};

View File

@ -63,12 +63,7 @@ export const Navbar = async ({ links, menuItemGroups }: NavbarProps) => {
<IconAutoGPTLogo className="h-full w-full" />
</div>
{links.map((link) => (
<NavbarLink
key={link.name}
name={link.name}
href={link.href}
className="font-poppins text-[20px] leading-[28px]"
/>
<NavbarLink key={link.name} name={link.name} href={link.href} />
))}
</div>
{/* Profile section */}

View File

@ -20,7 +20,11 @@ export const NavbarLink = ({ name, href }: NavbarLinkProps) => {
const activeLink = "/" + (parts.length > 2 ? parts[2] : parts[1]);
return (
<Link href={href} data-testid={`navbar-link-${name.toLowerCase()}`}>
<Link
href={href}
data-testid={`navbar-link-${name.toLowerCase()}`}
className="font-poppins text-[20px] leading-[28px]"
>
<div
className={`h-[48px] px-5 py-4 ${
activeLink === href

View File

@ -9,29 +9,33 @@ const meta: Meta<typeof ProfileInfoForm> = {
},
tags: ["autodocs"],
argTypes: {
displayName: {
control: "text",
description: "The display name of the user",
},
handle: {
control: "text",
description: "The user's handle/username",
},
bio: {
control: "text",
description: "User's biography text",
},
profileImage: {
control: "text",
description: "URL of the user's profile image",
},
links: {
profile: {
control: "object",
description: "Array of social media links",
},
categories: {
control: "object",
description: "Array of selected categories",
description: "The profile details of the user",
displayName: {
control: "text",
description: "The display name of the user",
},
handle: {
control: "text",
description: "The user's handle/username",
},
bio: {
control: "text",
description: "User's biography text",
},
profileImage: {
control: "text",
description: "URL of the user's profile image",
},
links: {
control: "object",
description: "Array of social media links",
},
categories: {
control: "object",
description: "Array of selected categories",
},
},
},
};
@ -41,30 +45,35 @@ type Story = StoryObj<typeof ProfileInfoForm>;
export const Empty: Story = {
args: {
displayName: "",
handle: "",
bio: "",
profileImage: undefined,
links: [],
categories: [],
profile: {
name: "",
username: "",
description: "",
avatar_url: "",
links: [],
top_categories: [],
agent_rating: 0,
agent_runs: 0,
},
},
};
export const Filled: Story = {
args: {
displayName: "Olivia Grace",
handle: "@ograce1421",
bio: "Our agents are designed to bring happiness and positive vibes to your daily routine. Each template helps you create and live more efficiently.",
profileImage: "https://via.placeholder.com/130x130",
links: [
{ id: 1, url: "www.websitelink.com" },
{ id: 2, url: "twitter.com/oliviagrace" },
{ id: 3, url: "github.com/ograce" },
],
categories: [
{ id: 1, name: "Entertainment" },
{ id: 2, name: "Blog" },
{ id: 3, name: "Content creation" },
],
profile: {
name: "Olivia Grace",
username: "@ograce1421",
description:
"Our agents are designed to bring happiness and positive vibes to your daily routine. Each template helps you create and live more efficiently.",
avatar_url: "https://via.placeholder.com/130x130",
links: [
"www.websitelink.com",
"twitter.com/oliviagrace",
"github.com/ograce",
],
top_categories: ["Entertainment", "Blog", "Content creation"],
agent_rating: 4.5,
agent_runs: 100,
},
},
};

View File

@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react";
import { PublishAgentSelect } from "./PublishAgentSelect";
import { Agent, PublishAgentSelect } from "./PublishAgentSelect";
const meta: Meta<typeof PublishAgentSelect> = {
title: "AGPT UI/Publish Agent Select",
@ -10,51 +10,69 @@ const meta: Meta<typeof PublishAgentSelect> = {
export default meta;
type Story = StoryObj<typeof PublishAgentSelect>;
const mockAgents = [
const mockAgents: Agent[] = [
{
name: "SEO Optimizer",
lastEdited: "2 days ago",
imageSrc: "https://picsum.photos/seed/seo/300/200",
id: "1",
version: 1,
},
{
name: "Content Writer",
lastEdited: "5 days ago",
imageSrc: "https://picsum.photos/seed/writer/300/200",
id: "1",
version: 1,
},
{
name: "Data Analyzer",
lastEdited: "1 week ago",
imageSrc: "https://picsum.photos/seed/data/300/200",
id: "1",
version: 1,
},
{
name: "Image Recognition",
lastEdited: "2 weeks ago",
imageSrc: "https://picsum.photos/seed/image/300/200",
id: "1",
version: 1,
},
{
name: "Chatbot Assistant",
lastEdited: "3 weeks ago",
imageSrc: "https://picsum.photos/seed/chat/300/200",
id: "1",
version: 1,
},
{
name: "Code Generator",
lastEdited: "1 month ago",
imageSrc: "https://picsum.photos/seed/code/300/200",
id: "1",
version: 1,
},
{
name: "AI Translator",
lastEdited: "6 weeks ago",
imageSrc: "https://picsum.photos/seed/translate/300/200",
id: "1",
version: 1,
},
{
name: "Voice Assistant",
lastEdited: "2 months ago",
imageSrc: "https://picsum.photos/seed/voice/300/200",
id: "1",
version: 1,
},
{
name: "Data Visualizer",
lastEdited: "3 months ago",
imageSrc: "https://picsum.photos/seed/visualize/300/200",
id: "1",
version: 1,
},
];

View File

@ -29,6 +29,8 @@ export const Filled: Story = {
args: {
...Default.args,
initialData: {
agent_id: "1",
slug: "super-seo-optimizer",
title: "Super SEO Optimizer",
subheader: "Boost your website's search engine rankings",
thumbnailSrc: "https://picsum.photos/seed/seo/500/350",
@ -44,6 +46,8 @@ export const ThreeImages: Story = {
args: {
...Default.args,
initialData: {
agent_id: "1",
slug: "super-seo-optimizer",
title: "Multi-Image Agent",
subheader: "Showcasing multiple images",
thumbnailSrc: "https://picsum.photos/seed/initial/500/350",
@ -63,6 +67,8 @@ export const SixImages: Story = {
args: {
...Default.args,
initialData: {
agent_id: "1",
slug: "super-seo-optimizer",
title: "Gallery Agent",
subheader: "Showcasing a gallery of images",
thumbnailSrc: "https://picsum.photos/seed/gallery1/500/350",

View File

@ -6,6 +6,18 @@ import { Button } from "../agptui/Button";
import { IconClose, IconPlus } from "../ui/icons";
import BackendAPI from "@/lib/autogpt-server-api";
export interface PublishAgentInfoInitialData {
agent_id: string;
title: string;
subheader: string;
slug: string;
thumbnailSrc: string;
youtubeLink: string;
category: string;
description: string;
additionalImages?: string[];
}
interface PublishAgentInfoProps {
onBack: () => void;
onSubmit: (
@ -18,17 +30,7 @@ interface PublishAgentInfoProps {
categories: string[],
) => void;
onClose: () => void;
initialData?: {
agent_id: string;
title: string;
subheader: string;
slug: string;
thumbnailSrc: string;
youtubeLink: string;
category: string;
description: string;
additionalImages?: string[];
};
initialData?: PublishAgentInfoInitialData;
}
export const PublishAgentInfo: React.FC<PublishAgentInfoProps> = ({

View File

@ -16,29 +16,32 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
agentName: "Test Agent",
onSubmit: (rating) => {
console.log("Rating submitted:", rating);
},
onClose: () => {
console.log("Rating card closed");
},
// onSubmit: (rating) => {
// console.log("Rating submitted:", rating);
// },
// onClose: () => {
// console.log("Rating card closed");
// },
storeListingVersionId: "1",
},
};
export const LongAgentName: Story = {
args: {
agentName: "Very Long Agent Name That Might Need Special Handling",
onSubmit: (rating) => {
console.log("Rating submitted:", rating);
},
onClose: () => {
console.log("Rating card closed");
},
// onSubmit: (rating) => {
// console.log("Rating submitted:", rating);
// },
// onClose: () => {
// console.log("Rating card closed");
// },
storeListingVersionId: "1",
},
};
export const WithoutCallbacks: Story = {
args: {
agentName: "Test Agent",
storeListingVersionId: "1",
},
};

View File

@ -44,6 +44,9 @@ export const Rejected: Story = {
};
export const AllStatuses: Story = {
args: {
status: "draft" as StatusType,
},
render: () => (
<div className="flex flex-col gap-4">
<Status status="draft" />

View File

@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react";
import { AgentsSection } from "./AgentsSection";
import { Agent, AgentsSection } from "./AgentsSection";
import { userEvent, within, expect } from "@storybook/test";
const meta = {
@ -16,7 +16,7 @@ const meta = {
argTypes: {
sectionTitle: { control: "text" },
agents: { control: "object" },
onCardClick: { action: "clicked" },
// onCardClick: { action: "clicked" },
},
} satisfies Meta<typeof AgentsSection>;
@ -25,41 +25,50 @@ type Story = StoryObj<typeof meta>;
const mockTopAgents = [
{
agentName: "SEO Optimizer Pro",
agentImage:
agent_name: "SEO Optimizer Pro",
agent_image:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
description:
"Boost your website's search engine rankings with our advanced AI-powered SEO optimization tool.",
runs: 50000,
rating: 4.7,
avatarSrc: "https://example.com/avatar1.jpg",
creator_avatar: "https://example.com/avatar1.jpg",
slug: "seo-optimizer-pro",
creator: "John Doe",
sub_heading: "SEO Expert",
},
{
agentName: "Content Writer AI",
agentImage:
agent_name: "Content Writer AI",
agent_image:
"https://upload.wikimedia.org/wikipedia/commons/c/c5/Big_buck_bunny_poster_big.jpg",
description:
"Generate high-quality, engaging content for your blog, social media, or marketing campaigns.",
runs: 75000,
rating: 4.5,
avatarSrc: "https://example.com/avatar2.jpg",
creator_avatar: "https://example.com/avatar2.jpg",
slug: "content-writer-ai",
creator: "Jane Doe",
sub_heading: "Content Writer",
},
{
agentName: "Data Analyzer Lite",
agentImage:
agent_name: "Data Analyzer Lite",
agent_image:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
description: "A basic tool for analyzing small to medium-sized datasets.",
runs: 10000,
rating: 3.8,
avatarSrc: "https://example.com/avatar3.jpg",
creator_avatar: "https://example.com/avatar3.jpg",
slug: "data-analyzer-lite",
creator: "John Doe",
sub_heading: "Data Analyst",
},
];
] satisfies Agent[];
export const Default: Story = {
args: {
sectionTitle: "Top Agents",
agents: mockTopAgents,
onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
// onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
},
};
@ -67,7 +76,7 @@ export const SingleAgent: Story = {
args: {
sectionTitle: "Top Agents",
agents: [mockTopAgents[0]],
onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
// onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
},
};
@ -75,7 +84,7 @@ export const NoAgents: Story = {
args: {
sectionTitle: "Top Agents",
agents: [],
onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
// onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
},
};
@ -83,7 +92,7 @@ export const WithInteraction: Story = {
args: {
sectionTitle: "Top Agents",
agents: mockTopAgents,
onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
// onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
@ -107,6 +116,9 @@ export const MultiRowAgents: Story = {
runs: 60000,
rating: 4.6,
creator_avatar: "https://example.com/avatar4.jpg",
slug: "image-recognition-ai",
creator: "John Doe",
sub_heading: "Image Recognition",
},
{
agent_name: "Natural Language Processor",
@ -117,6 +129,9 @@ export const MultiRowAgents: Story = {
runs: 80000,
rating: 4.8,
creator_avatar: "https://example.com/avatar5.jpg",
slug: "natural-language-processor",
creator: "John Doe",
sub_heading: "Natural Language Processing",
},
{
agent_name: "Sentiment Analyzer",
@ -127,6 +142,9 @@ export const MultiRowAgents: Story = {
runs: 45000,
rating: 4.3,
creator_avatar: "https://example.com/avatar6.jpg",
slug: "sentiment-analyzer",
creator: "John Doe",
sub_heading: "Sentiment Analysis",
},
{
agent_name: "Chatbot Builder",
@ -137,6 +155,9 @@ export const MultiRowAgents: Story = {
runs: 55000,
rating: 4.4,
creator_avatar: "https://example.com/avatar7.jpg",
slug: "chatbot-builder",
creator: "John Doe",
sub_heading: "Chatbot Developer",
},
{
agent_name: "Predictive Analytics Tool",
@ -147,6 +168,9 @@ export const MultiRowAgents: Story = {
runs: 40000,
rating: 4.2,
creator_avatar: "https://example.com/avatar8.jpg",
slug: "predictive-analytics-tool",
creator: "John Doe",
sub_heading: "Predictive Analytics",
},
{
agent_name: "Text-to-Speech Converter",
@ -157,9 +181,12 @@ export const MultiRowAgents: Story = {
runs: 35000,
rating: 4.1,
creator_avatar: "https://example.com/avatar9.jpg",
slug: "text-to-speech-converter",
creator: "John Doe",
sub_heading: "Text-to-Speech",
},
],
onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
// onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
},
};

View File

@ -8,6 +8,7 @@ import {
CarouselItem,
} from "@/components/ui/carousel";
import { useRouter } from "next/navigation";
import { cn } from "@/lib/utils";
export interface Agent {
slug: string;

View File

@ -15,7 +15,7 @@ const meta = {
tags: ["autodocs"],
argTypes: {
featuredCreators: { control: "object" },
onCardClick: { action: "cardClicked" },
// onCardClick: { action: "cardClicked" },
},
} satisfies Meta<typeof FeaturedCreators>;
@ -64,14 +64,14 @@ const defaultCreators = [
export const Default: Story = {
args: {
featuredCreators: defaultCreators,
onCardClick: (creatorName) => console.log(`Clicked on ${creatorName}`),
// onCardClick: (creatorName) => console.log(`Clicked on ${creatorName}`),
},
};
export const SingleCreator: Story = {
args: {
featuredCreators: [defaultCreators[0]],
onCardClick: (creatorName) => console.log(`Clicked on ${creatorName}`),
// onCardClick: (creatorName) => console.log(`Clicked on ${creatorName}`),
},
};
@ -98,14 +98,14 @@ export const ManyCreators: Story = {
num_agents: 25,
},
],
onCardClick: (creatorName) => console.log(`Clicked on ${creatorName}`),
// onCardClick: (creatorName) => console.log(`Clicked on ${creatorName}`),
},
};
export const WithInteraction: Story = {
args: {
featuredCreators: defaultCreators,
onCardClick: (creatorName) => console.log(`Clicked on ${creatorName}`),
// onCardClick: (creatorName) => console.log(`Clicked on ${creatorName}`),
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

View File

@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react";
import { FeaturedSection } from "./FeaturedSection";
import { FeaturedAgent, FeaturedSection } from "./FeaturedSection";
import { userEvent, within, expect } from "@storybook/test";
const meta = {
@ -15,7 +15,7 @@ const meta = {
tags: ["autodocs"],
argTypes: {
featuredAgents: { control: "object" },
onCardClick: { action: "clicked" },
// onCardClick: { action: "clicked" },
},
} satisfies Meta<typeof FeaturedSection>;
@ -24,97 +24,102 @@ type Story = StoryObj<typeof meta>;
const mockFeaturedAgents = [
{
agentName: "Personalized Morning Coffee Newsletter example of three lines",
subHeading:
agent_name: "Personalized Morning Coffee Newsletter example of three lines",
sub_heading:
"Transform ideas into breathtaking images with this AI-powered Image Generator.",
creatorName: "AI Solutions Inc.",
creator: "AI Solutions Inc.",
description:
"Elevate your web content with this powerful AI Webpage Copy Improver. Designed for marketers, SEO specialists, and web developers, this tool analyses and enhances website copy for maximum impact. Using advanced language models, it optimizes text for better clarity, SEO performance, and increased conversion rates.",
runs: 50000,
rating: 4.7,
agentImage:
agent_image:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
creatorImage:
creator_avatar:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
slug: "personalized-morning-coffee-newsletter",
},
{
agentName: "Data Analyzer Lite",
subHeading: "Basic data analysis tool",
creatorName: "DataTech",
agent_name: "Data Analyzer Lite",
sub_heading: "Basic data analysis tool",
creator: "DataTech",
description:
"A lightweight data analysis tool for basic data processing needs.",
runs: 10000,
rating: 2.8,
agentImage:
agent_image:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
creatorImage:
creator_avatar:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
slug: "data-analyzer-lite",
},
{
agentName: "CodeAssist AI",
subHeading: "Your AI coding companion",
creatorName: "DevTools Co.",
agent_name: "CodeAssist AI",
sub_heading: "Your AI coding companion",
creator: "DevTools Co.",
description:
"An intelligent coding assistant that helps developers write better code faster.",
runs: 1000000,
rating: 4.9,
agentImage:
agent_image:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
creatorImage:
creator_avatar:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
slug: "codeassist-ai",
},
{
agentName: "MultiTasker",
subHeading: "All-in-one productivity suite",
creatorName: "Productivity Plus",
agent_name: "MultiTasker",
sub_heading: "All-in-one productivity suite",
creator: "Productivity Plus",
description:
"A comprehensive productivity suite that combines task management, note-taking, and project planning into one seamless interface. Features include smart task prioritization, automated scheduling, and AI-powered insights to help you work more efficiently.",
runs: 75000,
rating: 4.5,
agentImage:
agent_image:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
creatorImage:
creator_avatar:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
slug: "multitasker",
},
{
agentName: "QuickTask",
subHeading: "Fast task automation",
creatorName: "EfficientWorks",
agent_name: "QuickTask",
sub_heading: "Fast task automation",
creator: "EfficientWorks",
description: "Simple and efficient task automation tool.",
runs: 50000,
rating: 4.2,
agentImage:
agent_image:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
creatorImage:
creator_avatar:
"https://framerusercontent.com/images/KCIpxr9f97EGJgpaoqnjKsrOPwI.jpg",
slug: "quicktask",
},
];
] satisfies FeaturedAgent[];
export const Default: Story = {
args: {
featuredAgents: mockFeaturedAgents,
onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
// onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
},
};
export const SingleAgent: Story = {
args: {
featuredAgents: [mockFeaturedAgents[0]],
onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
// onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
},
};
export const NoAgents: Story = {
args: {
featuredAgents: [],
onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
// onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
},
};
export const WithInteraction: Story = {
args: {
featuredAgents: mockFeaturedAgents,
onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
// onCardClick: (agentName: string) => console.log(`Clicked on ${agentName}`),
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

View File

@ -8,7 +8,10 @@ import {
PopoverAnchor,
} from "@/components/ui/popover";
import { PublishAgentSelect } from "../PublishAgentSelect";
import { PublishAgentInfo } from "../PublishAgentSelectInfo";
import {
PublishAgentInfo,
PublishAgentInfoInitialData,
} from "../PublishAgentSelectInfo";
import { PublishAgentAwaitingReview } from "../PublishAgentAwaitingReview";
import { Button } from "../Button";
import {
@ -45,17 +48,17 @@ export const PublishAgentPopout: React.FC<PublishAgentPopoutProps> = ({
);
const [myAgents, setMyAgents] = React.useState<MyAgentsResponse | null>(null);
const [selectedAgent, setSelectedAgent] = React.useState<string | null>(null);
const [initialData, setInitialData] = React.useState<{
agent_id: string;
title: string;
subheader: string;
slug: string;
thumbnailSrc: string;
youtubeLink: string;
category: string;
description: string;
additionalImages?: string[];
} | null>(null);
const [initialData, setInitialData] =
React.useState<PublishAgentInfoInitialData>({
agent_id: "",
title: "",
subheader: "",
slug: "",
thumbnailSrc: "",
youtubeLink: "",
category: "",
description: "",
});
const [publishData, setPublishData] =
React.useState<StoreSubmissionRequest>(submissionData);
const [selectedAgentId, setSelectedAgentId] = React.useState<string | null>(

View File

@ -2,16 +2,14 @@ import { LDProvider } from "launchdarkly-react-client-sdk";
import { ReactNode } from "react";
export function LaunchDarklyProvider({ children }: { children: ReactNode }) {
if (
process.env.NEXT_PUBLIC_LAUNCHDARKLY_ENABLED === true &&
!process.env.NEXT_PUBLIC_LAUNCHDARKLY_CLIENT_ID
) {
const clientId = process.env.NEXT_PUBLIC_LAUNCHDARKLY_CLIENT_ID;
const enabled = process.env.NEXT_PUBLIC_LAUNCHDARKLY_ENABLED === "true";
if (!enabled) return <>{children}</>;
if (!clientId) {
throw new Error("NEXT_PUBLIC_LAUNCHDARKLY_CLIENT_ID is not defined");
}
return (
<LDProvider clientSideID={process.env.NEXT_PUBLIC_LAUNCHDARKLY_CLIENT_ID}>
{children}
</LDProvider>
);
return <LDProvider clientSideID={clientId}>{children}</LDProvider>;
}

View File

@ -41,7 +41,6 @@ import { LocalValuedInput } from "./ui/input";
import NodeHandle from "./NodeHandle";
import { ConnectionData } from "./CustomNode";
import { CredentialsInput } from "./integrations/credentials-input";
import { MultiSelect } from "./ui/multiselect-input";
type NodeObjectInputTreeProps = {
nodeId: string;
@ -663,20 +662,6 @@ export const NodeGenericInputField: FC<{
handleInputClick={handleInputClick}
/>
);
case "object":
return (
<NodeKeyValueInput
nodeId={nodeId}
selfKey={propKey}
schema={propSchema}
entries={currentValue}
errors={errors}
className={className}
displayName={displayName}
connections={connections}
handleInputChange={handleInputChange}
/>
);
default:
console.warn(
`Schema for '${propKey}' specifies unknown type:`,
@ -968,10 +953,8 @@ const NodeKeyValueInput: FC<{
>
<div>
{keyValuePairs.map(({ key, value }, index) => (
/*
The `index` is used as a DOM key instead of the actual `key`
because the `key` can change with each input, causing the input to lose focus.
*/
// The `index` is used as a DOM key instead of the actual `key`
// because the `key` can change with each input, causing the input to lose focus.
<div key={index}>
<NodeHandle
keyName={getEntryKey(key)}

View File

@ -1,6 +1,14 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { useForm } from "react-hook-form";
import {
FieldValues,
InternalFieldName,
RegisterOptions,
useForm,
UseFormHandleSubmit,
UseFormRegister,
UseFormWatch,
} from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
@ -72,10 +80,300 @@ const FormExample = () => {
};
export const Default: Story = {
args: {
children: <FormExample />,
// watch(callback: (data, { name, type }) => void, defaultValues?: {[key:string]: unknown}): { unsubscribe: () => void }
watch: (name?: any, defaultValue?: any) => {
if (typeof name === "function") {
return { unsubscribe: () => {} };
}
return defaultValue || {};
},
getValues: () => [],
getFieldState: (name, formState) => ({
invalid: false,
isDirty: false,
isTouched: false,
isValidating: false,
error: undefined,
}),
setError: () => {},
setValue: () => {},
trigger: async () => true,
reset: () => {},
clearErrors: () => {},
formState: {
errors: {},
isDirty: false,
isSubmitting: false,
isValid: true,
isLoading: false,
isSubmitted: false,
isSubmitSuccessful: false,
isValidating: false,
defaultValues: {},
dirtyFields: {},
touchedFields: {},
disabled: false,
submitCount: 0,
validatingFields: {},
},
resetField: () => {},
handleSubmit: (() => {
return async (e?: React.BaseSyntheticEvent) => {
e?.preventDefault();
return Promise.resolve();
};
}) as unknown as UseFormHandleSubmit<any>,
unregister: () => {},
control: {
_subjects: {
state: {
observers: [],
subscribe: () => ({ unsubscribe: () => {} }),
unsubscribe: () => {},
next: () => {},
},
array: {
observers: [],
subscribe: () => ({ unsubscribe: () => {} }),
unsubscribe: () => {},
next: () => {},
},
values: {
observers: [],
subscribe: () => ({ unsubscribe: () => {} }),
unsubscribe: () => {},
next: () => {},
},
},
_reset: () => {},
_resetDefaultValues: () => {},
_getFieldArray: () => [],
_setErrors: () => {},
_updateDisabledField: () => {},
_executeSchema: () => Promise.resolve({ errors: {} }),
handleSubmit: (onSubmit?: any) => (e?: React.BaseSyntheticEvent) => {
e?.preventDefault();
return Promise.resolve();
},
unregister: () => {},
getFieldState: () => ({
invalid: false,
isDirty: false,
isTouched: false,
isValidating: false,
error: undefined,
}),
setError: () => {},
_disableForm: () => {},
_removeUnmounted: () => {},
_names: {
mount: new Set(),
array: new Set(),
watch: new Set(),
unMount: new Set(),
disabled: new Set(),
},
_state: { mount: false, watch: false, action: false },
_options: { mode: "onSubmit", defaultValues: {} },
_formState: {
isDirty: false,
isSubmitted: false,
submitCount: 0,
isLoading: false,
isSubmitSuccessful: false,
isSubmitting: false,
isValidating: false,
isValid: true,
disabled: false,
dirtyFields: {},
touchedFields: {},
errors: {},
validatingFields: {},
},
_fields: {},
_defaultValues: {},
_formValues: {},
_proxyFormState: {
isDirty: false,
dirtyFields: false,
touchedFields: false,
errors: false,
isValid: true,
isValidating: false,
validatingFields: false,
},
_getDirty: () => false,
_updateValid: () => {},
_updateFieldArray: () => {},
_getWatch: () => ({}),
_updateFormState: () => {},
register: ((name: string, options?: RegisterOptions<any>) => ({
name,
onChange: (e: any) => Promise.resolve(),
onBlur: (e: any) => Promise.resolve(),
ref: () => {},
})) as unknown as UseFormRegister<any>,
},
register: ((name: string) => ({
name,
onChange: (e: any) => Promise.resolve(),
onBlur: (e: any) => Promise.resolve(),
ref: () => {},
})) as UseFormRegister<FieldValues>,
setFocus: () => {},
},
render: () => <FormExample />,
};
export const WithError: Story = {
args: {
children: <FormExample />,
// watch(callback: (data, { name, type }) => void, defaultValues?: {[key:string]: unknown}): { unsubscribe: () => void }
watch: (name?: any, defaultValue?: any) => {
if (typeof name === "function") {
return { unsubscribe: () => {} };
}
return defaultValue || {};
},
getValues: () => [],
getFieldState: (name, formState) => ({
invalid: false,
isDirty: false,
isTouched: false,
isValidating: false,
error: undefined,
}),
setError: () => {},
setValue: () => {},
trigger: async () => true,
reset: () => {},
clearErrors: () => {},
formState: {
errors: {},
isDirty: false,
isSubmitting: false,
isValid: true,
isLoading: false,
isSubmitted: false,
isSubmitSuccessful: false,
isValidating: false,
defaultValues: {},
dirtyFields: {},
touchedFields: {},
disabled: false,
submitCount: 0,
validatingFields: {},
},
resetField: () => {},
handleSubmit: (() => {
return async (e?: React.BaseSyntheticEvent) => {
e?.preventDefault();
return Promise.resolve();
};
}) as unknown as UseFormHandleSubmit<any>,
unregister: () => {},
control: {
_subjects: {
state: {
observers: [],
subscribe: () => ({ unsubscribe: () => {} }),
unsubscribe: () => {},
next: () => {},
},
array: {
observers: [],
subscribe: () => ({ unsubscribe: () => {} }),
unsubscribe: () => {},
next: () => {},
},
values: {
observers: [],
subscribe: () => ({ unsubscribe: () => {} }),
unsubscribe: () => {},
next: () => {},
},
},
_reset: () => {},
_resetDefaultValues: () => {},
_getFieldArray: () => [],
_setErrors: () => {},
_updateDisabledField: () => {},
_executeSchema: () => Promise.resolve({ errors: {} }),
handleSubmit: (onSubmit?: any) => (e?: React.BaseSyntheticEvent) => {
e?.preventDefault();
return Promise.resolve();
},
unregister: () => {},
getFieldState: () => ({
invalid: false,
isDirty: false,
isTouched: false,
isValidating: false,
error: undefined,
}),
setError: () => {},
_disableForm: () => {},
_removeUnmounted: () => {},
_names: {
mount: new Set(),
array: new Set(),
watch: new Set(),
unMount: new Set(),
disabled: new Set(),
},
_state: { mount: false, watch: false, action: false },
_options: { mode: "onSubmit", defaultValues: {} },
_formState: {
isDirty: false,
isSubmitted: false,
submitCount: 0,
isLoading: false,
isSubmitSuccessful: false,
isSubmitting: false,
isValidating: false,
isValid: true,
disabled: false,
dirtyFields: {},
touchedFields: {},
errors: {},
validatingFields: {},
},
_fields: {},
_defaultValues: {},
_formValues: {},
_proxyFormState: {
isDirty: false,
dirtyFields: false,
touchedFields: false,
errors: false,
isValid: true,
isValidating: false,
validatingFields: false,
},
_getDirty: () => false,
_updateValid: () => {},
_updateFieldArray: () => {},
_getWatch: () => ({}),
_updateFormState: () => {},
register: ((name: string, options?: RegisterOptions<any>) => ({
name,
onChange: (e: any) => Promise.resolve(),
onBlur: (e: any) => Promise.resolve(),
ref: () => {},
})) as unknown as UseFormRegister<any>,
},
register: ((name: string) => ({
name,
onChange: (e: any) => Promise.resolve(),
onBlur: (e: any) => Promise.resolve(),
ref: () => {},
})) as UseFormRegister<FieldValues>,
setFocus: () => {},
},
render: () => {
const FormWithError = () => {
const form = useForm<z.infer<typeof formSchema>>({
@ -126,6 +424,151 @@ export const WithError: Story = {
};
export const WithDefaultValue: Story = {
args: {
children: <FormExample />,
// watch(callback: (data, { name, type }) => void, defaultValues?: {[key:string]: unknown}): { unsubscribe: () => void }
watch: (name?: any, defaultValue?: any) => {
if (typeof name === "function") {
return { unsubscribe: () => {} };
}
return defaultValue || {};
},
getValues: () => [],
getFieldState: (name, formState) => ({
invalid: false,
isDirty: false,
isTouched: false,
isValidating: false,
error: undefined,
}),
setError: () => {},
setValue: () => {},
trigger: async () => true,
reset: () => {},
clearErrors: () => {},
formState: {
errors: {},
isDirty: false,
isSubmitting: false,
isValid: true,
isLoading: false,
isSubmitted: false,
isSubmitSuccessful: false,
isValidating: false,
defaultValues: {},
dirtyFields: {},
touchedFields: {},
disabled: false,
submitCount: 0,
validatingFields: {},
},
resetField: () => {},
handleSubmit: (() => {
return async (e?: React.BaseSyntheticEvent) => {
e?.preventDefault();
return Promise.resolve();
};
}) as unknown as UseFormHandleSubmit<any>,
unregister: () => {},
control: {
_subjects: {
state: {
observers: [],
subscribe: () => ({ unsubscribe: () => {} }),
unsubscribe: () => {},
next: () => {},
},
array: {
observers: [],
subscribe: () => ({ unsubscribe: () => {} }),
unsubscribe: () => {},
next: () => {},
},
values: {
observers: [],
subscribe: () => ({ unsubscribe: () => {} }),
unsubscribe: () => {},
next: () => {},
},
},
_reset: () => {},
_resetDefaultValues: () => {},
_getFieldArray: () => [],
_setErrors: () => {},
_updateDisabledField: () => {},
_executeSchema: () => Promise.resolve({ errors: {} }),
handleSubmit: (onSubmit?: any) => (e?: React.BaseSyntheticEvent) => {
e?.preventDefault();
return Promise.resolve();
},
unregister: () => {},
getFieldState: () => ({
invalid: false,
isDirty: false,
isTouched: false,
isValidating: false,
error: undefined,
}),
setError: () => {},
_disableForm: () => {},
_removeUnmounted: () => {},
_names: {
mount: new Set(),
array: new Set(),
watch: new Set(),
unMount: new Set(),
disabled: new Set(),
},
_state: { mount: false, watch: false, action: false },
_options: { mode: "onSubmit", defaultValues: {} },
_formState: {
isDirty: false,
isSubmitted: false,
submitCount: 0,
isLoading: false,
isSubmitSuccessful: false,
isSubmitting: false,
isValidating: false,
isValid: true,
disabled: false,
dirtyFields: {},
touchedFields: {},
errors: {},
validatingFields: {},
},
_fields: {},
_defaultValues: {},
_formValues: {},
_proxyFormState: {
isDirty: false,
dirtyFields: false,
touchedFields: false,
errors: false,
isValid: true,
isValidating: false,
validatingFields: false,
},
_getDirty: () => false,
_updateValid: () => {},
_updateFieldArray: () => {},
_getWatch: () => ({}),
_updateFormState: () => {},
register: ((name: string, options?: RegisterOptions<any>) => ({
name,
onChange: (e: any) => Promise.resolve(),
onBlur: (e: any) => Promise.resolve(),
ref: () => {},
})) as unknown as UseFormRegister<any>,
},
register: ((name: string) => ({
name,
onChange: (e: any) => Promise.resolve(),
onBlur: (e: any) => Promise.resolve(),
ref: () => {},
})) as UseFormRegister<FieldValues>,
setFocus: () => {},
},
render: () => {
const FormWithDefaultValue = () => {
const form = useForm<z.infer<typeof formSchema>>({

View File

@ -7,7 +7,13 @@ import { cn } from "@/lib/utils";
const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = ({ children, delayDuration = 10 }) => (
const Tooltip = ({
children,
delayDuration = 10,
}: {
children: React.ReactNode;
delayDuration?: number;
}) => (
<TooltipPrimitive.Root delayDuration={delayDuration}>
{children}
</TooltipPrimitive.Root>

View File

@ -1,6 +1,11 @@
import { useCallback } from "react";
import { Node, Edge, useReactFlow, useViewport } from "@xyflow/react";
interface CopyableData {
nodes: Node[];
edges: Edge[];
}
export function useCopyPaste(getNextNodeId: () => string) {
const { setNodes, addEdges, getNodes, getEdges } = useReactFlow();
const { x, y, zoom } = useViewport();
@ -20,7 +25,7 @@ export function useCopyPaste(getNextNodeId: () => string) {
selectedNodeIds.has(edge.target),
);
const copiedData = {
const copiedData: CopyableData = {
nodes: selectedNodes.map((node) => ({
...node,
data: {
@ -36,7 +41,7 @@ export function useCopyPaste(getNextNodeId: () => string) {
if (event.key === "v" || event.key === "V") {
const copiedDataString = localStorage.getItem("copiedFlowData");
if (copiedDataString) {
const copiedData = JSON.parse(copiedDataString);
const copiedData = JSON.parse(copiedDataString) as CopyableData;
const oldToNewIdMap: Record<string, string> = {};
const viewportCenter = {
@ -77,7 +82,7 @@ export function useCopyPaste(getNextNodeId: () => string) {
};
});
const pastedEdges = copiedData.edges.map((edge: Edge) => {
const pastedEdges = copiedData.edges.map((edge) => {
const newSourceId = oldToNewIdMap[edge.source] ?? edge.source;
const newTargetId = oldToNewIdMap[edge.target] ?? edge.target;
return {
@ -99,10 +104,10 @@ export function useCopyPaste(getNextNodeId: () => string) {
if (oldToNewIdMap[node.id]) {
const nodeConnections = pastedEdges
.filter(
(edge) =>
(edge: Edge) =>
edge.source === node.id || edge.target === node.id,
)
.map((edge) => ({
.map((edge: Edge) => ({
edge_id: edge.id,
source: edge.source,
target: edge.target,

View File

@ -10,7 +10,7 @@ const stripePromise = loadStripe(
export default function useCredits(): {
credits: number | null;
fetchCredits: () => void;
requestTopUp: (amount: number) => Promise<void>;
requestTopUp: (credit_amount: number) => Promise<void>;
autoTopUpConfig: { amount: number; threshold: number } | null;
fetchAutoTopUpConfig: () => void;
updateAutoTopUpConfig: (amount: number, threshold: number) => Promise<void>;
@ -51,15 +51,14 @@ export default function useCredits(): {
);
const requestTopUp = useCallback(
async (amount: number) => {
async (credit_amount: number) => {
const stripe = await stripePromise;
if (!stripe) {
return;
}
// Convert dollar amount to credit count
const response = await api.requestTopUp(amount);
const response = await api.requestTopUp(credit_amount);
router.push(response.checkout_url);
},
[api, router],

View File

@ -100,8 +100,8 @@ export default class BackendAPI {
return this._request("POST", "/credits/auto-top-up", config);
}
requestTopUp(amount: number): Promise<{ checkout_url: string }> {
return this._request("POST", "/credits", { amount });
requestTopUp(credit_amount: number): Promise<{ checkout_url: string }> {
return this._request("POST", "/credits", { credit_amount });
}
getUserPaymentPortalLink(): Promise<{ url: string }> {

View File

@ -65,18 +65,21 @@ export type BlockIOObjectSubSchema = BlockIOSubSchemaMeta & {
properties: { [key: string]: BlockIOSubSchema };
default?: { [key: keyof BlockIOObjectSubSchema["properties"]]: any };
required?: (keyof BlockIOObjectSubSchema["properties"])[];
secret?: boolean;
};
export type BlockIOKVSubSchema = BlockIOSubSchemaMeta & {
type: "object";
additionalProperties: { type: "string" | "number" | "integer" };
default?: { [key: string]: string | number };
secret?: boolean;
};
export type BlockIOArraySubSchema = BlockIOSubSchemaMeta & {
type: "array";
items?: BlockIOSimpleTypeSubSchema;
default?: Array<string>;
secret?: boolean;
};
export type BlockIOStringSubSchema = BlockIOSubSchemaMeta & {
@ -90,11 +93,13 @@ export type BlockIOStringSubSchema = BlockIOSubSchemaMeta & {
export type BlockIONumberSubSchema = BlockIOSubSchemaMeta & {
type: "integer" | "number";
default?: number;
secret?: boolean;
};
export type BlockIOBooleanSubSchema = BlockIOSubSchemaMeta & {
type: "boolean";
default?: boolean;
secret?: boolean;
};
export type CredentialsType = "api_key" | "oauth2" | "user_password";
@ -144,16 +149,19 @@ export type CredentialsProviderName =
(typeof PROVIDER_NAMES)[keyof typeof PROVIDER_NAMES];
export type BlockIOCredentialsSubSchema = BlockIOSubSchemaMeta & {
type: "object";
/* Mirror of backend/data/model.py:CredentialsFieldSchemaExtra */
credentials_provider: CredentialsProviderName[];
credentials_scopes?: string[];
credentials_types: Array<CredentialsType>;
discriminator?: string;
discriminator_mapping?: { [key: string]: CredentialsProviderName };
secret?: boolean;
};
export type BlockIONullSubSchema = BlockIOSubSchemaMeta & {
type: "null";
secret?: boolean;
};
// At the time of writing, combined schemas only occur on the first nested level in a
@ -161,15 +169,21 @@ export type BlockIONullSubSchema = BlockIOSubSchemaMeta & {
type BlockIOCombinedTypeSubSchema = BlockIOSubSchemaMeta &
(
| {
type: "allOf";
allOf: [BlockIOSimpleTypeSubSchema];
secret?: boolean;
}
| {
type: "anyOf";
anyOf: BlockIOSimpleTypeSubSchema[];
default?: string | number | boolean | null;
secret?: boolean;
}
| {
type: "oneOf";
oneOf: BlockIOSimpleTypeSubSchema[];
default?: string | number | boolean | null;
secret?: boolean;
}
);

View File

@ -1,6 +1,5 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { createClient, SupabaseClient } from "@supabase/supabase-js";
import { faker } from "@faker-js/faker";
export type TestUser = {
email: string;
@ -26,24 +25,6 @@ function getSupabaseAdmin() {
return supabase;
}
async function createTestUser(userData: TestUser): Promise<TestUser> {
const supabase = getSupabaseAdmin();
const { data: authUser, error: authError } = await supabase.auth.signUp({
email: userData.email,
password: userData.password,
});
if (authError) {
throw new Error(`Failed to create test user: ${authError.message}`);
}
return {
...userData,
id: authUser.user?.id,
};
}
async function deleteTestUser(userId: string) {
const supabase = getSupabaseAdmin();
@ -59,25 +40,3 @@ async function deleteTestUser(userId: string) {
);
}
}
function generateUserData(): TestUser {
return {
email: `test.${faker.string.uuid()}@example.com`,
password: faker.internet.password({ length: 12 }),
};
}
// Export just the fixture function
export const createTestUserFixture = async ({}, use) => {
let user: TestUser | null = null;
try {
const userData = generateUserData();
user = await createTestUser(userData);
await use(user);
} finally {
if (user?.id) {
await deleteTestUser(user.id);
}
}
};