mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-14 09:38:00 -05:00
Compare commits
10 Commits
dev
...
fix/creden
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
104854a008 | ||
|
|
e4b3d2d4ef | ||
|
|
dc35acb4e6 | ||
|
|
2c70f11ec7 | ||
|
|
be7e1b8635 | ||
|
|
302f16c472 | ||
|
|
4fede09fce | ||
|
|
4ce617d7e1 | ||
|
|
8957ecb099 | ||
|
|
d2305d047d |
@@ -175,6 +175,7 @@ async def callback(
|
|||||||
f"Successfully processed OAuth callback for user {user_id} "
|
f"Successfully processed OAuth callback for user {user_id} "
|
||||||
f"and provider {provider.value}"
|
f"and provider {provider.value}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return CredentialsMetaResponse(
|
return CredentialsMetaResponse(
|
||||||
id=credentials.id,
|
id=credentials.id,
|
||||||
provider=credentials.provider,
|
provider=credentials.provider,
|
||||||
@@ -193,6 +194,7 @@ async def list_credentials(
|
|||||||
user_id: Annotated[str, Security(get_user_id)],
|
user_id: Annotated[str, Security(get_user_id)],
|
||||||
) -> list[CredentialsMetaResponse]:
|
) -> list[CredentialsMetaResponse]:
|
||||||
credentials = await creds_manager.store.get_all_creds(user_id)
|
credentials = await creds_manager.store.get_all_creds(user_id)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CredentialsMetaResponse(
|
CredentialsMetaResponse(
|
||||||
id=cred.id,
|
id=cred.id,
|
||||||
@@ -215,6 +217,7 @@ async def list_credentials_by_provider(
|
|||||||
user_id: Annotated[str, Security(get_user_id)],
|
user_id: Annotated[str, Security(get_user_id)],
|
||||||
) -> list[CredentialsMetaResponse]:
|
) -> list[CredentialsMetaResponse]:
|
||||||
credentials = await creds_manager.store.get_creds_by_provider(user_id, provider)
|
credentials = await creds_manager.store.get_creds_by_provider(user_id, provider)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CredentialsMetaResponse(
|
CredentialsMetaResponse(
|
||||||
id=cred.id,
|
id=cred.id,
|
||||||
@@ -831,6 +834,18 @@ async def list_providers() -> List[str]:
|
|||||||
return all_providers
|
return all_providers
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/providers/system", response_model=List[str])
|
||||||
|
async def list_system_providers() -> List[str]:
|
||||||
|
"""
|
||||||
|
Get a list of providers that have platform credits (system credentials) available.
|
||||||
|
|
||||||
|
These providers can be used without the user providing their own API keys.
|
||||||
|
"""
|
||||||
|
from backend.integrations.credentials_store import SYSTEM_PROVIDERS
|
||||||
|
|
||||||
|
return list(SYSTEM_PROVIDERS)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/providers/names", response_model=ProviderNamesResponse)
|
@router.get("/providers/names", response_model=ProviderNamesResponse)
|
||||||
async def get_provider_names() -> ProviderNamesResponse:
|
async def get_provider_names() -> ProviderNamesResponse:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -245,6 +245,21 @@ DEFAULT_CREDENTIALS = [
|
|||||||
webshare_proxy_credentials,
|
webshare_proxy_credentials,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SYSTEM_CREDENTIAL_IDS = {cred.id for cred in DEFAULT_CREDENTIALS}
|
||||||
|
|
||||||
|
# Set of providers that have system credentials available
|
||||||
|
SYSTEM_PROVIDERS = {cred.provider for cred in DEFAULT_CREDENTIALS}
|
||||||
|
|
||||||
|
|
||||||
|
def is_system_credential(credential_id: str) -> bool:
|
||||||
|
"""Check if a credential ID belongs to a system-managed credential."""
|
||||||
|
return credential_id in SYSTEM_CREDENTIAL_IDS
|
||||||
|
|
||||||
|
|
||||||
|
def is_system_provider(provider: str) -> bool:
|
||||||
|
"""Check if a provider has system-managed credentials available."""
|
||||||
|
return provider in SYSTEM_PROVIDERS
|
||||||
|
|
||||||
|
|
||||||
class IntegrationCredentialsStore:
|
class IntegrationCredentialsStore:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@@ -3,6 +3,13 @@ import { withSentryConfig } from "@sentry/nextjs";
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
productionBrowserSourceMaps: true,
|
productionBrowserSourceMaps: true,
|
||||||
|
// Externalize OpenTelemetry packages to fix Turbopack HMR issues
|
||||||
|
serverExternalPackages: [
|
||||||
|
"@opentelemetry/instrumentation",
|
||||||
|
"@opentelemetry/sdk-node",
|
||||||
|
"import-in-the-middle",
|
||||||
|
"require-in-the-middle",
|
||||||
|
],
|
||||||
experimental: {
|
experimental: {
|
||||||
serverActions: {
|
serverActions: {
|
||||||
bodySizeLimit: "256mb",
|
bodySizeLimit: "256mb",
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
"@hookform/resolvers": "5.2.2",
|
"@hookform/resolvers": "5.2.2",
|
||||||
"@next/third-parties": "15.4.6",
|
"@next/third-parties": "15.4.6",
|
||||||
"@phosphor-icons/react": "2.1.10",
|
"@phosphor-icons/react": "2.1.10",
|
||||||
|
"@radix-ui/react-accordion": "1.2.12",
|
||||||
"@radix-ui/react-alert-dialog": "1.1.15",
|
"@radix-ui/react-alert-dialog": "1.1.15",
|
||||||
"@radix-ui/react-avatar": "1.1.10",
|
"@radix-ui/react-avatar": "1.1.10",
|
||||||
"@radix-ui/react-checkbox": "1.3.3",
|
"@radix-ui/react-checkbox": "1.3.3",
|
||||||
@@ -117,6 +118,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@chromatic-com/storybook": "4.1.2",
|
"@chromatic-com/storybook": "4.1.2",
|
||||||
|
"@opentelemetry/instrumentation": "0.209.0",
|
||||||
"@playwright/test": "1.56.1",
|
"@playwright/test": "1.56.1",
|
||||||
"@storybook/addon-a11y": "9.1.5",
|
"@storybook/addon-a11y": "9.1.5",
|
||||||
"@storybook/addon-docs": "9.1.5",
|
"@storybook/addon-docs": "9.1.5",
|
||||||
@@ -140,6 +142,7 @@
|
|||||||
"eslint": "8.57.1",
|
"eslint": "8.57.1",
|
||||||
"eslint-config-next": "15.5.7",
|
"eslint-config-next": "15.5.7",
|
||||||
"eslint-plugin-storybook": "9.1.5",
|
"eslint-plugin-storybook": "9.1.5",
|
||||||
|
"import-in-the-middle": "2.0.2",
|
||||||
"msw": "2.11.6",
|
"msw": "2.11.6",
|
||||||
"msw-storybook-addon": "2.0.6",
|
"msw-storybook-addon": "2.0.6",
|
||||||
"orval": "7.13.0",
|
"orval": "7.13.0",
|
||||||
@@ -147,7 +150,7 @@
|
|||||||
"postcss": "8.5.6",
|
"postcss": "8.5.6",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.6.2",
|
||||||
"prettier-plugin-tailwindcss": "0.7.1",
|
"prettier-plugin-tailwindcss": "0.7.1",
|
||||||
"require-in-the-middle": "7.5.2",
|
"require-in-the-middle": "8.0.1",
|
||||||
"storybook": "9.1.5",
|
"storybook": "9.1.5",
|
||||||
"tailwindcss": "3.4.17",
|
"tailwindcss": "3.4.17",
|
||||||
"typescript": "5.9.3"
|
"typescript": "5.9.3"
|
||||||
@@ -157,5 +160,10 @@
|
|||||||
"public"
|
"public"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"overrides": {
|
||||||
|
"@opentelemetry/instrumentation": "0.209.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"packageManager": "pnpm@10.20.0+sha512.cf9998222162dd85864d0a8102e7892e7ba4ceadebbf5a31f9c2fce48dfce317a9c53b9f6464d1ef9042cba2e02ae02a9f7c143a2b438cd93c91840f0192b9dd"
|
"packageManager": "pnpm@10.20.0+sha512.cf9998222162dd85864d0a8102e7892e7ba4ceadebbf5a31f9c2fce48dfce317a9c53b9f6464d1ef9042cba2e02ae02a9f7c143a2b438cd93c91840f0192b9dd"
|
||||||
}
|
}
|
||||||
|
|||||||
140
autogpt_platform/frontend/pnpm-lock.yaml
generated
140
autogpt_platform/frontend/pnpm-lock.yaml
generated
@@ -4,6 +4,9 @@ settings:
|
|||||||
autoInstallPeers: true
|
autoInstallPeers: true
|
||||||
excludeLinksFromLockfile: false
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
overrides:
|
||||||
|
'@opentelemetry/instrumentation': 0.209.0
|
||||||
|
|
||||||
importers:
|
importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
@@ -20,6 +23,9 @@ importers:
|
|||||||
'@phosphor-icons/react':
|
'@phosphor-icons/react':
|
||||||
specifier: 2.1.10
|
specifier: 2.1.10
|
||||||
version: 2.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 2.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@radix-ui/react-accordion':
|
||||||
|
specifier: 1.2.12
|
||||||
|
version: 1.2.12(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
'@radix-ui/react-alert-dialog':
|
'@radix-ui/react-alert-dialog':
|
||||||
specifier: 1.1.15
|
specifier: 1.1.15
|
||||||
version: 1.1.15(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 1.1.15(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
@@ -270,6 +276,9 @@ importers:
|
|||||||
'@chromatic-com/storybook':
|
'@chromatic-com/storybook':
|
||||||
specifier: 4.1.2
|
specifier: 4.1.2
|
||||||
version: 4.1.2(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))
|
version: 4.1.2(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))
|
||||||
|
'@opentelemetry/instrumentation':
|
||||||
|
specifier: 0.209.0
|
||||||
|
version: 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@playwright/test':
|
'@playwright/test':
|
||||||
specifier: 1.56.1
|
specifier: 1.56.1
|
||||||
version: 1.56.1
|
version: 1.56.1
|
||||||
@@ -339,6 +348,9 @@ importers:
|
|||||||
eslint-plugin-storybook:
|
eslint-plugin-storybook:
|
||||||
specifier: 9.1.5
|
specifier: 9.1.5
|
||||||
version: 9.1.5(eslint@8.57.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3)
|
version: 9.1.5(eslint@8.57.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3)
|
||||||
|
import-in-the-middle:
|
||||||
|
specifier: 2.0.2
|
||||||
|
version: 2.0.2
|
||||||
msw:
|
msw:
|
||||||
specifier: 2.11.6
|
specifier: 2.11.6
|
||||||
version: 2.11.6(@types/node@24.10.0)(typescript@5.9.3)
|
version: 2.11.6(@types/node@24.10.0)(typescript@5.9.3)
|
||||||
@@ -361,8 +373,8 @@ importers:
|
|||||||
specifier: 0.7.1
|
specifier: 0.7.1
|
||||||
version: 0.7.1(prettier@3.6.2)
|
version: 0.7.1(prettier@3.6.2)
|
||||||
require-in-the-middle:
|
require-in-the-middle:
|
||||||
specifier: 7.5.2
|
specifier: 8.0.1
|
||||||
version: 7.5.2
|
version: 8.0.1
|
||||||
storybook:
|
storybook:
|
||||||
specifier: 9.1.5
|
specifier: 9.1.5
|
||||||
version: 9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2)
|
version: 9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2)
|
||||||
@@ -1543,8 +1555,8 @@ packages:
|
|||||||
'@open-draft/until@2.1.0':
|
'@open-draft/until@2.1.0':
|
||||||
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
|
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
|
||||||
|
|
||||||
'@opentelemetry/api-logs@0.208.0':
|
'@opentelemetry/api-logs@0.209.0':
|
||||||
resolution: {integrity: sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==}
|
resolution: {integrity: sha512-xomnUNi7TiAGtOgs0tb54LyrjRZLu9shJGGwkcN7NgtiPYOpNnKLkRJtzZvTjD/w6knSZH9sFZcUSUovYOPg6A==}
|
||||||
engines: {node: '>=8.0.0'}
|
engines: {node: '>=8.0.0'}
|
||||||
|
|
||||||
'@opentelemetry/api@1.9.0':
|
'@opentelemetry/api@1.9.0':
|
||||||
@@ -1695,8 +1707,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@opentelemetry/api': ^1.7.0
|
'@opentelemetry/api': ^1.7.0
|
||||||
|
|
||||||
'@opentelemetry/instrumentation@0.208.0':
|
'@opentelemetry/instrumentation@0.209.0':
|
||||||
resolution: {integrity: sha512-Eju0L4qWcQS+oXxi6pgh7zvE2byogAkcsVv0OjHF/97iOz1N/aKE6etSGowYkie+YA1uo6DNwdSxaaNnLvcRlA==}
|
resolution: {integrity: sha512-Cwe863ojTCnFlxVuuhG7s6ODkAOzKsAEthKAcI4MDRYz1OmGWYnmSl4X2pbyS+hBxVTdvfZePfoEA01IjqcEyw==}
|
||||||
engines: {node: ^18.19.0 || >=20.6.0}
|
engines: {node: ^18.19.0 || >=20.6.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@opentelemetry/api': ^1.3.0
|
'@opentelemetry/api': ^1.3.0
|
||||||
@@ -1810,6 +1822,19 @@ packages:
|
|||||||
'@radix-ui/primitive@1.1.3':
|
'@radix-ui/primitive@1.1.3':
|
||||||
resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==}
|
resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==}
|
||||||
|
|
||||||
|
'@radix-ui/react-accordion@1.2.12':
|
||||||
|
resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@radix-ui/react-alert-dialog@1.1.15':
|
'@radix-ui/react-alert-dialog@1.1.15':
|
||||||
resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==}
|
resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2631,7 +2656,7 @@ packages:
|
|||||||
'@opentelemetry/api': ^1.9.0
|
'@opentelemetry/api': ^1.9.0
|
||||||
'@opentelemetry/context-async-hooks': ^1.30.1 || ^2.1.0 || ^2.2.0
|
'@opentelemetry/context-async-hooks': ^1.30.1 || ^2.1.0 || ^2.2.0
|
||||||
'@opentelemetry/core': ^1.30.1 || ^2.1.0 || ^2.2.0
|
'@opentelemetry/core': ^1.30.1 || ^2.1.0 || ^2.2.0
|
||||||
'@opentelemetry/instrumentation': '>=0.57.1 <1'
|
'@opentelemetry/instrumentation': 0.209.0
|
||||||
'@opentelemetry/resources': ^1.30.1 || ^2.1.0 || ^2.2.0
|
'@opentelemetry/resources': ^1.30.1 || ^2.1.0 || ^2.2.0
|
||||||
'@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 || ^2.2.0
|
'@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 || ^2.2.0
|
||||||
'@opentelemetry/semantic-conventions': ^1.37.0
|
'@opentelemetry/semantic-conventions': ^1.37.0
|
||||||
@@ -4957,8 +4982,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
|
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
import-in-the-middle@2.0.1:
|
import-in-the-middle@2.0.2:
|
||||||
resolution: {integrity: sha512-bruMpJ7xz+9jwGzrwEhWgvRrlKRYCRDBrfU+ur3FcasYXLJDxTruJ//8g2Noj+QFyRBeqbpj8Bhn4Fbw6HjvhA==}
|
resolution: {integrity: sha512-qet/hkGt3EbNGVtbDfPu0BM+tCqBS8wT1SYrstPaDKoWtshsC6licOemz7DVtpBEyvDNzo8UTBf9/GwWuSDZ9w==}
|
||||||
|
|
||||||
imurmurhash@0.1.4:
|
imurmurhash@0.1.4:
|
||||||
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
||||||
@@ -6502,10 +6527,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
require-in-the-middle@7.5.2:
|
|
||||||
resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==}
|
|
||||||
engines: {node: '>=8.6.0'}
|
|
||||||
|
|
||||||
require-in-the-middle@8.0.1:
|
require-in-the-middle@8.0.1:
|
||||||
resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==}
|
resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==}
|
||||||
engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'}
|
engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'}
|
||||||
@@ -8716,7 +8737,7 @@ snapshots:
|
|||||||
|
|
||||||
'@open-draft/until@2.1.0': {}
|
'@open-draft/until@2.1.0': {}
|
||||||
|
|
||||||
'@opentelemetry/api-logs@0.208.0':
|
'@opentelemetry/api-logs@0.209.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
|
|
||||||
@@ -8735,7 +8756,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -8743,7 +8764,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
'@types/connect': 3.4.38
|
'@types/connect': 3.4.38
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -8752,7 +8773,7 @@ snapshots:
|
|||||||
'@opentelemetry/instrumentation-dataloader@0.26.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-dataloader@0.26.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -8760,7 +8781,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -8769,21 +8790,21 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@opentelemetry/instrumentation-generic-pool@0.52.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-generic-pool@0.52.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@opentelemetry/instrumentation-graphql@0.56.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-graphql@0.56.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -8791,7 +8812,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -8800,7 +8821,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
forwarded-parse: 2.1.2
|
forwarded-parse: 2.1.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -8809,7 +8830,7 @@ snapshots:
|
|||||||
'@opentelemetry/instrumentation-ioredis@0.56.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-ioredis@0.56.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/redis-common': 0.38.2
|
'@opentelemetry/redis-common': 0.38.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -8817,7 +8838,7 @@ snapshots:
|
|||||||
'@opentelemetry/instrumentation-kafkajs@0.18.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-kafkajs@0.18.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -8825,7 +8846,7 @@ snapshots:
|
|||||||
'@opentelemetry/instrumentation-knex@0.53.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-knex@0.53.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -8834,7 +8855,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -8842,14 +8863,14 @@ snapshots:
|
|||||||
'@opentelemetry/instrumentation-lru-memoizer@0.53.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-lru-memoizer@0.53.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@opentelemetry/instrumentation-mongodb@0.61.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-mongodb@0.61.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -8857,14 +8878,14 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@opentelemetry/instrumentation-mysql2@0.55.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-mysql2@0.55.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
'@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0)
|
'@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -8873,7 +8894,7 @@ snapshots:
|
|||||||
'@opentelemetry/instrumentation-mysql@0.54.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-mysql@0.54.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@types/mysql': 2.15.27
|
'@types/mysql': 2.15.27
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -8882,7 +8903,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
'@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0)
|
'@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0)
|
||||||
'@types/pg': 8.15.6
|
'@types/pg': 8.15.6
|
||||||
@@ -8893,7 +8914,7 @@ snapshots:
|
|||||||
'@opentelemetry/instrumentation-redis@0.57.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-redis@0.57.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/redis-common': 0.38.2
|
'@opentelemetry/redis-common': 0.38.2
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -8902,7 +8923,7 @@ snapshots:
|
|||||||
'@opentelemetry/instrumentation-tedious@0.27.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation-tedious@0.27.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@types/tedious': 4.0.14
|
'@types/tedious': 4.0.14
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -8911,16 +8932,16 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0)':
|
'@opentelemetry/instrumentation@0.209.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/api-logs': 0.208.0
|
'@opentelemetry/api-logs': 0.209.0
|
||||||
import-in-the-middle: 2.0.1
|
import-in-the-middle: 2.0.2
|
||||||
require-in-the-middle: 8.0.1
|
require-in-the-middle: 8.0.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -9100,7 +9121,7 @@ snapshots:
|
|||||||
'@prisma/instrumentation@6.19.0(@opentelemetry/api@1.9.0)':
|
'@prisma/instrumentation@6.19.0(@opentelemetry/api@1.9.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -9108,6 +9129,23 @@ snapshots:
|
|||||||
|
|
||||||
'@radix-ui/primitive@1.1.3': {}
|
'@radix-ui/primitive@1.1.3': {}
|
||||||
|
|
||||||
|
'@radix-ui/react-accordion@1.2.12(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@radix-ui/primitive': 1.1.3
|
||||||
|
'@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.17)(react@18.3.1)
|
||||||
|
'@radix-ui/react-context': 1.1.2(@types/react@18.3.17)(react@18.3.1)
|
||||||
|
'@radix-ui/react-direction': 1.1.1(@types/react@18.3.17)(react@18.3.1)
|
||||||
|
'@radix-ui/react-id': 1.1.1(@types/react@18.3.17)(react@18.3.1)
|
||||||
|
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.17)(react@18.3.1)
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 18.3.17
|
||||||
|
'@types/react-dom': 18.3.5(@types/react@18.3.17)
|
||||||
|
|
||||||
'@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
'@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@radix-ui/primitive': 1.1.3
|
'@radix-ui/primitive': 1.1.3
|
||||||
@@ -9932,19 +9970,19 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- webpack
|
- webpack
|
||||||
|
|
||||||
'@sentry/node-core@10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)':
|
'@sentry/node-core@10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.209.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@apm-js-collab/tracing-hooks': 0.3.1
|
'@apm-js-collab/tracing-hooks': 0.3.1
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/context-async-hooks': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/context-async-hooks': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
'@sentry/core': 10.27.0
|
'@sentry/core': 10.27.0
|
||||||
'@sentry/opentelemetry': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)
|
'@sentry/opentelemetry': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)
|
||||||
import-in-the-middle: 2.0.1
|
import-in-the-middle: 2.0.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -9953,7 +9991,7 @@ snapshots:
|
|||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
'@opentelemetry/context-async-hooks': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/context-async-hooks': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation': 0.209.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation-amqplib': 0.55.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation-amqplib': 0.55.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation-connect': 0.52.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation-connect': 0.52.0(@opentelemetry/api@1.9.0)
|
||||||
'@opentelemetry/instrumentation-dataloader': 0.26.0(@opentelemetry/api@1.9.0)
|
'@opentelemetry/instrumentation-dataloader': 0.26.0(@opentelemetry/api@1.9.0)
|
||||||
@@ -9981,9 +10019,9 @@ snapshots:
|
|||||||
'@opentelemetry/semantic-conventions': 1.38.0
|
'@opentelemetry/semantic-conventions': 1.38.0
|
||||||
'@prisma/instrumentation': 6.19.0(@opentelemetry/api@1.9.0)
|
'@prisma/instrumentation': 6.19.0(@opentelemetry/api@1.9.0)
|
||||||
'@sentry/core': 10.27.0
|
'@sentry/core': 10.27.0
|
||||||
'@sentry/node-core': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)
|
'@sentry/node-core': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.209.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)
|
||||||
'@sentry/opentelemetry': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)
|
'@sentry/opentelemetry': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)
|
||||||
import-in-the-middle: 2.0.1
|
import-in-the-middle: 2.0.2
|
||||||
minimatch: 9.0.5
|
minimatch: 9.0.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -12792,7 +12830,7 @@ snapshots:
|
|||||||
parent-module: 1.0.1
|
parent-module: 1.0.1
|
||||||
resolve-from: 4.0.0
|
resolve-from: 4.0.0
|
||||||
|
|
||||||
import-in-the-middle@2.0.1:
|
import-in-the-middle@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
acorn-import-attributes: 1.9.5(acorn@8.15.0)
|
acorn-import-attributes: 1.9.5(acorn@8.15.0)
|
||||||
@@ -14631,14 +14669,6 @@ snapshots:
|
|||||||
|
|
||||||
require-from-string@2.0.2: {}
|
require-from-string@2.0.2: {}
|
||||||
|
|
||||||
require-in-the-middle@7.5.2:
|
|
||||||
dependencies:
|
|
||||||
debug: 4.4.3
|
|
||||||
module-details-from-path: 1.0.4
|
|
||||||
resolve: 1.22.11
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
require-in-the-middle@8.0.1:
|
require-in-the-middle@8.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs";
|
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInput";
|
||||||
import { CredentialsMetaInput } from "@/app/api/__generated__/models/credentialsMetaInput";
|
import { CredentialsMetaInput } from "@/app/api/__generated__/models/credentialsMetaInput";
|
||||||
import { GraphMeta } from "@/app/api/__generated__/models/graphMeta";
|
import { GraphMeta } from "@/app/api/__generated__/models/graphMeta";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInput";
|
||||||
import Link from "next/link";
|
import { useGetOauthGetOauthAppInfo } from "@/app/api/__generated__/endpoints/oauth/oauth";
|
||||||
import { useSearchParams } from "next/navigation";
|
import { okData } from "@/app/api/helpers";
|
||||||
import { useState, useMemo, useRef } from "react";
|
|
||||||
import { AuthCard } from "@/components/auth/AuthCard";
|
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
|
||||||
import { Button } from "@/components/atoms/Button/Button";
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
import { AuthCard } from "@/components/auth/AuthCard";
|
||||||
import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard";
|
import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard";
|
||||||
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs";
|
|
||||||
import type {
|
import type {
|
||||||
BlockIOCredentialsSubSchema,
|
BlockIOCredentialsSubSchema,
|
||||||
CredentialsMetaInput,
|
CredentialsMetaInput,
|
||||||
CredentialsType,
|
CredentialsType,
|
||||||
} from "@/lib/autogpt-server-api";
|
} from "@/lib/autogpt-server-api";
|
||||||
import { CheckIcon, CircleIcon } from "@phosphor-icons/react";
|
import { CheckIcon, CircleIcon } from "@phosphor-icons/react";
|
||||||
import { useGetOauthGetOauthAppInfo } from "@/app/api/__generated__/endpoints/oauth/oauth";
|
import Image from "next/image";
|
||||||
import { okData } from "@/app/api/helpers";
|
import Link from "next/link";
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
|
import { useMemo, useRef, useState } from "react";
|
||||||
|
|
||||||
// All credential types - we accept any type of credential
|
// All credential types - we accept any type of credential
|
||||||
const ALL_CREDENTIAL_TYPES: CredentialsType[] = [
|
const ALL_CREDENTIAL_TYPES: CredentialsType[] = [
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
CustomNodeData,
|
CustomNodeData,
|
||||||
} from "@/app/(platform)/build/components/legacy-builder/CustomNode/CustomNode";
|
} from "@/app/(platform)/build/components/legacy-builder/CustomNode/CustomNode";
|
||||||
import { NodeTableInput } from "@/app/(platform)/build/components/legacy-builder/NodeTableInput";
|
import { NodeTableInput } from "@/app/(platform)/build/components/legacy-builder/NodeTableInput";
|
||||||
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs";
|
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInput";
|
||||||
import { Button } from "@/components/__legacy__/ui/button";
|
import { Button } from "@/components/__legacy__/ui/button";
|
||||||
import { Calendar } from "@/components/__legacy__/ui/calendar";
|
import { Calendar } from "@/components/__legacy__/ui/calendar";
|
||||||
import { LocalValuedInput } from "@/components/__legacy__/ui/input";
|
import { LocalValuedInput } from "@/components/__legacy__/ui/input";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs";
|
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInput";
|
||||||
import { Card } from "@/components/atoms/Card/Card";
|
import { Card } from "@/components/atoms/Card/Card";
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
import type { BlockIOCredentialsSubSchema } from "@/lib/autogpt-server-api";
|
import type { BlockIOCredentialsSubSchema } from "@/lib/autogpt-server-api";
|
||||||
|
|||||||
@@ -1,32 +1,31 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Button } from "@/components/atoms/Button/Button";
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
|
import { PublishAgentModal } from "@/components/contextual/PublishAgentModal/PublishAgentModal";
|
||||||
import { Breadcrumbs } from "@/components/molecules/Breadcrumbs/Breadcrumbs";
|
import { Breadcrumbs } from "@/components/molecules/Breadcrumbs/Breadcrumbs";
|
||||||
import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard";
|
import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { PlusIcon } from "@phosphor-icons/react";
|
import { PlusIcon } from "@phosphor-icons/react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { RunAgentModal } from "./components/modals/RunAgentModal/RunAgentModal";
|
|
||||||
import { useMarketplaceUpdate } from "./hooks/useMarketplaceUpdate";
|
|
||||||
import { AgentVersionChangelog } from "./components/AgentVersionChangelog";
|
import { AgentVersionChangelog } from "./components/AgentVersionChangelog";
|
||||||
import { MarketplaceBanners } from "@/components/contextual/MarketplaceBanners/MarketplaceBanners";
|
import { AgentSettingsModal } from "./components/modals/AgentSettingsModal/AgentSettingsModal";
|
||||||
import { PublishAgentModal } from "@/components/contextual/PublishAgentModal/PublishAgentModal";
|
import { RunAgentModal } from "./components/modals/RunAgentModal/RunAgentModal";
|
||||||
import { AgentSettingsButton } from "./components/other/AgentSettingsButton";
|
|
||||||
import { AgentRunsLoading } from "./components/other/AgentRunsLoading";
|
import { AgentRunsLoading } from "./components/other/AgentRunsLoading";
|
||||||
import { EmptySchedules } from "./components/other/EmptySchedules";
|
import { EmptySchedules } from "./components/other/EmptySchedules";
|
||||||
import { EmptyTasks } from "./components/other/EmptyTasks";
|
import { EmptyTasks } from "./components/other/EmptyTasks";
|
||||||
import { EmptyTemplates } from "./components/other/EmptyTemplates";
|
import { EmptyTemplates } from "./components/other/EmptyTemplates";
|
||||||
import { EmptyTriggers } from "./components/other/EmptyTriggers";
|
import { EmptyTriggers } from "./components/other/EmptyTriggers";
|
||||||
|
import { MarketplaceBanners } from "./components/other/MarketplaceBanners";
|
||||||
import { SectionWrap } from "./components/other/SectionWrap";
|
import { SectionWrap } from "./components/other/SectionWrap";
|
||||||
import { LoadingSelectedContent } from "./components/selected-views/LoadingSelectedContent";
|
import { LoadingSelectedContent } from "./components/selected-views/LoadingSelectedContent";
|
||||||
import { SelectedRunView } from "./components/selected-views/SelectedRunView/SelectedRunView";
|
import { SelectedRunView } from "./components/selected-views/SelectedRunView/SelectedRunView";
|
||||||
import { SelectedScheduleView } from "./components/selected-views/SelectedScheduleView/SelectedScheduleView";
|
import { SelectedScheduleView } from "./components/selected-views/SelectedScheduleView/SelectedScheduleView";
|
||||||
import { SelectedSettingsView } from "./components/selected-views/SelectedSettingsView/SelectedSettingsView";
|
|
||||||
import { SelectedTemplateView } from "./components/selected-views/SelectedTemplateView/SelectedTemplateView";
|
import { SelectedTemplateView } from "./components/selected-views/SelectedTemplateView/SelectedTemplateView";
|
||||||
import { SelectedTriggerView } from "./components/selected-views/SelectedTriggerView/SelectedTriggerView";
|
import { SelectedTriggerView } from "./components/selected-views/SelectedTriggerView/SelectedTriggerView";
|
||||||
import { SelectedViewLayout } from "./components/selected-views/SelectedViewLayout";
|
import { SelectedViewLayout } from "./components/selected-views/SelectedViewLayout";
|
||||||
import { SidebarRunsList } from "./components/sidebar/SidebarRunsList/SidebarRunsList";
|
import { SidebarRunsList } from "./components/sidebar/SidebarRunsList/SidebarRunsList";
|
||||||
import { AGENT_LIBRARY_SECTION_PADDING_X } from "./helpers";
|
import { AGENT_LIBRARY_SECTION_PADDING_X } from "./helpers";
|
||||||
|
import { useMarketplaceUpdate } from "./hooks/useMarketplaceUpdate";
|
||||||
import { useNewAgentLibraryView } from "./useNewAgentLibraryView";
|
import { useNewAgentLibraryView } from "./useNewAgentLibraryView";
|
||||||
|
|
||||||
export function NewAgentLibraryView() {
|
export function NewAgentLibraryView() {
|
||||||
@@ -45,7 +44,6 @@ export function NewAgentLibraryView() {
|
|||||||
handleSelectRun,
|
handleSelectRun,
|
||||||
handleCountsChange,
|
handleCountsChange,
|
||||||
handleClearSelectedRun,
|
handleClearSelectedRun,
|
||||||
handleSelectSettings,
|
|
||||||
onRunInitiated,
|
onRunInitiated,
|
||||||
onTriggerSetup,
|
onTriggerSetup,
|
||||||
onScheduleCreated,
|
onScheduleCreated,
|
||||||
@@ -137,13 +135,16 @@ export function NewAgentLibraryView() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
<div className="mx-6 pt-4">
|
<div className="mx-6 flex flex-col gap-4 pt-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
<Breadcrumbs
|
<Breadcrumbs
|
||||||
items={[
|
items={[
|
||||||
{ name: "My Library", link: "/library" },
|
{ name: "My Library", link: "/library" },
|
||||||
{ name: agent.name, link: `/library/agents/${agentId}` },
|
{ name: agent.name, link: `/library/agents/${agentId}` },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<AgentSettingsModal agent={agent} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex min-h-0 flex-1">
|
<div className="flex min-h-0 flex-1">
|
||||||
<EmptyTasks
|
<EmptyTasks
|
||||||
@@ -170,13 +171,12 @@ export function NewAgentLibraryView() {
|
|||||||
AGENT_LIBRARY_SECTION_PADDING_X,
|
AGENT_LIBRARY_SECTION_PADDING_X,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<RunAgentModal
|
<RunAgentModal
|
||||||
triggerSlot={
|
triggerSlot={
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
size="large"
|
size="large"
|
||||||
className="flex-1"
|
className="w-full"
|
||||||
disabled={isTemplateLoading && activeTab === "templates"}
|
disabled={isTemplateLoading && activeTab === "templates"}
|
||||||
>
|
>
|
||||||
<PlusIcon size={20} /> New task
|
<PlusIcon size={20} /> New task
|
||||||
@@ -189,12 +189,6 @@ export function NewAgentLibraryView() {
|
|||||||
initialInputValues={activeTemplate?.inputs}
|
initialInputValues={activeTemplate?.inputs}
|
||||||
initialInputCredentials={activeTemplate?.credentials}
|
initialInputCredentials={activeTemplate?.credentials}
|
||||||
/>
|
/>
|
||||||
<AgentSettingsButton
|
|
||||||
agent={agent}
|
|
||||||
onSelectSettings={handleSelectSettings}
|
|
||||||
selected={activeItem === "settings"}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SidebarRunsList
|
<SidebarRunsList
|
||||||
@@ -208,12 +202,7 @@ export function NewAgentLibraryView() {
|
|||||||
</SectionWrap>
|
</SectionWrap>
|
||||||
|
|
||||||
{activeItem ? (
|
{activeItem ? (
|
||||||
activeItem === "settings" ? (
|
activeTab === "scheduled" ? (
|
||||||
<SelectedSettingsView
|
|
||||||
agent={agent}
|
|
||||||
onClearSelectedRun={handleClearSelectedRun}
|
|
||||||
/>
|
|
||||||
) : activeTab === "scheduled" ? (
|
|
||||||
<SelectedScheduleView
|
<SelectedScheduleView
|
||||||
agent={agent}
|
agent={agent}
|
||||||
scheduleId={activeItem}
|
scheduleId={activeItem}
|
||||||
@@ -246,8 +235,6 @@ export function NewAgentLibraryView() {
|
|||||||
onSelectRun={handleSelectRun}
|
onSelectRun={handleSelectRun}
|
||||||
onClearSelectedRun={handleClearSelectedRun}
|
onClearSelectedRun={handleClearSelectedRun}
|
||||||
banner={renderMarketplaceUpdateBanner()}
|
banner={renderMarketplaceUpdateBanner()}
|
||||||
onSelectSettings={handleSelectSettings}
|
|
||||||
selectedSettings={activeItem === "settings"}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
) : sidebarLoading ? (
|
) : sidebarLoading ? (
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
import type { CredentialsMetaInput } from "@/lib/autogpt-server-api/types";
|
import type { CredentialsMetaInput } from "@/lib/autogpt-server-api/types";
|
||||||
import { CredentialsInput } from "../CredentialsInputs/CredentialsInputs";
|
import { CredentialsInput } from "../CredentialsInputs/CredentialsInput";
|
||||||
|
import { isSystemCredential } from "../CredentialsInputs/helpers";
|
||||||
import { RunAgentInputs } from "../RunAgentInputs/RunAgentInputs";
|
import { RunAgentInputs } from "../RunAgentInputs/RunAgentInputs";
|
||||||
import { getAgentCredentialsFields, getAgentInputFields } from "./helpers";
|
import { getAgentCredentialsFields, getAgentInputFields } from "./helpers";
|
||||||
|
|
||||||
@@ -71,6 +72,7 @@ export function AgentInputsReadOnly({
|
|||||||
{credentialFieldEntries.map(([key, inputSubSchema]) => {
|
{credentialFieldEntries.map(([key, inputSubSchema]) => {
|
||||||
const credential = credentialInputs![key];
|
const credential = credentialInputs![key];
|
||||||
if (!credential) return null;
|
if (!credential) return null;
|
||||||
|
if (isSystemCredential(credential)) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CredentialsInput
|
<CredentialsInput
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||||
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
|
import { Switch } from "@/components/atoms/Switch/Switch";
|
||||||
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
import { Dialog } from "@/components/molecules/Dialog/Dialog";
|
||||||
|
import { useAgentSafeMode } from "@/hooks/useAgentSafeMode";
|
||||||
|
import { GearIcon } from "@phosphor-icons/react";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
agent: LibraryAgent;
|
||||||
|
controlledOpen?: boolean;
|
||||||
|
onOpenChange?: (open: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AgentSettingsModal({
|
||||||
|
agent,
|
||||||
|
controlledOpen,
|
||||||
|
onOpenChange,
|
||||||
|
}: Props) {
|
||||||
|
const [internalIsOpen, setInternalIsOpen] = useState(false);
|
||||||
|
const isOpen = controlledOpen !== undefined ? controlledOpen : internalIsOpen;
|
||||||
|
|
||||||
|
function setIsOpen(open: boolean) {
|
||||||
|
if (onOpenChange) {
|
||||||
|
onOpenChange(open);
|
||||||
|
} else {
|
||||||
|
setInternalIsOpen(open);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { currentSafeMode, isPending, hasHITLBlocks, handleToggle } =
|
||||||
|
useAgentSafeMode(agent);
|
||||||
|
|
||||||
|
if (!hasHITLBlocks) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
controlled={{ isOpen, set: setIsOpen }}
|
||||||
|
styling={{ maxWidth: "600px", maxHeight: "90vh" }}
|
||||||
|
title="Agent Settings"
|
||||||
|
>
|
||||||
|
{controlledOpen === undefined && (
|
||||||
|
<Dialog.Trigger>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="small"
|
||||||
|
className="m-0 min-w-0 rounded-full p-0 px-1"
|
||||||
|
aria-label="Agent Settings"
|
||||||
|
>
|
||||||
|
<GearIcon size={18} className="text-zinc-600" />
|
||||||
|
<Text variant="small">Agent Settings</Text>
|
||||||
|
</Button>
|
||||||
|
</Dialog.Trigger>
|
||||||
|
)}
|
||||||
|
<Dialog.Content>
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="flex w-full flex-col items-start gap-4 rounded-xl border border-zinc-100 bg-white p-6">
|
||||||
|
<div className="flex w-full items-start justify-between gap-4">
|
||||||
|
<div className="flex-1">
|
||||||
|
<Text variant="large-semibold">Require human approval</Text>
|
||||||
|
<Text variant="large" className="mt-1 text-zinc-900">
|
||||||
|
The agent will pause and wait for your review before
|
||||||
|
continuing
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
checked={currentSafeMode || false}
|
||||||
|
onCheckedChange={handleToggle}
|
||||||
|
disabled={isPending}
|
||||||
|
className="mt-1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dialog.Content>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
import { Button } from "@/components/atoms/Button/Button";
|
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
import { InformationTooltip } from "@/components/molecules/InformationTooltip/InformationTooltip";
|
|
||||||
import {
|
import {
|
||||||
BlockIOCredentialsSubSchema,
|
BlockIOCredentialsSubSchema,
|
||||||
CredentialsMetaInput,
|
CredentialsMetaInput,
|
||||||
@@ -8,13 +6,11 @@ import {
|
|||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { toDisplayName } from "@/providers/agent-credentials/helper";
|
import { toDisplayName } from "@/providers/agent-credentials/helper";
|
||||||
import { APIKeyCredentialsModal } from "./components/APIKeyCredentialsModal/APIKeyCredentialsModal";
|
import { APIKeyCredentialsModal } from "./components/APIKeyCredentialsModal/APIKeyCredentialsModal";
|
||||||
import { CredentialRow } from "./components/CredentialRow/CredentialRow";
|
import { CredentialsFlatView } from "./components/CredentialsFlatView/CredentialsFlatView";
|
||||||
import { CredentialsSelect } from "./components/CredentialsSelect/CredentialsSelect";
|
|
||||||
import { DeleteConfirmationModal } from "./components/DeleteConfirmationModal/DeleteConfirmationModal";
|
|
||||||
import { HostScopedCredentialsModal } from "./components/HotScopedCredentialsModal/HotScopedCredentialsModal";
|
import { HostScopedCredentialsModal } from "./components/HotScopedCredentialsModal/HotScopedCredentialsModal";
|
||||||
import { OAuthFlowWaitingModal } from "./components/OAuthWaitingModal/OAuthWaitingModal";
|
import { OAuthFlowWaitingModal } from "./components/OAuthWaitingModal/OAuthWaitingModal";
|
||||||
import { PasswordCredentialsModal } from "./components/PasswordCredentialsModal/PasswordCredentialsModal";
|
import { PasswordCredentialsModal } from "./components/PasswordCredentialsModal/PasswordCredentialsModal";
|
||||||
import { getCredentialDisplayName } from "./helpers";
|
import { isSystemCredential } from "./helpers";
|
||||||
import {
|
import {
|
||||||
CredentialsInputState,
|
CredentialsInputState,
|
||||||
useCredentialsInput,
|
useCredentialsInput,
|
||||||
@@ -72,115 +68,53 @@ export function CredentialsInput({
|
|||||||
supportsOAuth2,
|
supportsOAuth2,
|
||||||
supportsUserPassword,
|
supportsUserPassword,
|
||||||
supportsHostScoped,
|
supportsHostScoped,
|
||||||
credentialsToShow,
|
userCredentials,
|
||||||
|
systemCredentials,
|
||||||
oAuthError,
|
oAuthError,
|
||||||
isAPICredentialsModalOpen,
|
isAPICredentialsModalOpen,
|
||||||
isUserPasswordCredentialsModalOpen,
|
isUserPasswordCredentialsModalOpen,
|
||||||
isHostScopedCredentialsModalOpen,
|
isHostScopedCredentialsModalOpen,
|
||||||
isOAuth2FlowInProgress,
|
isOAuth2FlowInProgress,
|
||||||
oAuthPopupController,
|
oAuthPopupController,
|
||||||
credentialToDelete,
|
|
||||||
deleteCredentialsMutation,
|
|
||||||
actionButtonText,
|
actionButtonText,
|
||||||
setAPICredentialsModalOpen,
|
setAPICredentialsModalOpen,
|
||||||
setUserPasswordCredentialsModalOpen,
|
setUserPasswordCredentialsModalOpen,
|
||||||
setHostScopedCredentialsModalOpen,
|
setHostScopedCredentialsModalOpen,
|
||||||
setCredentialToDelete,
|
|
||||||
handleActionButtonClick,
|
handleActionButtonClick,
|
||||||
handleCredentialSelect,
|
handleCredentialSelect,
|
||||||
handleDeleteCredential,
|
|
||||||
handleDeleteConfirm,
|
|
||||||
} = hookData;
|
} = hookData;
|
||||||
|
|
||||||
const displayName = toDisplayName(provider);
|
const displayName = toDisplayName(provider);
|
||||||
const hasCredentialsToShow = credentialsToShow.length > 0;
|
const selectedCredentialIsSystem =
|
||||||
|
selectedCredential && isSystemCredential(selectedCredential);
|
||||||
|
|
||||||
|
const allCredentials = [...userCredentials, ...systemCredentials];
|
||||||
|
|
||||||
|
if (readOnly && selectedCredentialIsSystem) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("mb-6", className)}>
|
<div className={cn("mb-6", className)}>
|
||||||
{showTitle && (
|
<CredentialsFlatView
|
||||||
<div className="mb-2 flex items-center gap-2">
|
schema={schema}
|
||||||
<Text variant="large-medium">
|
|
||||||
{displayName} credentials
|
|
||||||
{isOptional && (
|
|
||||||
<span className="ml-1 text-sm font-normal text-gray-500">
|
|
||||||
(optional)
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
{schema.description && (
|
|
||||||
<InformationTooltip description={schema.description} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasCredentialsToShow ? (
|
|
||||||
<>
|
|
||||||
{(credentialsToShow.length > 1 || isOptional) && !readOnly ? (
|
|
||||||
<CredentialsSelect
|
|
||||||
credentials={credentialsToShow}
|
|
||||||
provider={provider}
|
provider={provider}
|
||||||
displayName={displayName}
|
displayName={displayName}
|
||||||
selectedCredentials={selectedCredential}
|
credentials={allCredentials}
|
||||||
|
selectedCredential={selectedCredential}
|
||||||
onSelectCredential={handleCredentialSelect}
|
onSelectCredential={handleCredentialSelect}
|
||||||
onClearCredential={() => onSelectCredential(undefined)}
|
onClearCredential={() => onSelectCredential(undefined)}
|
||||||
|
onAddCredential={handleActionButtonClick}
|
||||||
|
actionButtonText={actionButtonText}
|
||||||
|
isOptional={isOptional}
|
||||||
|
showTitle={showTitle}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
allowNone={isOptional}
|
|
||||||
variant={variant}
|
variant={variant}
|
||||||
/>
|
/>
|
||||||
) : (
|
|
||||||
<div className="mb-4 space-y-2">
|
|
||||||
{credentialsToShow.map((credential) => {
|
|
||||||
return (
|
|
||||||
<CredentialRow
|
|
||||||
key={credential.id}
|
|
||||||
credential={credential}
|
|
||||||
provider={provider}
|
|
||||||
displayName={displayName}
|
|
||||||
onSelect={() => handleCredentialSelect(credential.id)}
|
|
||||||
onDelete={() =>
|
|
||||||
handleDeleteCredential({
|
|
||||||
id: credential.id,
|
|
||||||
title: getCredentialDisplayName(
|
|
||||||
credential,
|
|
||||||
displayName,
|
|
||||||
),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
readOnly={readOnly}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!readOnly && (
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
size="small"
|
|
||||||
onClick={handleActionButtonClick}
|
|
||||||
className="w-fit"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
{actionButtonText}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
!readOnly && (
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
size="small"
|
|
||||||
onClick={handleActionButtonClick}
|
|
||||||
className="w-fit"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
{actionButtonText}
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!readOnly && (
|
{!readOnly && (
|
||||||
<>
|
<>
|
||||||
{supportsApiKey ? (
|
{supportsApiKey && (
|
||||||
<APIKeyCredentialsModal
|
<APIKeyCredentialsModal
|
||||||
schema={schema}
|
schema={schema}
|
||||||
open={isAPICredentialsModalOpen}
|
open={isAPICredentialsModalOpen}
|
||||||
@@ -191,15 +125,15 @@ export function CredentialsInput({
|
|||||||
}}
|
}}
|
||||||
siblingInputs={siblingInputs}
|
siblingInputs={siblingInputs}
|
||||||
/>
|
/>
|
||||||
) : null}
|
)}
|
||||||
{supportsOAuth2 ? (
|
{supportsOAuth2 && (
|
||||||
<OAuthFlowWaitingModal
|
<OAuthFlowWaitingModal
|
||||||
open={isOAuth2FlowInProgress}
|
open={isOAuth2FlowInProgress}
|
||||||
onClose={() => oAuthPopupController?.abort("canceled")}
|
onClose={() => oAuthPopupController?.abort("canceled")}
|
||||||
providerName={providerName}
|
providerName={providerName}
|
||||||
/>
|
/>
|
||||||
) : null}
|
)}
|
||||||
{supportsUserPassword ? (
|
{supportsUserPassword && (
|
||||||
<PasswordCredentialsModal
|
<PasswordCredentialsModal
|
||||||
schema={schema}
|
schema={schema}
|
||||||
open={isUserPasswordCredentialsModalOpen}
|
open={isUserPasswordCredentialsModalOpen}
|
||||||
@@ -210,8 +144,8 @@ export function CredentialsInput({
|
|||||||
}}
|
}}
|
||||||
siblingInputs={siblingInputs}
|
siblingInputs={siblingInputs}
|
||||||
/>
|
/>
|
||||||
) : null}
|
)}
|
||||||
{supportsHostScoped ? (
|
{supportsHostScoped && (
|
||||||
<HostScopedCredentialsModal
|
<HostScopedCredentialsModal
|
||||||
schema={schema}
|
schema={schema}
|
||||||
open={isHostScopedCredentialsModalOpen}
|
open={isHostScopedCredentialsModalOpen}
|
||||||
@@ -222,20 +156,13 @@ export function CredentialsInput({
|
|||||||
}}
|
}}
|
||||||
siblingInputs={siblingInputs}
|
siblingInputs={siblingInputs}
|
||||||
/>
|
/>
|
||||||
) : null}
|
)}
|
||||||
|
|
||||||
{oAuthError ? (
|
{oAuthError && (
|
||||||
<Text variant="body" className="mt-2 text-red-500">
|
<Text variant="body" className="mt-2 text-red-500">
|
||||||
Error: {oAuthError}
|
Error: {oAuthError}
|
||||||
</Text>
|
</Text>
|
||||||
) : null}
|
)}
|
||||||
|
|
||||||
<DeleteConfirmationModal
|
|
||||||
credentialToDelete={credentialToDelete}
|
|
||||||
isDeleting={deleteCredentialsMutation.isPending}
|
|
||||||
onClose={() => setCredentialToDelete(null)}
|
|
||||||
onConfirm={handleDeleteConfirm}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Input } from "@/components/atoms/Input/Input";
|
|
||||||
import { Button } from "@/components/atoms/Button/Button";
|
|
||||||
import { Dialog } from "@/components/molecules/Dialog/Dialog";
|
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormDescription,
|
FormDescription,
|
||||||
FormField,
|
FormField,
|
||||||
} from "@/components/__legacy__/ui/form";
|
} from "@/components/__legacy__/ui/form";
|
||||||
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
|
import { Input } from "@/components/atoms/Input/Input";
|
||||||
|
import { Dialog } from "@/components/molecules/Dialog/Dialog";
|
||||||
import {
|
import {
|
||||||
BlockIOCredentialsSubSchema,
|
BlockIOCredentialsSubSchema,
|
||||||
CredentialsMetaInput,
|
CredentialsMetaInput,
|
||||||
@@ -60,7 +60,23 @@ export function APIKeyCredentialsModal({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-2">
|
<form
|
||||||
|
onSubmit={form.handleSubmit(onSubmit)}
|
||||||
|
className="space-y-2 px-2"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="title"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Input
|
||||||
|
id="title"
|
||||||
|
label="Name"
|
||||||
|
type="text"
|
||||||
|
placeholder="Enter a name for this API Key..."
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="apiKey"
|
name="apiKey"
|
||||||
@@ -70,8 +86,7 @@ export function APIKeyCredentialsModal({
|
|||||||
id="apiKey"
|
id="apiKey"
|
||||||
label="API Key"
|
label="API Key"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="Enter API key..."
|
placeholder="Enter API Key..."
|
||||||
size="small"
|
|
||||||
hint={
|
hint={
|
||||||
schema.credentials_scopes ? (
|
schema.credentials_scopes ? (
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
@@ -90,20 +105,7 @@ export function APIKeyCredentialsModal({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="title"
|
|
||||||
render={({ field }) => (
|
|
||||||
<Input
|
|
||||||
id="title"
|
|
||||||
label="Name"
|
|
||||||
type="text"
|
|
||||||
placeholder="Enter a name for this API key..."
|
|
||||||
size="small"
|
|
||||||
{...field}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="expiresAt"
|
name="expiresAt"
|
||||||
@@ -113,13 +115,31 @@ export function APIKeyCredentialsModal({
|
|||||||
label="Expiration Date"
|
label="Expiration Date"
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
placeholder="Select expiration date..."
|
placeholder="Select expiration date..."
|
||||||
size="small"
|
value={field.value}
|
||||||
{...field}
|
onChange={(e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
if (value) {
|
||||||
|
const dateTime = new Date(value);
|
||||||
|
dateTime.setHours(0, 0, 0, 0);
|
||||||
|
const year = dateTime.getFullYear();
|
||||||
|
const month = String(dateTime.getMonth() + 1).padStart(
|
||||||
|
2,
|
||||||
|
"0",
|
||||||
|
);
|
||||||
|
const day = String(dateTime.getDate()).padStart(2, "0");
|
||||||
|
const normalizedValue = `${year}-${month}-${day}T00:00`;
|
||||||
|
field.onChange(normalizedValue);
|
||||||
|
} else {
|
||||||
|
field.onChange(value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Button type="submit" size="small" className="min-w-68">
|
<Button type="submit" className="min-w-68">
|
||||||
Save & use this API key
|
Add API Key
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { z } from "zod";
|
|
||||||
import { useForm, type UseFormReturn } from "react-hook-form";
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
|
||||||
import useCredentials from "@/hooks/useCredentials";
|
import useCredentials from "@/hooks/useCredentials";
|
||||||
import {
|
import {
|
||||||
BlockIOCredentialsSubSchema,
|
BlockIOCredentialsSubSchema,
|
||||||
CredentialsMetaInput,
|
CredentialsMetaInput,
|
||||||
} from "@/lib/autogpt-server-api/types";
|
} from "@/lib/autogpt-server-api/types";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useForm, type UseFormReturn } from "react-hook-form";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export type APIKeyFormValues = {
|
export type APIKeyFormValues = {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
@@ -40,12 +40,24 @@ export function useAPIKeyCredentialsModal({
|
|||||||
expiresAt: z.string().optional(),
|
expiresAt: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getDefaultExpirationDate(): string {
|
||||||
|
const tomorrow = new Date();
|
||||||
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
|
tomorrow.setHours(0, 0, 0, 0);
|
||||||
|
const year = tomorrow.getFullYear();
|
||||||
|
const month = String(tomorrow.getMonth() + 1).padStart(2, "0");
|
||||||
|
const day = String(tomorrow.getDate()).padStart(2, "0");
|
||||||
|
const hours = String(tomorrow.getHours()).padStart(2, "0");
|
||||||
|
const minutes = String(tomorrow.getMinutes()).padStart(2, "0");
|
||||||
|
return `${year}-${month}-${day}T${hours}:${minutes}`;
|
||||||
|
}
|
||||||
|
|
||||||
const form = useForm<APIKeyFormValues>({
|
const form = useForm<APIKeyFormValues>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
apiKey: "",
|
apiKey: "",
|
||||||
title: "",
|
title: "",
|
||||||
expiresAt: "",
|
expiresAt: getDefaultExpirationDate(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/molecules/DropdownMenu/DropdownMenu";
|
} from "@/components/molecules/DropdownMenu/DropdownMenu";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { CaretDown, DotsThreeVertical } from "@phosphor-icons/react";
|
import { CaretDownIcon, DotsThreeVertical } from "@phosphor-icons/react";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
fallbackIcon,
|
fallbackIcon,
|
||||||
getCredentialDisplayName,
|
getCredentialDisplayName,
|
||||||
@@ -26,7 +27,7 @@ type CredentialRowProps = {
|
|||||||
provider: string;
|
provider: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
onSelect: () => void;
|
onSelect: () => void;
|
||||||
onDelete: () => void;
|
onDelete?: () => void;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
showCaret?: boolean;
|
showCaret?: boolean;
|
||||||
asSelectTrigger?: boolean;
|
asSelectTrigger?: boolean;
|
||||||
@@ -47,11 +48,32 @@ export function CredentialRow({
|
|||||||
}: CredentialRowProps) {
|
}: CredentialRowProps) {
|
||||||
const ProviderIcon = providerIcons[provider] || fallbackIcon;
|
const ProviderIcon = providerIcons[provider] || fallbackIcon;
|
||||||
const isNodeVariant = variant === "node";
|
const isNodeVariant = variant === "node";
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [showMaskedKey, setShowMaskedKey] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const container = containerRef.current;
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
const resizeObserver = new ResizeObserver((entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
const width = entry.contentRect.width;
|
||||||
|
setShowMaskedKey(width >= 360);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
resizeObserver.observe(container);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
resizeObserver.disconnect();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={containerRef}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-3 rounded-medium border border-zinc-200 bg-white p-3 transition-colors",
|
"flex min-w-[20rem] items-center gap-3 rounded-medium border border-zinc-200 bg-white p-3 transition-colors",
|
||||||
asSelectTrigger && isNodeVariant
|
asSelectTrigger && isNodeVariant
|
||||||
? "min-w-0 flex-1 overflow-hidden border-0 bg-transparent"
|
? "min-w-0 flex-1 overflow-hidden border-0 bg-transparent"
|
||||||
: asSelectTrigger
|
: asSelectTrigger
|
||||||
@@ -73,34 +95,35 @@ export function CredentialRow({
|
|||||||
<IconKey className="h-5 w-5 shrink-0 text-zinc-800" />
|
<IconKey className="h-5 w-5 shrink-0 text-zinc-800" />
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex min-w-0 flex-1 flex-nowrap items-center gap-4",
|
"relative flex min-w-0 flex-1 flex-nowrap items-center gap-4",
|
||||||
isNodeVariant && "overflow-hidden",
|
isNodeVariant && "overflow-hidden",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
variant="body"
|
variant="body"
|
||||||
className={cn(
|
className={cn(
|
||||||
"tracking-tight",
|
"min-w-0 flex-1 tracking-tight",
|
||||||
isNodeVariant
|
isNodeVariant ? "truncate" : "line-clamp-1 text-ellipsis",
|
||||||
? "truncate"
|
|
||||||
: "line-clamp-1 flex-[0_0_50%] text-ellipsis",
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{getCredentialDisplayName(credential, displayName)}
|
{getCredentialDisplayName(credential, displayName)}
|
||||||
</Text>
|
</Text>
|
||||||
{!(asSelectTrigger && isNodeVariant) && (
|
{!(asSelectTrigger && isNodeVariant) && showMaskedKey && (
|
||||||
<Text
|
<Text
|
||||||
variant="large"
|
variant="large"
|
||||||
className="relative top-1 hidden overflow-hidden whitespace-nowrap font-mono tracking-tight md:block"
|
className={cn(
|
||||||
|
"absolute top-[65%] -translate-y-1/2 overflow-hidden whitespace-nowrap font-mono tracking-tight",
|
||||||
|
asSelectTrigger ? "right-0" : "right-6",
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{"*".repeat(MASKED_KEY_LENGTH)}
|
{"*".repeat(MASKED_KEY_LENGTH)}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{showCaret && !asSelectTrigger && (
|
{(showCaret || (asSelectTrigger && !readOnly)) && (
|
||||||
<CaretDown className="h-4 w-4 shrink-0 text-gray-400" />
|
<CaretDownIcon className="h-4 w-4 shrink-0 text-gray-400" />
|
||||||
)}
|
)}
|
||||||
{!readOnly && !showCaret && !asSelectTrigger && (
|
{!readOnly && !showCaret && !asSelectTrigger && onDelete && (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -0,0 +1,203 @@
|
|||||||
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
import {
|
||||||
|
Accordion,
|
||||||
|
AccordionContent,
|
||||||
|
AccordionItem,
|
||||||
|
AccordionTrigger,
|
||||||
|
} from "@/components/molecules/Accordion/Accordion";
|
||||||
|
import { InformationTooltip } from "@/components/molecules/InformationTooltip/InformationTooltip";
|
||||||
|
import {
|
||||||
|
BlockIOCredentialsSubSchema,
|
||||||
|
CredentialsMetaInput,
|
||||||
|
} from "@/lib/autogpt-server-api/types";
|
||||||
|
import { SlidersHorizontalIcon } from "lucide-react";
|
||||||
|
import { CredentialRow } from "../CredentialRow/CredentialRow";
|
||||||
|
import { CredentialsSelect } from "../CredentialsSelect/CredentialsSelect";
|
||||||
|
|
||||||
|
type Credential = {
|
||||||
|
id: string;
|
||||||
|
title?: string;
|
||||||
|
username?: string;
|
||||||
|
type: string;
|
||||||
|
provider: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
schema: BlockIOCredentialsSubSchema;
|
||||||
|
provider: string;
|
||||||
|
displayName: string;
|
||||||
|
userCredentials: Credential[];
|
||||||
|
systemCredentials: Credential[];
|
||||||
|
isSystemProvider: boolean;
|
||||||
|
selectedCredential?: CredentialsMetaInput;
|
||||||
|
onSelectCredential: (credentialId: string) => void;
|
||||||
|
onClearCredential: () => void;
|
||||||
|
onAddCredential: () => void;
|
||||||
|
actionButtonText: string;
|
||||||
|
isOptional: boolean;
|
||||||
|
showTitle: boolean;
|
||||||
|
variant: "default" | "node";
|
||||||
|
};
|
||||||
|
|
||||||
|
export function CredentialsAccordionView({
|
||||||
|
schema,
|
||||||
|
provider,
|
||||||
|
displayName,
|
||||||
|
userCredentials,
|
||||||
|
systemCredentials,
|
||||||
|
isSystemProvider,
|
||||||
|
selectedCredential,
|
||||||
|
onSelectCredential,
|
||||||
|
onClearCredential,
|
||||||
|
onAddCredential,
|
||||||
|
actionButtonText,
|
||||||
|
isOptional,
|
||||||
|
showTitle,
|
||||||
|
variant,
|
||||||
|
}: Props) {
|
||||||
|
const allCredentials = [...userCredentials, ...systemCredentials];
|
||||||
|
const hasSystemCredentials = systemCredentials.length > 0;
|
||||||
|
const hasUserCredentials = userCredentials.length > 0;
|
||||||
|
|
||||||
|
const credentialsInAccordion = isSystemProvider
|
||||||
|
? allCredentials
|
||||||
|
: systemCredentials;
|
||||||
|
|
||||||
|
const shouldOpenAccordionByDefault =
|
||||||
|
hasSystemCredentials && !isOptional && !selectedCredential;
|
||||||
|
|
||||||
|
const showUserCredentialsOutsideAccordion =
|
||||||
|
!isSystemProvider && hasUserCredentials;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{showTitle && showUserCredentialsOutsideAccordion && (
|
||||||
|
<div className="mb-2 flex items-center gap-2">
|
||||||
|
<Text variant="large-medium">
|
||||||
|
{displayName} credentials
|
||||||
|
{isOptional && (
|
||||||
|
<span className="ml-1 text-sm font-normal text-gray-500">
|
||||||
|
(optional)
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
{schema.description && (
|
||||||
|
<InformationTooltip description={schema.description} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showUserCredentialsOutsideAccordion && (
|
||||||
|
<>
|
||||||
|
{userCredentials.length > 1 || isOptional ? (
|
||||||
|
<CredentialsSelect
|
||||||
|
credentials={userCredentials}
|
||||||
|
provider={provider}
|
||||||
|
displayName={displayName}
|
||||||
|
selectedCredentials={selectedCredential}
|
||||||
|
onSelectCredential={onSelectCredential}
|
||||||
|
onClearCredential={onClearCredential}
|
||||||
|
allowNone={isOptional}
|
||||||
|
variant={variant}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="mb-4 space-y-2">
|
||||||
|
{userCredentials.map((credential) => (
|
||||||
|
<CredentialRow
|
||||||
|
key={credential.id}
|
||||||
|
credential={credential}
|
||||||
|
provider={provider}
|
||||||
|
displayName={displayName}
|
||||||
|
onSelect={() => onSelectCredential(credential.id)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
size="small"
|
||||||
|
onClick={onAddCredential}
|
||||||
|
className="w-fit"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{actionButtonText}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasSystemCredentials && (
|
||||||
|
<Accordion
|
||||||
|
type="single"
|
||||||
|
collapsible
|
||||||
|
defaultValue={
|
||||||
|
shouldOpenAccordionByDefault ? "system-credentials" : undefined
|
||||||
|
}
|
||||||
|
className={showUserCredentialsOutsideAccordion ? "mt-4" : ""}
|
||||||
|
>
|
||||||
|
<AccordionItem value="system-credentials" className="border-none">
|
||||||
|
<AccordionTrigger className="py-2 text-sm text-muted-foreground hover:no-underline">
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<SlidersHorizontalIcon className="size-4" /> System credentials
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
<div className="space-y-4 px-1 pt-2">
|
||||||
|
{showTitle && (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Text variant="large-medium">
|
||||||
|
{displayName} credentials
|
||||||
|
{isOptional && (
|
||||||
|
<span className="ml-1 text-sm font-normal text-gray-500">
|
||||||
|
(optional)
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
{schema.description && (
|
||||||
|
<InformationTooltip description={schema.description} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{credentialsInAccordion.length > 0 && (
|
||||||
|
<CredentialsSelect
|
||||||
|
credentials={credentialsInAccordion}
|
||||||
|
provider={provider}
|
||||||
|
displayName={displayName}
|
||||||
|
selectedCredentials={selectedCredential}
|
||||||
|
onSelectCredential={onSelectCredential}
|
||||||
|
onClearCredential={onClearCredential}
|
||||||
|
allowNone={isOptional}
|
||||||
|
variant={variant}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{isSystemProvider && (
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
size="small"
|
||||||
|
onClick={onAddCredential}
|
||||||
|
className="w-fit"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{actionButtonText}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!showUserCredentialsOutsideAccordion && !isSystemProvider && (
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
size="small"
|
||||||
|
onClick={onAddCredential}
|
||||||
|
className="w-fit"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{actionButtonText}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
import { InformationTooltip } from "@/components/molecules/InformationTooltip/InformationTooltip";
|
||||||
|
import {
|
||||||
|
BlockIOCredentialsSubSchema,
|
||||||
|
CredentialsMetaInput,
|
||||||
|
} from "@/lib/autogpt-server-api/types";
|
||||||
|
import { ExclamationTriangleIcon } from "@radix-ui/react-icons";
|
||||||
|
import { CredentialRow } from "../CredentialRow/CredentialRow";
|
||||||
|
import { CredentialsSelect } from "../CredentialsSelect/CredentialsSelect";
|
||||||
|
|
||||||
|
type Credential = {
|
||||||
|
id: string;
|
||||||
|
title?: string;
|
||||||
|
username?: string;
|
||||||
|
type: string;
|
||||||
|
provider: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
schema: BlockIOCredentialsSubSchema;
|
||||||
|
provider: string;
|
||||||
|
displayName: string;
|
||||||
|
credentials: Credential[];
|
||||||
|
selectedCredential?: CredentialsMetaInput;
|
||||||
|
actionButtonText: string;
|
||||||
|
isOptional: boolean;
|
||||||
|
showTitle: boolean;
|
||||||
|
readOnly: boolean;
|
||||||
|
variant: "default" | "node";
|
||||||
|
onSelectCredential: (credentialId: string) => void;
|
||||||
|
onClearCredential: () => void;
|
||||||
|
onAddCredential: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function CredentialsFlatView({
|
||||||
|
schema,
|
||||||
|
provider,
|
||||||
|
displayName,
|
||||||
|
credentials,
|
||||||
|
selectedCredential,
|
||||||
|
actionButtonText,
|
||||||
|
isOptional,
|
||||||
|
showTitle,
|
||||||
|
readOnly,
|
||||||
|
variant,
|
||||||
|
onSelectCredential,
|
||||||
|
onClearCredential,
|
||||||
|
onAddCredential,
|
||||||
|
}: Props) {
|
||||||
|
const hasCredentials = credentials.length > 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{showTitle && (
|
||||||
|
<div className="mb-2 flex items-center gap-2">
|
||||||
|
<Text variant="large-medium" className="flex items-center gap-2">
|
||||||
|
<span className="inline-flex items-center gap-1">
|
||||||
|
{displayName} credentials
|
||||||
|
{isOptional && (
|
||||||
|
<span className="text-sm font-normal text-gray-500">
|
||||||
|
(optional)
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{!isOptional && !selectedCredential && (
|
||||||
|
<span className="inline-flex items-center gap-1 text-red-600">
|
||||||
|
<ExclamationTriangleIcon className="size-4" />
|
||||||
|
<span className="text-sm font-normal">required</span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</Text>
|
||||||
|
{schema.description && (
|
||||||
|
<InformationTooltip description={schema.description} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasCredentials ? (
|
||||||
|
<>
|
||||||
|
{(credentials.length > 1 || isOptional) && !readOnly ? (
|
||||||
|
<CredentialsSelect
|
||||||
|
credentials={credentials}
|
||||||
|
provider={provider}
|
||||||
|
displayName={displayName}
|
||||||
|
selectedCredentials={selectedCredential}
|
||||||
|
onSelectCredential={onSelectCredential}
|
||||||
|
onClearCredential={onClearCredential}
|
||||||
|
readOnly={readOnly}
|
||||||
|
allowNone={isOptional}
|
||||||
|
variant={variant}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="mb-4 space-y-2">
|
||||||
|
{credentials.map((credential) => (
|
||||||
|
<CredentialRow
|
||||||
|
key={credential.id}
|
||||||
|
credential={credential}
|
||||||
|
provider={provider}
|
||||||
|
displayName={displayName}
|
||||||
|
onSelect={() => onSelectCredential(credential.id)}
|
||||||
|
readOnly={readOnly}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!readOnly && (
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
size="small"
|
||||||
|
onClick={onAddCredential}
|
||||||
|
className="w-fit"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{actionButtonText}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
!readOnly && (
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
size="small"
|
||||||
|
onClick={onAddCredential}
|
||||||
|
className="w-fit"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{actionButtonText}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,14 +1,4 @@
|
|||||||
import {
|
import { CredentialsMetaInput } from "@/app/api/__generated__/models/credentialsMetaInput";
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/__legacy__/ui/select";
|
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
|
||||||
import { CredentialsMetaInput } from "@/lib/autogpt-server-api/types";
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import { getCredentialDisplayName } from "../../helpers";
|
import { getCredentialDisplayName } from "../../helpers";
|
||||||
import { CredentialRow } from "../CredentialRow/CredentialRow";
|
import { CredentialRow } from "../CredentialRow/CredentialRow";
|
||||||
|
|
||||||
@@ -42,42 +32,67 @@ export function CredentialsSelect({
|
|||||||
allowNone = true,
|
allowNone = true,
|
||||||
variant = "default",
|
variant = "default",
|
||||||
}: Props) {
|
}: Props) {
|
||||||
// Auto-select first credential if none is selected (only if allowNone is false)
|
function handleValueChange(e: React.ChangeEvent<HTMLSelectElement>) {
|
||||||
useEffect(() => {
|
const value = e.target.value;
|
||||||
if (!allowNone && !selectedCredentials && credentials.length > 0) {
|
|
||||||
onSelectCredential(credentials[0].id);
|
|
||||||
}
|
|
||||||
}, [allowNone, selectedCredentials, credentials, onSelectCredential]);
|
|
||||||
|
|
||||||
const handleValueChange = (value: string) => {
|
|
||||||
if (value === "__none__") {
|
if (value === "__none__") {
|
||||||
onClearCredential?.();
|
onClearCredential?.();
|
||||||
} else {
|
} else {
|
||||||
onSelectCredential(value);
|
onSelectCredential(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedCredential = selectedCredentials
|
||||||
|
? credentials.find((c) => c.id === selectedCredentials.id)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const displayCredential = selectedCredential
|
||||||
|
? {
|
||||||
|
id: selectedCredential.id,
|
||||||
|
title: selectedCredential.title,
|
||||||
|
username: selectedCredential.username,
|
||||||
|
type: selectedCredential.type,
|
||||||
|
provider: selectedCredential.provider,
|
||||||
|
}
|
||||||
|
: allowNone
|
||||||
|
? {
|
||||||
|
id: "__none__",
|
||||||
|
title: "None (skip this credential)",
|
||||||
|
type: "none",
|
||||||
|
provider: provider,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
id: "__placeholder__",
|
||||||
|
title: "Select credential",
|
||||||
|
type: "placeholder",
|
||||||
|
provider: provider,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-4 w-full">
|
<div className="mb-4 w-full">
|
||||||
<Select
|
<div className="relative">
|
||||||
value={selectedCredentials?.id || (allowNone ? "__none__" : "")}
|
<select
|
||||||
onValueChange={handleValueChange}
|
value={selectedCredentials?.id ?? "__none__"}
|
||||||
|
onChange={handleValueChange}
|
||||||
|
disabled={readOnly}
|
||||||
|
className="absolute inset-0 z-10 cursor-pointer opacity-0"
|
||||||
|
aria-label={`Select ${displayName} credential`}
|
||||||
>
|
>
|
||||||
<SelectTrigger
|
{allowNone ? (
|
||||||
className={cn(
|
<option value="__none__">None (skip this credential)</option>
|
||||||
"h-auto min-h-12 w-full rounded-medium border-zinc-200 p-0 pr-4 shadow-none",
|
) : (
|
||||||
variant === "node" && "overflow-hidden",
|
<option value="__none__" disabled hidden>
|
||||||
|
Select a credential
|
||||||
|
</option>
|
||||||
)}
|
)}
|
||||||
>
|
{credentials.map((credential) => (
|
||||||
{selectedCredentials ? (
|
<option key={credential.id} value={credential.id}>
|
||||||
<SelectValue key={selectedCredentials.id} asChild>
|
{getCredentialDisplayName(credential, displayName)}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<div className="rounded-medium border border-zinc-200 bg-white">
|
||||||
<CredentialRow
|
<CredentialRow
|
||||||
credential={{
|
credential={displayCredential}
|
||||||
id: selectedCredentials.id,
|
|
||||||
title: selectedCredentials.title || undefined,
|
|
||||||
type: selectedCredentials.type,
|
|
||||||
provider: selectedCredentials.provider,
|
|
||||||
}}
|
|
||||||
provider={provider}
|
provider={provider}
|
||||||
displayName={displayName}
|
displayName={displayName}
|
||||||
onSelect={() => {}}
|
onSelect={() => {}}
|
||||||
@@ -86,32 +101,8 @@ export function CredentialsSelect({
|
|||||||
asSelectTrigger={true}
|
asSelectTrigger={true}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
/>
|
/>
|
||||||
</SelectValue>
|
|
||||||
) : (
|
|
||||||
<SelectValue key="placeholder" placeholder="Select credential" />
|
|
||||||
)}
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
{allowNone && (
|
|
||||||
<SelectItem key="__none__" value="__none__">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Text variant="body" className="tracking-tight text-gray-500">
|
|
||||||
None (skip this credential)
|
|
||||||
</Text>
|
|
||||||
</div>
|
</div>
|
||||||
</SelectItem>
|
|
||||||
)}
|
|
||||||
{credentials.map((credential) => (
|
|
||||||
<SelectItem key={credential.id} value={credential.id}>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Text variant="body" className="tracking-tight">
|
|
||||||
{getCredentialDisplayName(credential, displayName)}
|
|
||||||
</Text>
|
|
||||||
</div>
|
</div>
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,4 +99,30 @@ export function getCredentialDisplayName(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const OAUTH_TIMEOUT_MS = 5 * 60 * 1000;
|
export const OAUTH_TIMEOUT_MS = 5 * 60 * 1000;
|
||||||
export const MASKED_KEY_LENGTH = 30;
|
export const MASKED_KEY_LENGTH = 15;
|
||||||
|
|
||||||
|
export function isSystemCredential(credential: {
|
||||||
|
title?: string | null;
|
||||||
|
is_system?: boolean;
|
||||||
|
}): boolean {
|
||||||
|
if (credential.is_system === true) return true;
|
||||||
|
if (!credential.title) return false;
|
||||||
|
const titleLower = credential.title.toLowerCase();
|
||||||
|
return (
|
||||||
|
titleLower.includes("system") ||
|
||||||
|
titleLower.startsWith("use credits for") ||
|
||||||
|
titleLower.includes("use credits")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function filterSystemCredentials<
|
||||||
|
T extends { title?: string; is_system?: boolean },
|
||||||
|
>(credentials: T[]): T[] {
|
||||||
|
return credentials.filter((cred) => !isSystemCredential(cred));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSystemCredentials<
|
||||||
|
T extends { title?: string; is_system?: boolean },
|
||||||
|
>(credentials: T[]): T[] {
|
||||||
|
return credentials.filter((cred) => isSystemCredential(cred));
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ import {
|
|||||||
CredentialsMetaInput,
|
CredentialsMetaInput,
|
||||||
} from "@/lib/autogpt-server-api/types";
|
} from "@/lib/autogpt-server-api/types";
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
|
filterSystemCredentials,
|
||||||
getActionButtonText,
|
getActionButtonText,
|
||||||
|
getSystemCredentials,
|
||||||
OAUTH_TIMEOUT_MS,
|
OAUTH_TIMEOUT_MS,
|
||||||
OAuthPopupResultMessage,
|
OAuthPopupResultMessage,
|
||||||
} from "./helpers";
|
} from "./helpers";
|
||||||
@@ -54,6 +56,7 @@ export function useCredentialsInput({
|
|||||||
const api = useBackendAPI();
|
const api = useBackendAPI();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const credentials = useCredentials(schema, siblingInputs);
|
const credentials = useCredentials(schema, siblingInputs);
|
||||||
|
const hasAttemptedAutoSelect = useRef(false);
|
||||||
|
|
||||||
const deleteCredentialsMutation = useDeleteV1DeleteCredentials({
|
const deleteCredentialsMutation = useDeleteV1DeleteCredentials({
|
||||||
mutation: {
|
mutation: {
|
||||||
@@ -82,38 +85,51 @@ export function useCredentialsInput({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (readOnly) return;
|
if (readOnly) return;
|
||||||
if (!credentials || !("savedCredentials" in credentials)) return;
|
if (!credentials || !("savedCredentials" in credentials)) return;
|
||||||
|
const availableCreds = credentials.savedCredentials;
|
||||||
if (
|
if (
|
||||||
selectedCredential &&
|
selectedCredential &&
|
||||||
!credentials.savedCredentials.some((c) => c.id === selectedCredential.id)
|
!availableCreds.some((c) => c.id === selectedCredential.id)
|
||||||
) {
|
) {
|
||||||
onSelectCredential(undefined);
|
onSelectCredential(undefined);
|
||||||
|
// Reset auto-selection flag so it can run again after unsetting invalid credential
|
||||||
|
hasAttemptedAutoSelect.current = false;
|
||||||
}
|
}
|
||||||
}, [credentials, selectedCredential, onSelectCredential, readOnly]);
|
}, [credentials, selectedCredential, onSelectCredential, readOnly]);
|
||||||
|
|
||||||
// The available credential, if there is only one
|
// Auto-select the first available credential on initial mount
|
||||||
const singleCredential = useMemo(() => {
|
// Once a user has made a selection, we don't override it
|
||||||
if (!credentials || !("savedCredentials" in credentials)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return credentials.savedCredentials.length === 1
|
|
||||||
? credentials.savedCredentials[0]
|
|
||||||
: null;
|
|
||||||
}, [credentials]);
|
|
||||||
|
|
||||||
// Auto-select the one available credential (only if not optional)
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (readOnly) return;
|
if (readOnly) return;
|
||||||
if (isOptional) return; // Don't auto-select when credential is optional
|
if (!credentials || !("savedCredentials" in credentials)) return;
|
||||||
if (singleCredential && !selectedCredential) {
|
|
||||||
onSelectCredential(singleCredential);
|
// If already selected, don't auto-select
|
||||||
|
if (selectedCredential?.id) return;
|
||||||
|
|
||||||
|
// Only attempt auto-selection once
|
||||||
|
if (hasAttemptedAutoSelect.current) return;
|
||||||
|
hasAttemptedAutoSelect.current = true;
|
||||||
|
|
||||||
|
// If optional, don't auto-select (user can choose "None")
|
||||||
|
if (isOptional) return;
|
||||||
|
|
||||||
|
const savedCreds = credentials.savedCredentials;
|
||||||
|
|
||||||
|
// Auto-select the first credential if any are available
|
||||||
|
if (savedCreds.length > 0) {
|
||||||
|
const cred = savedCreds[0];
|
||||||
|
onSelectCredential({
|
||||||
|
id: cred.id,
|
||||||
|
type: cred.type,
|
||||||
|
provider: credentials.provider,
|
||||||
|
title: (cred as any).title,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
singleCredential,
|
credentials,
|
||||||
selectedCredential,
|
selectedCredential?.id,
|
||||||
onSelectCredential,
|
|
||||||
readOnly,
|
readOnly,
|
||||||
isOptional,
|
isOptional,
|
||||||
|
onSelectCredential,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -135,8 +151,13 @@ export function useCredentialsInput({
|
|||||||
supportsHostScoped,
|
supportsHostScoped,
|
||||||
savedCredentials,
|
savedCredentials,
|
||||||
oAuthCallback,
|
oAuthCallback,
|
||||||
|
isSystemProvider,
|
||||||
} = credentials;
|
} = credentials;
|
||||||
|
|
||||||
|
// Split credentials into user and system
|
||||||
|
const userCredentials = filterSystemCredentials(savedCredentials);
|
||||||
|
const systemCredentials = getSystemCredentials(savedCredentials);
|
||||||
|
|
||||||
async function handleOAuthLogin() {
|
async function handleOAuthLogin() {
|
||||||
setOAuthError(null);
|
setOAuthError(null);
|
||||||
const { login_url, state_token } = await api.oAuthLogin(
|
const { login_url, state_token } = await api.oAuthLogin(
|
||||||
@@ -291,7 +312,10 @@ export function useCredentialsInput({
|
|||||||
supportsOAuth2,
|
supportsOAuth2,
|
||||||
supportsUserPassword,
|
supportsUserPassword,
|
||||||
supportsHostScoped,
|
supportsHostScoped,
|
||||||
credentialsToShow: savedCredentials,
|
isSystemProvider,
|
||||||
|
userCredentials,
|
||||||
|
systemCredentials,
|
||||||
|
allCredentials: savedCredentials,
|
||||||
selectedCredential,
|
selectedCredential,
|
||||||
oAuthError,
|
oAuthError,
|
||||||
isAPICredentialsModalOpen,
|
isAPICredentialsModalOpen,
|
||||||
@@ -306,7 +330,7 @@ export function useCredentialsInput({
|
|||||||
supportsApiKey,
|
supportsApiKey,
|
||||||
supportsUserPassword,
|
supportsUserPassword,
|
||||||
supportsHostScoped,
|
supportsHostScoped,
|
||||||
savedCredentials.length > 0,
|
userCredentials.length > 0,
|
||||||
),
|
),
|
||||||
setAPICredentialsModalOpen,
|
setAPICredentialsModalOpen,
|
||||||
setUserPasswordCredentialsModalOpen,
|
setUserPasswordCredentialsModalOpen,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/atoms/Tooltip/BaseTooltip";
|
} from "@/components/atoms/Tooltip/BaseTooltip";
|
||||||
import { Dialog } from "@/components/molecules/Dialog/Dialog";
|
import { Dialog } from "@/components/molecules/Dialog/Dialog";
|
||||||
import { useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { ScheduleAgentModal } from "../ScheduleAgentModal/ScheduleAgentModal";
|
import { ScheduleAgentModal } from "../ScheduleAgentModal/ScheduleAgentModal";
|
||||||
import { ModalHeader } from "./components/ModalHeader/ModalHeader";
|
import { ModalHeader } from "./components/ModalHeader/ModalHeader";
|
||||||
import { ModalRunSection } from "./components/ModalRunSection/ModalRunSection";
|
import { ModalRunSection } from "./components/ModalRunSection/ModalRunSection";
|
||||||
@@ -82,6 +82,8 @@ export function RunAgentModal({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [isScheduleModalOpen, setIsScheduleModalOpen] = useState(false);
|
const [isScheduleModalOpen, setIsScheduleModalOpen] = useState(false);
|
||||||
|
const [hasOverflow, setHasOverflow] = useState(false);
|
||||||
|
const contentRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const hasAnySetupFields =
|
const hasAnySetupFields =
|
||||||
Object.keys(agentInputFields || {}).length > 0 ||
|
Object.keys(agentInputFields || {}).length > 0 ||
|
||||||
@@ -89,6 +91,43 @@ export function RunAgentModal({
|
|||||||
|
|
||||||
const isTriggerRunType = defaultRunType.includes("trigger");
|
const isTriggerRunType = defaultRunType.includes("trigger");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isOpen) return;
|
||||||
|
|
||||||
|
function checkOverflow() {
|
||||||
|
if (!contentRef.current) return;
|
||||||
|
const scrollableParent = contentRef.current
|
||||||
|
.closest("[data-dialog-content]")
|
||||||
|
?.querySelector('[class*="overflow-y-auto"]');
|
||||||
|
if (scrollableParent) {
|
||||||
|
setHasOverflow(
|
||||||
|
scrollableParent.scrollHeight > scrollableParent.clientHeight,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeoutId = setTimeout(checkOverflow, 100);
|
||||||
|
const resizeObserver = new ResizeObserver(checkOverflow);
|
||||||
|
if (contentRef.current) {
|
||||||
|
const scrollableParent = contentRef.current
|
||||||
|
.closest("[data-dialog-content]")
|
||||||
|
?.querySelector('[class*="overflow-y-auto"]');
|
||||||
|
if (scrollableParent) {
|
||||||
|
resizeObserver.observe(scrollableParent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
resizeObserver.disconnect();
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
isOpen,
|
||||||
|
hasAnySetupFields,
|
||||||
|
agentInputFields,
|
||||||
|
agentCredentialsInputFields,
|
||||||
|
]);
|
||||||
|
|
||||||
function handleInputChange(key: string, value: string) {
|
function handleInputChange(key: string, value: string) {
|
||||||
setInputValues((prev) => ({
|
setInputValues((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
@@ -134,12 +173,14 @@ export function RunAgentModal({
|
|||||||
>
|
>
|
||||||
<Dialog.Trigger>{triggerSlot}</Dialog.Trigger>
|
<Dialog.Trigger>{triggerSlot}</Dialog.Trigger>
|
||||||
<Dialog.Content>
|
<Dialog.Content>
|
||||||
|
<div ref={contentRef} className="flex min-h-full flex-col">
|
||||||
|
<div className="flex-1">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<ModalHeader agent={agent} />
|
<ModalHeader agent={agent} />
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
{hasAnySetupFields ? (
|
{hasAnySetupFields ? (
|
||||||
<div className="mt-10">
|
<div className="mt-10 pb-32">
|
||||||
<RunAgentModalContextProvider
|
<RunAgentModalContextProvider
|
||||||
value={{
|
value={{
|
||||||
agent,
|
agent,
|
||||||
@@ -160,8 +201,15 @@ export function RunAgentModal({
|
|||||||
</RunAgentModalContextProvider>
|
</RunAgentModalContextProvider>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
<Dialog.Footer className="mt-6 bg-white pt-4">
|
<Dialog.Footer
|
||||||
|
className={`sticky bottom-0 z-10 bg-white pt-4 ${
|
||||||
|
hasOverflow
|
||||||
|
? "border-t border-neutral-100 shadow-[0_-2px_8px_rgba(0,0,0,0.04)]"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<div className="flex items-center justify-end gap-3">
|
<div className="flex items-center justify-end gap-3">
|
||||||
{isTriggerRunType ? null : !allRequiredInputsAreSet ? (
|
{isTriggerRunType ? null : !allRequiredInputsAreSet ? (
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
@@ -183,8 +231,8 @@ export function RunAgentModal({
|
|||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>
|
<p>
|
||||||
Please set up all required inputs and credentials before
|
Please set up all required inputs and credentials
|
||||||
scheduling
|
before scheduling
|
||||||
</p>
|
</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -193,11 +241,7 @@ export function RunAgentModal({
|
|||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={handleOpenScheduleModal}
|
onClick={handleOpenScheduleModal}
|
||||||
disabled={
|
disabled={isExecuting || isSettingUpTrigger}
|
||||||
isExecuting ||
|
|
||||||
isSettingUpTrigger ||
|
|
||||||
!allRequiredInputsAreSet
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
Schedule Task
|
Schedule Task
|
||||||
</Button>
|
</Button>
|
||||||
@@ -219,6 +263,7 @@ export function RunAgentModal({
|
|||||||
onScheduleCreated={handleScheduleCreated}
|
onScheduleCreated={handleScheduleCreated}
|
||||||
/>
|
/>
|
||||||
</Dialog.Footer>
|
</Dialog.Footer>
|
||||||
|
</div>
|
||||||
</Dialog.Content>
|
</Dialog.Content>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInput";
|
||||||
|
import {
|
||||||
|
Accordion,
|
||||||
|
AccordionContent,
|
||||||
|
AccordionItem,
|
||||||
|
AccordionTrigger,
|
||||||
|
} from "@/components/molecules/Accordion/Accordion";
|
||||||
|
import { CredentialsProvidersContext } from "@/providers/agent-credentials/credentials-provider";
|
||||||
|
import { SlidersHorizontal } from "@phosphor-icons/react";
|
||||||
|
import { useContext, useEffect, useMemo, useRef } from "react";
|
||||||
|
import { useRunAgentModalContext } from "../../context";
|
||||||
|
import {
|
||||||
|
CredentialField,
|
||||||
|
findSavedCredentialByProviderAndType,
|
||||||
|
hasMissingRequiredSystemCredentials,
|
||||||
|
splitCredentialFieldsBySystem,
|
||||||
|
} from "../helpers";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
credentialFields: CredentialField[];
|
||||||
|
requiredCredentials: Set<string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function CredentialsGroupedView({
|
||||||
|
credentialFields,
|
||||||
|
requiredCredentials,
|
||||||
|
}: Props) {
|
||||||
|
const allProviders = useContext(CredentialsProvidersContext);
|
||||||
|
const { inputCredentials, setInputCredentialsValue, inputValues } =
|
||||||
|
useRunAgentModalContext();
|
||||||
|
|
||||||
|
const { userCredentialFields, systemCredentialFields } = useMemo(
|
||||||
|
() =>
|
||||||
|
splitCredentialFieldsBySystem(
|
||||||
|
credentialFields,
|
||||||
|
allProviders,
|
||||||
|
inputCredentials,
|
||||||
|
),
|
||||||
|
[credentialFields, allProviders, inputCredentials],
|
||||||
|
);
|
||||||
|
|
||||||
|
const hasSystemCredentials = systemCredentialFields.length > 0;
|
||||||
|
const hasUserCredentials = userCredentialFields.length > 0;
|
||||||
|
const hasAttemptedAutoSelect = useRef(false);
|
||||||
|
|
||||||
|
const hasMissingSystemCredentials = useMemo(
|
||||||
|
() =>
|
||||||
|
hasMissingRequiredSystemCredentials(
|
||||||
|
systemCredentialFields,
|
||||||
|
requiredCredentials,
|
||||||
|
inputCredentials,
|
||||||
|
),
|
||||||
|
[systemCredentialFields, requiredCredentials, inputCredentials],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasAttemptedAutoSelect.current) return;
|
||||||
|
if (!hasSystemCredentials) return;
|
||||||
|
|
||||||
|
let appliedSelection = false;
|
||||||
|
|
||||||
|
for (const [key, schema] of systemCredentialFields) {
|
||||||
|
const alreadySelected = inputCredentials?.[key];
|
||||||
|
const isRequired = requiredCredentials.has(key);
|
||||||
|
if (alreadySelected || !isRequired) continue;
|
||||||
|
|
||||||
|
const providerNames = schema.credentials_provider || [];
|
||||||
|
const credentialTypes = schema.credentials_types || [];
|
||||||
|
const savedCredential = findSavedCredentialByProviderAndType(
|
||||||
|
providerNames,
|
||||||
|
credentialTypes,
|
||||||
|
allProviders,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (savedCredential) {
|
||||||
|
appliedSelection = true;
|
||||||
|
setInputCredentialsValue(key, {
|
||||||
|
id: savedCredential.id,
|
||||||
|
provider: savedCredential.provider,
|
||||||
|
type: savedCredential.type,
|
||||||
|
title: (savedCredential as { title?: string }).title,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appliedSelection) {
|
||||||
|
hasAttemptedAutoSelect.current = true;
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
allProviders,
|
||||||
|
hasSystemCredentials,
|
||||||
|
systemCredentialFields,
|
||||||
|
requiredCredentials,
|
||||||
|
inputCredentials,
|
||||||
|
setInputCredentialsValue,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
{hasUserCredentials && (
|
||||||
|
<>
|
||||||
|
{userCredentialFields.map(
|
||||||
|
([key, inputSubSchema]: CredentialField) => {
|
||||||
|
const selectedCred = inputCredentials?.[key];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CredentialsInput
|
||||||
|
key={key}
|
||||||
|
schema={
|
||||||
|
{ ...inputSubSchema, discriminator: undefined } as any
|
||||||
|
}
|
||||||
|
selectedCredentials={selectedCred}
|
||||||
|
onSelectCredentials={(value) => {
|
||||||
|
setInputCredentialsValue(key, value);
|
||||||
|
}}
|
||||||
|
siblingInputs={inputValues}
|
||||||
|
isOptional={!requiredCredentials.has(key)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasSystemCredentials && (
|
||||||
|
<Accordion
|
||||||
|
type="single"
|
||||||
|
collapsible
|
||||||
|
className={hasUserCredentials ? "mt-4" : ""}
|
||||||
|
>
|
||||||
|
<AccordionItem value="system-credentials" className="border-none">
|
||||||
|
<AccordionTrigger className="py-2 text-sm text-muted-foreground hover:no-underline">
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<SlidersHorizontal size={16} weight="bold" /> System credentials
|
||||||
|
{hasMissingSystemCredentials && (
|
||||||
|
<span className="text-destructive">(missing)</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
<div className="space-y-6 px-1 pt-2">
|
||||||
|
{systemCredentialFields.map(
|
||||||
|
([key, inputSubSchema]: CredentialField) => {
|
||||||
|
const selectedCred = inputCredentials?.[key];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CredentialsInput
|
||||||
|
key={key}
|
||||||
|
schema={
|
||||||
|
{ ...inputSubSchema, discriminator: undefined } as any
|
||||||
|
}
|
||||||
|
selectedCredentials={selectedCred}
|
||||||
|
onSelectCredentials={(value) => {
|
||||||
|
setInputCredentialsValue(key, value);
|
||||||
|
}}
|
||||||
|
siblingInputs={inputValues}
|
||||||
|
isOptional={!requiredCredentials.has(key)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs";
|
|
||||||
import { Input } from "@/components/atoms/Input/Input";
|
import { Input } from "@/components/atoms/Input/Input";
|
||||||
import { InformationTooltip } from "@/components/molecules/InformationTooltip/InformationTooltip";
|
import { InformationTooltip } from "@/components/molecules/InformationTooltip/InformationTooltip";
|
||||||
|
import { useMemo } from "react";
|
||||||
import { RunAgentInputs } from "../../../RunAgentInputs/RunAgentInputs";
|
import { RunAgentInputs } from "../../../RunAgentInputs/RunAgentInputs";
|
||||||
import { useRunAgentModalContext } from "../../context";
|
import { useRunAgentModalContext } from "../../context";
|
||||||
|
import { CredentialsGroupedView } from "../CredentialsGroupedView/CredentialsGroupedView";
|
||||||
import { ModalSection } from "../ModalSection/ModalSection";
|
import { ModalSection } from "../ModalSection/ModalSection";
|
||||||
import { WebhookTriggerBanner } from "../WebhookTriggerBanner/WebhookTriggerBanner";
|
import { WebhookTriggerBanner } from "../WebhookTriggerBanner/WebhookTriggerBanner";
|
||||||
|
|
||||||
@@ -17,15 +18,16 @@ export function ModalRunSection() {
|
|||||||
inputValues,
|
inputValues,
|
||||||
setInputValue,
|
setInputValue,
|
||||||
agentInputFields,
|
agentInputFields,
|
||||||
inputCredentials,
|
|
||||||
setInputCredentialsValue,
|
|
||||||
agentCredentialsInputFields,
|
agentCredentialsInputFields,
|
||||||
} = useRunAgentModalContext();
|
} = useRunAgentModalContext();
|
||||||
|
|
||||||
const inputFields = Object.entries(agentInputFields || {});
|
const inputFields = Object.entries(agentInputFields || {});
|
||||||
const credentialFields = Object.entries(agentCredentialsInputFields || {});
|
|
||||||
|
|
||||||
// Get the list of required credentials from the schema
|
const credentialFields = useMemo(() => {
|
||||||
|
if (!agentCredentialsInputFields) return [];
|
||||||
|
return Object.entries(agentCredentialsInputFields);
|
||||||
|
}, [agentCredentialsInputFields]);
|
||||||
|
|
||||||
const requiredCredentials = new Set(
|
const requiredCredentials = new Set(
|
||||||
(agent.credentials_input_schema?.required as string[]) || [],
|
(agent.credentials_input_schema?.required as string[]) || [],
|
||||||
);
|
);
|
||||||
@@ -97,24 +99,10 @@ export function ModalRunSection() {
|
|||||||
title="Task Credentials"
|
title="Task Credentials"
|
||||||
subtitle="These are the credentials the agent will use to perform this task"
|
subtitle="These are the credentials the agent will use to perform this task"
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<CredentialsGroupedView
|
||||||
{Object.entries(agentCredentialsInputFields || {}).map(
|
credentialFields={credentialFields}
|
||||||
([key, inputSubSchema]) => (
|
requiredCredentials={requiredCredentials}
|
||||||
<CredentialsInput
|
|
||||||
key={key}
|
|
||||||
schema={
|
|
||||||
{ ...inputSubSchema, discriminator: undefined } as any
|
|
||||||
}
|
|
||||||
selectedCredentials={inputCredentials?.[key]}
|
|
||||||
onSelectCredentials={(value) =>
|
|
||||||
setInputCredentialsValue(key, value)
|
|
||||||
}
|
|
||||||
siblingInputs={inputValues}
|
|
||||||
isOptional={!requiredCredentials.has(key)}
|
|
||||||
/>
|
/>
|
||||||
),
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</ModalSection>
|
</ModalSection>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { CredentialsProvidersContextType } from "@/providers/agent-credentials/credentials-provider";
|
||||||
|
|
||||||
|
export type CredentialField = [string, any];
|
||||||
|
|
||||||
|
type SavedCredential = {
|
||||||
|
id: string;
|
||||||
|
provider: string;
|
||||||
|
type: string;
|
||||||
|
title?: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function splitCredentialFieldsBySystem(
|
||||||
|
credentialFields: CredentialField[],
|
||||||
|
allProviders: CredentialsProvidersContextType | null,
|
||||||
|
inputCredentials?: Record<string, unknown>,
|
||||||
|
) {
|
||||||
|
if (!allProviders || credentialFields.length === 0) {
|
||||||
|
return {
|
||||||
|
userCredentialFields: [] as CredentialField[],
|
||||||
|
systemCredentialFields: [] as CredentialField[],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const userFields: CredentialField[] = [];
|
||||||
|
const systemFields: CredentialField[] = [];
|
||||||
|
|
||||||
|
for (const [key, schema] of credentialFields) {
|
||||||
|
const providerNames = schema.credentials_provider || [];
|
||||||
|
const isSystemField = providerNames.some((providerName: string) => {
|
||||||
|
const providerData = allProviders[providerName];
|
||||||
|
return providerData?.isSystemProvider === true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isSystemField) {
|
||||||
|
systemFields.push([key, schema]);
|
||||||
|
} else {
|
||||||
|
userFields.push([key, schema]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortByUnsetFirst = (a: CredentialField, b: CredentialField) => {
|
||||||
|
const aIsSet = Boolean(inputCredentials?.[a[0]]);
|
||||||
|
const bIsSet = Boolean(inputCredentials?.[b[0]]);
|
||||||
|
|
||||||
|
if (aIsSet === bIsSet) return 0;
|
||||||
|
return aIsSet ? 1 : -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
userCredentialFields: userFields.sort(sortByUnsetFirst),
|
||||||
|
systemCredentialFields: systemFields.sort(sortByUnsetFirst),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasMissingRequiredSystemCredentials(
|
||||||
|
systemCredentialFields: CredentialField[],
|
||||||
|
requiredCredentials: Set<string>,
|
||||||
|
inputCredentials?: Record<string, unknown>,
|
||||||
|
) {
|
||||||
|
if (systemCredentialFields.length === 0) return false;
|
||||||
|
|
||||||
|
return systemCredentialFields.some(([key]) => {
|
||||||
|
const isRequired = requiredCredentials.has(key);
|
||||||
|
const selectedCred = inputCredentials?.[key];
|
||||||
|
return isRequired && !selectedCred;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findSavedCredentialByProviderAndType(
|
||||||
|
providerNames: string[],
|
||||||
|
credentialTypes: string[],
|
||||||
|
allProviders: CredentialsProvidersContextType | null,
|
||||||
|
): SavedCredential | undefined {
|
||||||
|
for (const providerName of providerNames) {
|
||||||
|
const providerData = allProviders?.[providerName];
|
||||||
|
if (!providerData) continue;
|
||||||
|
|
||||||
|
const matchingCredential = providerData.savedCredentials.find(
|
||||||
|
(credential) => {
|
||||||
|
if (credentialTypes.length > 0) {
|
||||||
|
return credentialTypes.includes(credential.type);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (matchingCredential) {
|
||||||
|
return matchingCredential as SavedCredential;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
@@ -11,9 +11,18 @@ import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
|||||||
import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset";
|
import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset";
|
||||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||||
import { isEmpty } from "@/lib/utils";
|
import { isEmpty } from "@/lib/utils";
|
||||||
|
import { CredentialsProvidersContext } from "@/providers/agent-credentials/credentials-provider";
|
||||||
import { analytics } from "@/services/analytics";
|
import { analytics } from "@/services/analytics";
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import {
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import { getSystemCredentials } from "../CredentialsInputs/helpers";
|
||||||
import { showExecutionErrorToast } from "./errorHelpers";
|
import { showExecutionErrorToast } from "./errorHelpers";
|
||||||
|
|
||||||
export type RunVariant =
|
export type RunVariant =
|
||||||
@@ -42,8 +51,10 @@ export function useAgentRunModal(
|
|||||||
const [inputCredentials, setInputCredentials] = useState<Record<string, any>>(
|
const [inputCredentials, setInputCredentials] = useState<Record<string, any>>(
|
||||||
callbacks?.initialInputCredentials || {},
|
callbacks?.initialInputCredentials || {},
|
||||||
);
|
);
|
||||||
|
|
||||||
const [presetName, setPresetName] = useState<string>("");
|
const [presetName, setPresetName] = useState<string>("");
|
||||||
const [presetDescription, setPresetDescription] = useState<string>("");
|
const [presetDescription, setPresetDescription] = useState<string>("");
|
||||||
|
const hasInitializedSystemCreds = useRef(false);
|
||||||
|
|
||||||
// Determine the default run type based on agent capabilities
|
// Determine the default run type based on agent capabilities
|
||||||
const defaultRunType: RunVariant = agent.trigger_setup_info
|
const defaultRunType: RunVariant = agent.trigger_setup_info
|
||||||
@@ -58,6 +69,91 @@ export function useAgentRunModal(
|
|||||||
setInputCredentials(callbacks?.initialInputCredentials || {});
|
setInputCredentials(callbacks?.initialInputCredentials || {});
|
||||||
}, [callbacks?.initialInputValues, callbacks?.initialInputCredentials]);
|
}, [callbacks?.initialInputValues, callbacks?.initialInputCredentials]);
|
||||||
|
|
||||||
|
const allProviders = useContext(CredentialsProvidersContext);
|
||||||
|
|
||||||
|
// Initialize credentials with default system credentials
|
||||||
|
useEffect(() => {
|
||||||
|
if (!allProviders || !agent.credentials_input_schema?.properties) return;
|
||||||
|
if (callbacks?.initialInputCredentials) {
|
||||||
|
hasInitializedSystemCreds.current = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hasInitializedSystemCreds.current) return;
|
||||||
|
|
||||||
|
const properties = agent.credentials_input_schema.properties as Record<
|
||||||
|
string,
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
|
||||||
|
setInputCredentials((currentCreds) => {
|
||||||
|
const credsToAdd: Record<string, any> = {};
|
||||||
|
|
||||||
|
for (const [key, schema] of Object.entries(properties)) {
|
||||||
|
if (currentCreds[key]) continue;
|
||||||
|
|
||||||
|
const providerNames = schema.credentials_provider || [];
|
||||||
|
const supportedTypes = schema.credentials_types || [];
|
||||||
|
const requiredScopes = schema.credentials_scopes;
|
||||||
|
|
||||||
|
for (const providerName of providerNames) {
|
||||||
|
const providerData = allProviders[providerName];
|
||||||
|
if (!providerData) continue;
|
||||||
|
|
||||||
|
const systemCreds = getSystemCredentials(
|
||||||
|
providerData.savedCredentials ?? [],
|
||||||
|
);
|
||||||
|
const matchingSystemCreds = systemCreds.filter((cred) => {
|
||||||
|
if (!supportedTypes.includes(cred.type)) return false;
|
||||||
|
|
||||||
|
if (
|
||||||
|
cred.type === "oauth2" &&
|
||||||
|
requiredScopes &&
|
||||||
|
requiredScopes.length > 0
|
||||||
|
) {
|
||||||
|
const grantedScopes = new Set(cred.scopes || []);
|
||||||
|
const hasAllRequiredScopes = requiredScopes.every(
|
||||||
|
(scope: string) => grantedScopes.has(scope),
|
||||||
|
);
|
||||||
|
if (!hasAllRequiredScopes) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (matchingSystemCreds.length === 1) {
|
||||||
|
const systemCred = matchingSystemCreds[0];
|
||||||
|
credsToAdd[key] = {
|
||||||
|
id: systemCred.id,
|
||||||
|
type: systemCred.type,
|
||||||
|
provider: providerName,
|
||||||
|
title: systemCred.title,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(credsToAdd).length > 0) {
|
||||||
|
hasInitializedSystemCreds.current = true;
|
||||||
|
return {
|
||||||
|
...currentCreds,
|
||||||
|
...credsToAdd,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentCreds;
|
||||||
|
});
|
||||||
|
}, [
|
||||||
|
allProviders,
|
||||||
|
agent.credentials_input_schema,
|
||||||
|
callbacks?.initialInputCredentials,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Reset initialization flag when modal closes/opens or agent changes
|
||||||
|
useEffect(() => {
|
||||||
|
hasInitializedSystemCreds.current = false;
|
||||||
|
}, [isOpen, agent.graph_id]);
|
||||||
|
|
||||||
// API mutations
|
// API mutations
|
||||||
const executeGraphMutation = usePostV1ExecuteGraphAgent({
|
const executeGraphMutation = usePostV1ExecuteGraphAgent({
|
||||||
mutation: {
|
mutation: {
|
||||||
@@ -66,7 +162,6 @@ export function useAgentRunModal(
|
|||||||
toast({
|
toast({
|
||||||
title: "Agent execution started",
|
title: "Agent execution started",
|
||||||
});
|
});
|
||||||
// Invalidate runs list for this graph
|
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: getGetV1ListGraphExecutionsQueryKey(agent.graph_id),
|
queryKey: getGetV1ListGraphExecutionsQueryKey(agent.graph_id),
|
||||||
});
|
});
|
||||||
@@ -163,14 +258,10 @@ export function useAgentRunModal(
|
|||||||
}, [agentInputSchema.required, inputValues]);
|
}, [agentInputSchema.required, inputValues]);
|
||||||
|
|
||||||
const [allCredentialsAreSet, missingCredentials] = useMemo(() => {
|
const [allCredentialsAreSet, missingCredentials] = useMemo(() => {
|
||||||
// Only check required credentials from schema, not all properties
|
|
||||||
// Credentials marked as optional in node metadata won't be in the required array
|
|
||||||
const requiredCredentials = new Set(
|
const requiredCredentials = new Set(
|
||||||
(agent.credentials_input_schema?.required as string[]) || [],
|
(agent.credentials_input_schema?.required as string[]) || [],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check if required credentials have valid id (not just key existence)
|
|
||||||
// A credential is valid only if it has an id field set
|
|
||||||
const missing = [...requiredCredentials].filter((key) => {
|
const missing = [...requiredCredentials].filter((key) => {
|
||||||
const cred = inputCredentials[key];
|
const cred = inputCredentials[key];
|
||||||
return !cred || !cred.id;
|
return !cred || !cred.id;
|
||||||
@@ -184,7 +275,6 @@ export function useAgentRunModal(
|
|||||||
[agentCredentialsInputFields],
|
[agentCredentialsInputFields],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Final readiness flag combining inputs + credentials when credentials are shown
|
|
||||||
const allRequiredInputsAreSet = useMemo(
|
const allRequiredInputsAreSet = useMemo(
|
||||||
() =>
|
() =>
|
||||||
allRequiredInputsAreSetRaw &&
|
allRequiredInputsAreSetRaw &&
|
||||||
@@ -223,7 +313,6 @@ export function useAgentRunModal(
|
|||||||
defaultRunType === "automatic-trigger" ||
|
defaultRunType === "automatic-trigger" ||
|
||||||
defaultRunType === "manual-trigger"
|
defaultRunType === "manual-trigger"
|
||||||
) {
|
) {
|
||||||
// Setup trigger
|
|
||||||
if (!presetName.trim()) {
|
if (!presetName.trim()) {
|
||||||
toast({
|
toast({
|
||||||
title: "⚠️ Trigger name required",
|
title: "⚠️ Trigger name required",
|
||||||
@@ -244,9 +333,6 @@ export function useAgentRunModal(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Manual execution
|
|
||||||
// Filter out incomplete credentials (optional ones not selected)
|
|
||||||
// Only send credentials that have a valid id field
|
|
||||||
const validCredentials = Object.fromEntries(
|
const validCredentials = Object.fromEntries(
|
||||||
Object.entries(inputCredentials).filter(([_, cred]) => cred && cred.id),
|
Object.entries(inputCredentials).filter(([_, cred]) => cred && cred.id),
|
||||||
);
|
);
|
||||||
@@ -280,41 +366,24 @@ export function useAgentRunModal(
|
|||||||
}, [agentInputFields]);
|
}, [agentInputFields]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// UI state
|
|
||||||
isOpen,
|
isOpen,
|
||||||
setIsOpen,
|
setIsOpen,
|
||||||
|
|
||||||
// Run mode
|
|
||||||
defaultRunType: defaultRunType as RunVariant,
|
defaultRunType: defaultRunType as RunVariant,
|
||||||
|
|
||||||
// Form: regular inputs
|
|
||||||
inputValues,
|
inputValues,
|
||||||
setInputValues,
|
setInputValues,
|
||||||
|
|
||||||
// Form: credentials
|
|
||||||
inputCredentials,
|
inputCredentials,
|
||||||
setInputCredentials,
|
setInputCredentials,
|
||||||
|
|
||||||
// Preset/trigger labels
|
|
||||||
presetName,
|
presetName,
|
||||||
presetDescription,
|
presetDescription,
|
||||||
setPresetName,
|
setPresetName,
|
||||||
setPresetDescription,
|
setPresetDescription,
|
||||||
|
|
||||||
// Validation/readiness
|
|
||||||
allRequiredInputsAreSet,
|
allRequiredInputsAreSet,
|
||||||
missingInputs,
|
missingInputs,
|
||||||
|
|
||||||
// Schemas for rendering
|
|
||||||
agentInputFields,
|
agentInputFields,
|
||||||
agentCredentialsInputFields,
|
agentCredentialsInputFields,
|
||||||
hasInputFields,
|
hasInputFields,
|
||||||
|
|
||||||
// Async states
|
|
||||||
isExecuting: executeGraphMutation.isPending,
|
isExecuting: executeGraphMutation.isPending,
|
||||||
isSettingUpTrigger: setupTriggerMutation.isPending,
|
isSettingUpTrigger: setupTriggerMutation.isPending,
|
||||||
|
|
||||||
// Actions
|
|
||||||
handleRun,
|
handleRun,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,17 @@
|
|||||||
import { Button } from "@/components/atoms/Button/Button";
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
import { GearIcon } from "@phosphor-icons/react";
|
import { GearIcon } from "@phosphor-icons/react";
|
||||||
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
|
||||||
import { useAgentSafeMode } from "@/hooks/useAgentSafeMode";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
agent: LibraryAgent;
|
|
||||||
onSelectSettings: () => void;
|
|
||||||
selected?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AgentSettingsButton({
|
|
||||||
agent,
|
|
||||||
onSelectSettings,
|
|
||||||
selected,
|
|
||||||
}: Props) {
|
|
||||||
const { hasHITLBlocks } = useAgentSafeMode(agent);
|
|
||||||
|
|
||||||
if (!hasHITLBlocks) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export function AgentSettingsButton() {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant={selected ? "secondary" : "ghost"}
|
variant="ghost"
|
||||||
size="small"
|
size="small"
|
||||||
className="m-0 min-w-0 rounded-full p-0 px-1"
|
className="m-0 min-w-0 rounded-full p-0 px-1"
|
||||||
onClick={onSelectSettings}
|
|
||||||
aria-label="Agent Settings"
|
aria-label="Agent Settings"
|
||||||
>
|
>
|
||||||
<GearIcon
|
<GearIcon size={18} className="text-zinc-600" />
|
||||||
size={18}
|
<Text variant="small">Agent Settings</Text>
|
||||||
className={selected ? "text-zinc-900" : "text-zinc-600"}
|
|
||||||
/>
|
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
|
||||||
export function EmptySchedules() {
|
export function EmptySchedules() {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
|
||||||
export function EmptyTemplates() {
|
export function EmptyTemplates() {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
|
||||||
export function EmptyTriggers() {
|
export function EmptyTriggers() {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { Button } from "@/components/atoms/Button/Button";
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
|
||||||
interface MarketplaceBannersProps {
|
interface Props {
|
||||||
hasUpdate?: boolean;
|
hasUpdate?: boolean;
|
||||||
latestVersion?: number;
|
latestVersion?: number;
|
||||||
hasUnpublishedChanges?: boolean;
|
hasUnpublishedChanges?: boolean;
|
||||||
@@ -21,7 +21,7 @@ export function MarketplaceBanners({
|
|||||||
isUpdating,
|
isUpdating,
|
||||||
onUpdate,
|
onUpdate,
|
||||||
onPublish,
|
onPublish,
|
||||||
}: MarketplaceBannersProps) {
|
}: Props) {
|
||||||
const renderUpdateBanner = () => {
|
const renderUpdateBanner = () => {
|
||||||
if (hasUpdate && latestVersion) {
|
if (hasUpdate && latestVersion) {
|
||||||
return (
|
return (
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
@@ -1,22 +1,16 @@
|
|||||||
|
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||||
import { Skeleton } from "@/components/__legacy__/ui/skeleton";
|
import { Skeleton } from "@/components/__legacy__/ui/skeleton";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
|
||||||
import { AGENT_LIBRARY_SECTION_PADDING_X } from "../../helpers";
|
import { AGENT_LIBRARY_SECTION_PADDING_X } from "../../helpers";
|
||||||
import { SelectedViewLayout } from "./SelectedViewLayout";
|
import { SelectedViewLayout } from "./SelectedViewLayout";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
agent: LibraryAgent;
|
agent: LibraryAgent;
|
||||||
onSelectSettings?: () => void;
|
|
||||||
selectedSettings?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LoadingSelectedContent(props: Props) {
|
export function LoadingSelectedContent(props: Props) {
|
||||||
return (
|
return (
|
||||||
<SelectedViewLayout
|
<SelectedViewLayout agent={props.agent}>
|
||||||
agent={props.agent}
|
|
||||||
onSelectSettings={props.onSelectSettings}
|
|
||||||
selectedSettings={props.selectedSettings}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
className={cn("flex flex-col gap-4", AGENT_LIBRARY_SECTION_PADDING_X)}
|
className={cn("flex flex-col gap-4", AGENT_LIBRARY_SECTION_PADDING_X)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ interface Props {
|
|||||||
onSelectRun?: (id: string) => void;
|
onSelectRun?: (id: string) => void;
|
||||||
onClearSelectedRun?: () => void;
|
onClearSelectedRun?: () => void;
|
||||||
banner?: React.ReactNode;
|
banner?: React.ReactNode;
|
||||||
onSelectSettings?: () => void;
|
|
||||||
selectedSettings?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SelectedRunView({
|
export function SelectedRunView({
|
||||||
@@ -43,8 +41,6 @@ export function SelectedRunView({
|
|||||||
onSelectRun,
|
onSelectRun,
|
||||||
onClearSelectedRun,
|
onClearSelectedRun,
|
||||||
banner,
|
banner,
|
||||||
onSelectSettings,
|
|
||||||
selectedSettings,
|
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { run, preset, isLoading, responseError, httpError } =
|
const { run, preset, isLoading, responseError, httpError } =
|
||||||
useSelectedRunView(agent.graph_id, runId);
|
useSelectedRunView(agent.graph_id, runId);
|
||||||
@@ -84,12 +80,7 @@ export function SelectedRunView({
|
|||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full gap-4">
|
<div className="flex h-full w-full gap-4">
|
||||||
<div className="flex min-h-0 min-w-0 flex-1 flex-col">
|
<div className="flex min-h-0 min-w-0 flex-1 flex-col">
|
||||||
<SelectedViewLayout
|
<SelectedViewLayout agent={agent} banner={banner}>
|
||||||
agent={agent}
|
|
||||||
banner={banner}
|
|
||||||
onSelectSettings={onSelectSettings}
|
|
||||||
selectedSettings={selectedSettings}
|
|
||||||
>
|
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<RunDetailHeader agent={agent} run={run} />
|
<RunDetailHeader agent={agent} run={run} />
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ interface Props {
|
|||||||
scheduleId: string;
|
scheduleId: string;
|
||||||
onClearSelectedRun?: () => void;
|
onClearSelectedRun?: () => void;
|
||||||
banner?: React.ReactNode;
|
banner?: React.ReactNode;
|
||||||
onSelectSettings?: () => void;
|
|
||||||
selectedSettings?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SelectedScheduleView({
|
export function SelectedScheduleView({
|
||||||
@@ -30,8 +28,6 @@ export function SelectedScheduleView({
|
|||||||
scheduleId,
|
scheduleId,
|
||||||
onClearSelectedRun,
|
onClearSelectedRun,
|
||||||
banner,
|
banner,
|
||||||
onSelectSettings,
|
|
||||||
selectedSettings,
|
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { schedule, isLoading, error } = useSelectedScheduleView(
|
const { schedule, isLoading, error } = useSelectedScheduleView(
|
||||||
agent.graph_id,
|
agent.graph_id,
|
||||||
@@ -76,12 +72,7 @@ export function SelectedScheduleView({
|
|||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full gap-4">
|
<div className="flex h-full w-full gap-4">
|
||||||
<div className="flex min-h-0 min-w-0 flex-1 flex-col">
|
<div className="flex min-h-0 min-w-0 flex-1 flex-col">
|
||||||
<SelectedViewLayout
|
<SelectedViewLayout agent={agent} banner={banner}>
|
||||||
agent={agent}
|
|
||||||
banner={banner}
|
|
||||||
onSelectSettings={onSelectSettings}
|
|
||||||
selectedSettings={selectedSettings}
|
|
||||||
>
|
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="flex w-full flex-col gap-0">
|
<div className="flex w-full flex-col gap-0">
|
||||||
<RunDetailHeader
|
<RunDetailHeader
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
|
||||||
import { Switch } from "@/components/atoms/Switch/Switch";
|
|
||||||
import { Button } from "@/components/atoms/Button/Button";
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
import { ArrowLeftIcon } from "@phosphor-icons/react";
|
import { Switch } from "@/components/atoms/Switch/Switch";
|
||||||
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
import { useAgentSafeMode } from "@/hooks/useAgentSafeMode";
|
import { useAgentSafeMode } from "@/hooks/useAgentSafeMode";
|
||||||
import { SelectedViewLayout } from "../SelectedViewLayout";
|
import { ArrowLeftIcon } from "@phosphor-icons/react";
|
||||||
import { AGENT_LIBRARY_SECTION_PADDING_X } from "../../../helpers";
|
import { AGENT_LIBRARY_SECTION_PADDING_X } from "../../../helpers";
|
||||||
|
import { SelectedViewLayout } from "../SelectedViewLayout";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
agent: LibraryAgent;
|
agent: LibraryAgent;
|
||||||
@@ -17,7 +17,7 @@ export function SelectedSettingsView({ agent, onClearSelectedRun }: Props) {
|
|||||||
useAgentSafeMode(agent);
|
useAgentSafeMode(agent);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectedViewLayout agent={agent} onSelectSettings={() => {}}>
|
<SelectedViewLayout agent={agent}>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div
|
<div
|
||||||
className={`${AGENT_LIBRARY_SECTION_PADDING_X} mb-8 flex items-center gap-3`}
|
className={`${AGENT_LIBRARY_SECTION_PADDING_X} mb-8 flex items-center gap-3`}
|
||||||
@@ -33,15 +33,8 @@ export function SelectedSettingsView({ agent, onClearSelectedRun }: Props) {
|
|||||||
<Text variant="h2">Agent Settings</Text>
|
<Text variant="h2">Agent Settings</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={AGENT_LIBRARY_SECTION_PADDING_X}>
|
<div className={`${AGENT_LIBRARY_SECTION_PADDING_X} space-y-6`}>
|
||||||
{!hasHITLBlocks ? (
|
{hasHITLBlocks ? (
|
||||||
<div className="rounded-xl border border-zinc-100 bg-white p-6">
|
|
||||||
<Text variant="body" className="text-muted-foreground">
|
|
||||||
This agent doesn't have any human-in-the-loop blocks, so
|
|
||||||
there are no settings to configure.
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex w-full max-w-2xl flex-col items-start gap-4 rounded-xl border border-zinc-100 bg-white p-6">
|
<div className="flex w-full max-w-2xl flex-col items-start gap-4 rounded-xl border border-zinc-100 bg-white p-6">
|
||||||
<div className="flex w-full items-start justify-between gap-4">
|
<div className="flex w-full items-start justify-between gap-4">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
@@ -59,6 +52,12 @@ export function SelectedSettingsView({ agent, onClearSelectedRun }: Props) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="rounded-xl border border-zinc-100 bg-white p-6">
|
||||||
|
<Text variant="body" className="text-muted-foreground">
|
||||||
|
This agent doesn't have any configurable settings.
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
getAgentCredentialsFields,
|
getAgentCredentialsFields,
|
||||||
getAgentInputFields,
|
getAgentInputFields,
|
||||||
} from "../../modals/AgentInputsReadOnly/helpers";
|
} from "../../modals/AgentInputsReadOnly/helpers";
|
||||||
import { CredentialsInput } from "../../modals/CredentialsInputs/CredentialsInputs";
|
import { CredentialsInput } from "../../modals/CredentialsInputs/CredentialsInput";
|
||||||
import { RunAgentInputs } from "../../modals/RunAgentInputs/RunAgentInputs";
|
import { RunAgentInputs } from "../../modals/RunAgentInputs/RunAgentInputs";
|
||||||
import { LoadingSelectedContent } from "../LoadingSelectedContent";
|
import { LoadingSelectedContent } from "../LoadingSelectedContent";
|
||||||
import { RunDetailCard } from "../RunDetailCard/RunDetailCard";
|
import { RunDetailCard } from "../RunDetailCard/RunDetailCard";
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
getAgentCredentialsFields,
|
getAgentCredentialsFields,
|
||||||
getAgentInputFields,
|
getAgentInputFields,
|
||||||
} from "../../modals/AgentInputsReadOnly/helpers";
|
} from "../../modals/AgentInputsReadOnly/helpers";
|
||||||
import { CredentialsInput } from "../../modals/CredentialsInputs/CredentialsInputs";
|
import { CredentialsInput } from "../../modals/CredentialsInputs/CredentialsInput";
|
||||||
import { RunAgentInputs } from "../../modals/RunAgentInputs/RunAgentInputs";
|
import { RunAgentInputs } from "../../modals/RunAgentInputs/RunAgentInputs";
|
||||||
import { LoadingSelectedContent } from "../LoadingSelectedContent";
|
import { LoadingSelectedContent } from "../LoadingSelectedContent";
|
||||||
import { RunDetailCard } from "../RunDetailCard/RunDetailCard";
|
import { RunDetailCard } from "../RunDetailCard/RunDetailCard";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Breadcrumbs } from "@/components/molecules/Breadcrumbs/Breadcrumbs";
|
|
||||||
import { AgentSettingsButton } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/other/AgentSettingsButton";
|
|
||||||
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||||
|
import { Breadcrumbs } from "@/components/molecules/Breadcrumbs/Breadcrumbs";
|
||||||
import { AGENT_LIBRARY_SECTION_PADDING_X } from "../../helpers";
|
import { AGENT_LIBRARY_SECTION_PADDING_X } from "../../helpers";
|
||||||
|
import { AgentSettingsModal } from "../modals/AgentSettingsModal/AgentSettingsModal";
|
||||||
import { SectionWrap } from "../other/SectionWrap";
|
import { SectionWrap } from "../other/SectionWrap";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -9,8 +9,6 @@ interface Props {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
banner?: React.ReactNode;
|
banner?: React.ReactNode;
|
||||||
additionalBreadcrumb?: { name: string; link?: string };
|
additionalBreadcrumb?: { name: string; link?: string };
|
||||||
onSelectSettings?: () => void;
|
|
||||||
selectedSettings?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SelectedViewLayout(props: Props) {
|
export function SelectedViewLayout(props: Props) {
|
||||||
@@ -19,8 +17,8 @@ export function SelectedViewLayout(props: Props) {
|
|||||||
<div
|
<div
|
||||||
className={`${AGENT_LIBRARY_SECTION_PADDING_X} flex-shrink-0 border-b border-zinc-100 pb-0 lg:pb-4`}
|
className={`${AGENT_LIBRARY_SECTION_PADDING_X} flex-shrink-0 border-b border-zinc-100 pb-0 lg:pb-4`}
|
||||||
>
|
>
|
||||||
{props.banner && <div className="mb-4">{props.banner}</div>}
|
{props.banner}
|
||||||
<div className="relative flex w-fit items-center gap-2">
|
<div className="relative flex w-full items-center justify-between">
|
||||||
<Breadcrumbs
|
<Breadcrumbs
|
||||||
items={[
|
items={[
|
||||||
{ name: "My Library", link: "/library" },
|
{ name: "My Library", link: "/library" },
|
||||||
@@ -33,15 +31,9 @@ export function SelectedViewLayout(props: Props) {
|
|||||||
: []),
|
: []),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
{props.agent && props.onSelectSettings && (
|
<div className="absolute right-0">
|
||||||
<div className="absolute -right-8">
|
<AgentSettingsModal agent={props.agent} />
|
||||||
<AgentSettingsButton
|
|
||||||
agent={props.agent}
|
|
||||||
onSelectSettings={props.onSelectSettings}
|
|
||||||
selected={props.selectedSettings}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex min-h-0 flex-1 flex-col overflow-y-auto overflow-x-visible">
|
<div className="flex min-h-0 flex-1 flex-col overflow-y-auto overflow-x-visible">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
} from "@/lib/autogpt-server-api";
|
} from "@/lib/autogpt-server-api";
|
||||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||||
|
|
||||||
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs";
|
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInput";
|
||||||
import { RunAgentInputs } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/RunAgentInputs/RunAgentInputs";
|
import { RunAgentInputs } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/RunAgentInputs/RunAgentInputs";
|
||||||
import { ScheduleTaskDialog } from "@/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/cron-scheduler-dialog";
|
import { ScheduleTaskDialog } from "@/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/cron-scheduler-dialog";
|
||||||
import ActionButtonGroup from "@/components/__legacy__/action-button-group";
|
import ActionButtonGroup from "@/components/__legacy__/action-button-group";
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag";
|
|
||||||
import { NewAgentLibraryView } from "./components/NewAgentLibraryView/NewAgentLibraryView";
|
import { NewAgentLibraryView } from "./components/NewAgentLibraryView/NewAgentLibraryView";
|
||||||
import { OldAgentLibraryView } from "./components/OldAgentLibraryView/OldAgentLibraryView";
|
|
||||||
|
|
||||||
export default function AgentLibraryPage() {
|
export default function AgentLibraryPage() {
|
||||||
const isNewLibraryPageEnabled = useGetFlag(Flag.NEW_AGENT_RUNS);
|
return <NewAgentLibraryView />;
|
||||||
return isNewLibraryPageEnabled ? (
|
|
||||||
<NewAgentLibraryView />
|
|
||||||
) : (
|
|
||||||
<OldAgentLibraryView />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2775,6 +2775,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/integrations/providers/system": {
|
||||||
|
"get": {
|
||||||
|
"tags": ["v1", "integrations"],
|
||||||
|
"summary": "List System Providers",
|
||||||
|
"description": "Get a list of providers that have platform credits (system credentials) available.\n\nThese providers can be used without the user providing their own API keys.",
|
||||||
|
"operationId": "getV1ListSystemProviders",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"items": { "type": "string" },
|
||||||
|
"type": "array",
|
||||||
|
"title": "Response Getv1Listsystemproviders"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/integrations/webhooks/{webhook_id}/ping": {
|
"/api/integrations/webhooks/{webhook_id}/ping": {
|
||||||
"post": {
|
"post": {
|
||||||
"tags": ["v1", "integrations"],
|
"tags": ["v1", "integrations"],
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export function Button(props: ButtonProps) {
|
|||||||
rightIcon,
|
rightIcon,
|
||||||
children,
|
children,
|
||||||
as = "button",
|
as = "button",
|
||||||
|
asChild: _asChild, // Destructure to prevent passing to DOM
|
||||||
...restProps
|
...restProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs";
|
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInput";
|
||||||
import { Button } from "@/components/atoms/Button/Button";
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
import { CircleNotchIcon, FolderOpenIcon } from "@phosphor-icons/react";
|
import { CircleNotchIcon, FolderOpenIcon } from "@phosphor-icons/react";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -0,0 +1,203 @@
|
|||||||
|
import type { Meta } from "@storybook/nextjs";
|
||||||
|
import {
|
||||||
|
Accordion,
|
||||||
|
AccordionContent,
|
||||||
|
AccordionItem,
|
||||||
|
AccordionTrigger,
|
||||||
|
} from "./Accordion";
|
||||||
|
|
||||||
|
const meta: Meta<typeof Accordion> = {
|
||||||
|
title: "Molecules/Accordion",
|
||||||
|
component: Accordion,
|
||||||
|
parameters: {
|
||||||
|
layout: "centered",
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
component: `
|
||||||
|
## Accordion Component
|
||||||
|
|
||||||
|
A vertically stacked set of interactive headings that each reveal an associated section of content.
|
||||||
|
|
||||||
|
### ✨ Features
|
||||||
|
|
||||||
|
- **Built on Radix UI** - Uses @radix-ui/react-accordion for accessibility and functionality
|
||||||
|
- **Single or multiple** - Supports single or multiple items open at once
|
||||||
|
- **Smooth animations** - Built-in expand/collapse animations
|
||||||
|
- **Accessible** - Full keyboard navigation and screen reader support
|
||||||
|
- **Customizable** - Style with Tailwind CSS classes
|
||||||
|
|
||||||
|
### 🎯 Usage
|
||||||
|
|
||||||
|
\`\`\`tsx
|
||||||
|
<Accordion type="single" collapsible>
|
||||||
|
<AccordionItem value="item-1">
|
||||||
|
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
Yes. It adheres to the WAI-ARIA design pattern.
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
**Accordion**:
|
||||||
|
- **type**: "single" | "multiple" - Whether one or multiple items can be open
|
||||||
|
- **collapsible**: boolean - When type is "single", allows closing all items
|
||||||
|
- **defaultValue**: string | string[] - Default open item(s)
|
||||||
|
- **value**: string | string[] - Controlled open item(s)
|
||||||
|
- **onValueChange**: (value) => void - Callback when value changes
|
||||||
|
|
||||||
|
**AccordionItem**:
|
||||||
|
- **value**: string - Unique identifier for the item
|
||||||
|
- **disabled**: boolean - Whether the item is disabled
|
||||||
|
|
||||||
|
**AccordionTrigger**:
|
||||||
|
- Standard button props
|
||||||
|
|
||||||
|
**AccordionContent**:
|
||||||
|
- Standard div props
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tags: ["autodocs"],
|
||||||
|
argTypes: {
|
||||||
|
type: {
|
||||||
|
control: "radio",
|
||||||
|
options: ["single", "multiple"],
|
||||||
|
description: "Whether one or multiple items can be open at the same time",
|
||||||
|
table: {
|
||||||
|
defaultValue: { summary: "single" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
collapsible: {
|
||||||
|
control: "boolean",
|
||||||
|
description:
|
||||||
|
'When type is "single", allows closing content when clicking on open trigger',
|
||||||
|
table: {
|
||||||
|
defaultValue: { summary: "false" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
export function Default() {
|
||||||
|
return (
|
||||||
|
<Accordion type="single" collapsible className="w-96">
|
||||||
|
<AccordionItem value="item-1">
|
||||||
|
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
Yes. It adheres to the WAI-ARIA design pattern.
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="item-2">
|
||||||
|
<AccordionTrigger>Is it styled?</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
Yes. It comes with default styles that match your design system.
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="item-3">
|
||||||
|
<AccordionTrigger>Is it animated?</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
Yes. It's animated by default with smooth expand/collapse
|
||||||
|
transitions.
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Multiple() {
|
||||||
|
return (
|
||||||
|
<Accordion type="multiple" className="w-96">
|
||||||
|
<AccordionItem value="item-1">
|
||||||
|
<AccordionTrigger>First section</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
Multiple items can be open at the same time when type is set to
|
||||||
|
"multiple".
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="item-2">
|
||||||
|
<AccordionTrigger>Second section</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
Try opening this one while the first is still open.
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="item-3">
|
||||||
|
<AccordionTrigger>Third section</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
All three can be open simultaneously.
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DefaultOpen() {
|
||||||
|
return (
|
||||||
|
<Accordion type="single" collapsible defaultValue="item-2" className="w-96">
|
||||||
|
<AccordionItem value="item-1">
|
||||||
|
<AccordionTrigger>Closed by default</AccordionTrigger>
|
||||||
|
<AccordionContent>This item starts closed.</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="item-2">
|
||||||
|
<AccordionTrigger>Open by default</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
This item starts open because defaultValue is set to
|
||||||
|
"item-2".
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="item-3">
|
||||||
|
<AccordionTrigger>Also closed</AccordionTrigger>
|
||||||
|
<AccordionContent>This item also starts closed.</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WithDisabledItem() {
|
||||||
|
return (
|
||||||
|
<Accordion type="single" collapsible className="w-96">
|
||||||
|
<AccordionItem value="item-1">
|
||||||
|
<AccordionTrigger>Available item</AccordionTrigger>
|
||||||
|
<AccordionContent>This item can be toggled.</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="item-2" disabled>
|
||||||
|
<AccordionTrigger>Disabled item</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
This content cannot be accessed because the item is disabled.
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="item-3">
|
||||||
|
<AccordionTrigger>Another available item</AccordionTrigger>
|
||||||
|
<AccordionContent>This item can also be toggled.</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CustomStyled() {
|
||||||
|
return (
|
||||||
|
<Accordion type="single" collapsible className="w-96">
|
||||||
|
<AccordionItem value="item-1" className="border-none">
|
||||||
|
<AccordionTrigger className="rounded-lg bg-zinc-100 px-4 hover:bg-zinc-200 hover:no-underline">
|
||||||
|
Custom styled trigger
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="px-4 pt-2">
|
||||||
|
You can customize the styling using className props.
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="item-2" className="mt-2 border-none">
|
||||||
|
<AccordionTrigger className="rounded-lg bg-blue-50 px-4 text-blue-700 hover:bg-blue-100 hover:no-underline">
|
||||||
|
Blue themed
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="px-4 pt-2 text-blue-600">
|
||||||
|
Each item can have different styles.
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Accordion,
|
||||||
|
AccordionContent,
|
||||||
|
AccordionItem,
|
||||||
|
AccordionTrigger,
|
||||||
|
} from "@/components/ui/accordion";
|
||||||
@@ -22,6 +22,9 @@ export function DrawerWrap({
|
|||||||
handleClose,
|
handleClose,
|
||||||
isForceOpen,
|
isForceOpen,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const accessibleTitle = title ?? "Dialog";
|
||||||
|
const hasVisibleTitle = Boolean(title);
|
||||||
|
|
||||||
const closeBtn = (
|
const closeBtn = (
|
||||||
<Button
|
<Button
|
||||||
variant="link"
|
variant="link"
|
||||||
@@ -44,15 +47,19 @@ export function DrawerWrap({
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`flex w-full shrink-0 items-center justify-between ${
|
className={`flex w-full shrink-0 items-center justify-between ${
|
||||||
title ? "pb-6" : "pb-0"
|
hasVisibleTitle ? "pb-6" : "pb-0"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{title ? (
|
{hasVisibleTitle ? (
|
||||||
<Drawer.Title className={drawerStyles.title}>{title}</Drawer.Title>
|
<Drawer.Title className={drawerStyles.title}>
|
||||||
) : null}
|
{accessibleTitle}
|
||||||
|
</Drawer.Title>
|
||||||
|
) : (
|
||||||
|
<Drawer.Title className="sr-only">{accessibleTitle}</Drawer.Title>
|
||||||
|
)}
|
||||||
|
|
||||||
{!isForceOpen ? (
|
{!isForceOpen ? (
|
||||||
title ? (
|
hasVisibleTitle ? (
|
||||||
closeBtn
|
closeBtn
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import React, { useMemo } from "react";
|
import { useNodeStore } from "@/app/(platform)/build/stores/nodeStore";
|
||||||
import { FieldProps, getUiOptions } from "@rjsf/utils";
|
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInput";
|
||||||
|
import { Switch } from "@/components/atoms/Switch/Switch";
|
||||||
import {
|
import {
|
||||||
BlockIOCredentialsSubSchema,
|
BlockIOCredentialsSubSchema,
|
||||||
CredentialsMetaInput,
|
CredentialsMetaInput,
|
||||||
} from "@/lib/autogpt-server-api";
|
} from "@/lib/autogpt-server-api";
|
||||||
import { CredentialsInput } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs";
|
import { FieldProps, getUiOptions } from "@rjsf/utils";
|
||||||
import { useNodeStore } from "@/app/(platform)/build/stores/nodeStore";
|
import { useMemo } from "react";
|
||||||
import { useShallow } from "zustand/react/shallow";
|
import { useShallow } from "zustand/react/shallow";
|
||||||
import { CredentialFieldTitle } from "./components/CredentialFieldTitle";
|
import { CredentialFieldTitle } from "./components/CredentialFieldTitle";
|
||||||
import { Switch } from "@/components/atoms/Switch/Switch";
|
|
||||||
|
|
||||||
export const CredentialsField = (props: FieldProps) => {
|
export const CredentialsField = (props: FieldProps) => {
|
||||||
const { formData, onChange, schema, registry, fieldPathId, required } = props;
|
const { formData, onChange, schema, registry, fieldPathId, required } = props;
|
||||||
|
|||||||
57
autogpt_platform/frontend/src/components/ui/accordion.tsx
Normal file
57
autogpt_platform/frontend/src/components/ui/accordion.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import * as AccordionPrimitive from "@radix-ui/react-accordion";
|
||||||
|
import { ChevronDown } from "lucide-react";
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
const Accordion = AccordionPrimitive.Root;
|
||||||
|
|
||||||
|
const AccordionItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AccordionPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AccordionPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn("border-b", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
AccordionItem.displayName = "AccordionItem";
|
||||||
|
|
||||||
|
const AccordionTrigger = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<AccordionPrimitive.Header className="flex">
|
||||||
|
<AccordionPrimitive.Trigger
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex flex-1 items-center justify-between py-4 text-left text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<ChevronDown className="h-4 w-4 shrink-0 text-neutral-500 transition-transform duration-200 dark:text-neutral-400" />
|
||||||
|
</AccordionPrimitive.Trigger>
|
||||||
|
</AccordionPrimitive.Header>
|
||||||
|
));
|
||||||
|
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
|
const AccordionContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AccordionPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<AccordionPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<div className={cn("pb-4 pt-0", className)}>{children}</div>
|
||||||
|
</AccordionPrimitive.Content>
|
||||||
|
));
|
||||||
|
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
|
||||||
|
|
||||||
|
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
|
||||||
@@ -352,6 +352,10 @@ export default class BackendAPI {
|
|||||||
return this._get("/integrations/providers");
|
return this._get("/integrations/providers");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listSystemProviders(): Promise<string[]> {
|
||||||
|
return this._get("/integrations/providers/system");
|
||||||
|
}
|
||||||
|
|
||||||
listCredentials(provider?: string): Promise<CredentialsMetaResponse[]> {
|
listCredentials(provider?: string): Promise<CredentialsMetaResponse[]> {
|
||||||
return this._get(
|
return this._get(
|
||||||
provider
|
provider
|
||||||
|
|||||||
@@ -593,6 +593,7 @@ export type CredentialsMetaResponse = {
|
|||||||
scopes?: Array<string>;
|
scopes?: Array<string>;
|
||||||
username?: string;
|
username?: string;
|
||||||
host?: string;
|
host?: string;
|
||||||
|
is_system?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mirror of backend/server/integrations/router.py:CredentialsDeletionResponse */
|
/* Mirror of backend/server/integrations/router.py:CredentialsDeletionResponse */
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { createContext, useCallback, useEffect, useState } from "react";
|
import { useToastOnFail } from "@/components/molecules/Toast/use-toast";
|
||||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
|
||||||
import {
|
import {
|
||||||
APIKeyCredentials,
|
APIKeyCredentials,
|
||||||
CredentialsDeleteNeedConfirmationResponse,
|
CredentialsDeleteNeedConfirmationResponse,
|
||||||
@@ -10,8 +9,9 @@ import {
|
|||||||
UserPasswordCredentials,
|
UserPasswordCredentials,
|
||||||
} from "@/lib/autogpt-server-api";
|
} from "@/lib/autogpt-server-api";
|
||||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||||
import { useToastOnFail } from "@/components/molecules/Toast/use-toast";
|
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||||
import { toDisplayName } from "@/providers/agent-credentials/helper";
|
import { toDisplayName } from "@/providers/agent-credentials/helper";
|
||||||
|
import { createContext, useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
type APIKeyCredentialsCreatable = Omit<
|
type APIKeyCredentialsCreatable = Omit<
|
||||||
APIKeyCredentials,
|
APIKeyCredentials,
|
||||||
@@ -32,6 +32,8 @@ export type CredentialsProviderData = {
|
|||||||
provider: CredentialsProviderName;
|
provider: CredentialsProviderName;
|
||||||
providerName: string;
|
providerName: string;
|
||||||
savedCredentials: CredentialsMetaResponse[];
|
savedCredentials: CredentialsMetaResponse[];
|
||||||
|
/** Whether this provider has platform credits available (system credentials) */
|
||||||
|
isSystemProvider: boolean;
|
||||||
oAuthCallback: (
|
oAuthCallback: (
|
||||||
code: string,
|
code: string,
|
||||||
state_token: string,
|
state_token: string,
|
||||||
@@ -68,6 +70,9 @@ export default function CredentialsProvider({
|
|||||||
const [providers, setProviders] =
|
const [providers, setProviders] =
|
||||||
useState<CredentialsProvidersContextType | null>(null);
|
useState<CredentialsProvidersContextType | null>(null);
|
||||||
const [providerNames, setProviderNames] = useState<string[]>([]);
|
const [providerNames, setProviderNames] = useState<string[]>([]);
|
||||||
|
const [systemProviders, setSystemProviders] = useState<Set<string>>(
|
||||||
|
new Set(),
|
||||||
|
);
|
||||||
const { isLoggedIn } = useSupabase();
|
const { isLoggedIn } = useSupabase();
|
||||||
const api = useBackendAPI();
|
const api = useBackendAPI();
|
||||||
const onFailToast = useToastOnFail();
|
const onFailToast = useToastOnFail();
|
||||||
@@ -218,17 +223,7 @@ export default function CredentialsProvider({
|
|||||||
[api, onFailToast],
|
[api, onFailToast],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Fetch provider names on mount
|
const loadCredentials = useCallback(() => {
|
||||||
useEffect(() => {
|
|
||||||
api
|
|
||||||
.listProviders()
|
|
||||||
.then((names) => {
|
|
||||||
setProviderNames(names);
|
|
||||||
})
|
|
||||||
.catch(onFailToast("load provider names"));
|
|
||||||
}, [api, onFailToast]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isLoggedIn || providerNames.length === 0) {
|
if (!isLoggedIn || providerNames.length === 0) {
|
||||||
if (isLoggedIn == false) setProviders({});
|
if (isLoggedIn == false) setProviders({});
|
||||||
return;
|
return;
|
||||||
@@ -251,12 +246,16 @@ export default function CredentialsProvider({
|
|||||||
setProviders((prev) => ({
|
setProviders((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
...Object.fromEntries(
|
...Object.fromEntries(
|
||||||
providerNames.map((provider) => [
|
providerNames.map((provider) => {
|
||||||
|
const providerCredentials = credentialsByProvider[provider] ?? [];
|
||||||
|
|
||||||
|
return [
|
||||||
provider,
|
provider,
|
||||||
{
|
{
|
||||||
provider,
|
provider,
|
||||||
providerName: toDisplayName(provider as string),
|
providerName: toDisplayName(provider as string),
|
||||||
savedCredentials: credentialsByProvider[provider] ?? [],
|
savedCredentials: providerCredentials,
|
||||||
|
isSystemProvider: systemProviders.has(provider),
|
||||||
oAuthCallback: (code: string, state_token: string) =>
|
oAuthCallback: (code: string, state_token: string) =>
|
||||||
oAuthCallback(provider, code, state_token),
|
oAuthCallback(provider, code, state_token),
|
||||||
createAPIKeyCredentials: (
|
createAPIKeyCredentials: (
|
||||||
@@ -271,7 +270,8 @@ export default function CredentialsProvider({
|
|||||||
deleteCredentials: (id: string, force: boolean = false) =>
|
deleteCredentials: (id: string, force: boolean = false) =>
|
||||||
deleteCredentials(provider, id, force),
|
deleteCredentials(provider, id, force),
|
||||||
} satisfies CredentialsProviderData,
|
} satisfies CredentialsProviderData,
|
||||||
]),
|
];
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
@@ -280,6 +280,7 @@ export default function CredentialsProvider({
|
|||||||
api,
|
api,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
providerNames,
|
providerNames,
|
||||||
|
systemProviders,
|
||||||
createAPIKeyCredentials,
|
createAPIKeyCredentials,
|
||||||
createUserPasswordCredentials,
|
createUserPasswordCredentials,
|
||||||
createHostScopedCredentials,
|
createHostScopedCredentials,
|
||||||
@@ -288,6 +289,20 @@ export default function CredentialsProvider({
|
|||||||
onFailToast,
|
onFailToast,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Fetch provider names and system providers on mount
|
||||||
|
useEffect(() => {
|
||||||
|
Promise.all([api.listProviders(), api.listSystemProviders()])
|
||||||
|
.then(([names, systemList]) => {
|
||||||
|
setProviderNames(names);
|
||||||
|
setSystemProviders(new Set(systemList));
|
||||||
|
})
|
||||||
|
.catch(onFailToast("Load provider names"));
|
||||||
|
}, [api, onFailToast]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadCredentials();
|
||||||
|
}, [loadCredentials]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CredentialsProvidersContext.Provider value={providers}>
|
<CredentialsProvidersContext.Provider value={providers}>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -22,13 +22,7 @@ const config = {
|
|||||||
poppins: ["var(--font-poppins)"],
|
poppins: ["var(--font-poppins)"],
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
// *** APPROVED DESIGN SYSTEM COLORS ***
|
|
||||||
// These are the ONLY colors that should be used in our app
|
|
||||||
...colors,
|
...colors,
|
||||||
|
|
||||||
// Legacy colors - DO NOT USE THESE IN NEW CODE
|
|
||||||
// These are kept only to prevent breaking existing styles
|
|
||||||
// Use the approved design system colors above instead
|
|
||||||
border: "hsl(var(--border))",
|
border: "hsl(var(--border))",
|
||||||
input: "hsl(var(--input))",
|
input: "hsl(var(--input))",
|
||||||
ring: "hsl(var(--ring))",
|
ring: "hsl(var(--ring))",
|
||||||
@@ -63,70 +57,66 @@ const config = {
|
|||||||
foreground: "hsl(var(--card-foreground))",
|
foreground: "hsl(var(--card-foreground))",
|
||||||
},
|
},
|
||||||
customGray: {
|
customGray: {
|
||||||
100: "#d9d9d9",
|
"100": "#d9d9d9",
|
||||||
200: "#a8a8a8",
|
"200": "#a8a8a8",
|
||||||
300: "#878787",
|
"300": "#878787",
|
||||||
400: "#646464",
|
"400": "#646464",
|
||||||
500: "#474747",
|
"500": "#474747",
|
||||||
600: "#282828",
|
"600": "#282828",
|
||||||
700: "#272727",
|
"700": "#272727",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
spacing: {
|
spacing: {
|
||||||
// Tailwind spacing + custom sizes
|
"0": "0rem",
|
||||||
0: "0rem", // 0px
|
"1": "0.25rem",
|
||||||
0.5: "0.125rem", // 2px
|
"2": "0.5rem",
|
||||||
1: "0.25rem", // 4px
|
"3": "0.75rem",
|
||||||
1.5: "0.375rem", // 6px
|
"4": "1rem",
|
||||||
2: "0.5rem", // 8px
|
"5": "1.25rem",
|
||||||
2.5: "0.625rem", // 10px
|
"6": "1.5rem",
|
||||||
3: "0.75rem", // 12px
|
"7": "1.75rem",
|
||||||
3.5: "0.875rem", // 14px
|
"8": "2rem",
|
||||||
4: "1rem", // 16px
|
"9": "2.25rem",
|
||||||
5: "1.25rem", // 20px
|
"10": "2.5rem",
|
||||||
6: "1.5rem", // 24px
|
"11": "2.75rem",
|
||||||
7: "1.75rem", // 28px
|
"12": "3rem",
|
||||||
7.5: "1.875rem", // 30px
|
"14": "3.5rem",
|
||||||
8: "2rem", // 32px
|
"16": "4rem",
|
||||||
8.5: "2.125rem", // 34px
|
"18": "4.5rem",
|
||||||
9: "2.25rem", // 36px
|
"20": "5rem",
|
||||||
10: "2.5rem", // 40px
|
"24": "6rem",
|
||||||
11: "2.75rem", // 44px
|
"28": "7rem",
|
||||||
12: "3rem", // 48px
|
"32": "8rem",
|
||||||
14: "3.5rem", // 56px
|
"36": "9rem",
|
||||||
16: "4rem", // 64px
|
"40": "10rem",
|
||||||
18: "4.5rem", // 72px
|
"44": "11rem",
|
||||||
20: "5rem", // 80px
|
"48": "12rem",
|
||||||
24: "6rem", // 96px
|
"52": "13rem",
|
||||||
28: "7rem", // 112px
|
"56": "14rem",
|
||||||
32: "8rem", // 128px
|
"60": "15rem",
|
||||||
36: "9rem", // 144px
|
"64": "16rem",
|
||||||
40: "10rem", // 160px
|
"68": "17rem",
|
||||||
44: "11rem", // 176px
|
"70": "17.5rem",
|
||||||
48: "12rem", // 192px
|
"71": "17.75rem",
|
||||||
52: "13rem", // 208px
|
"72": "18rem",
|
||||||
56: "14rem", // 224px
|
"76": "19rem",
|
||||||
60: "15rem", // 240px
|
"80": "20rem",
|
||||||
64: "16rem", // 256px
|
"96": "24rem",
|
||||||
68: "17rem", // 272px
|
"0.5": "0.125rem",
|
||||||
70: "17.5rem", // 280px
|
"1.5": "0.375rem",
|
||||||
71: "17.75rem", // 284px
|
"2.5": "0.625rem",
|
||||||
72: "18rem", // 288px
|
"3.5": "0.875rem",
|
||||||
76: "19rem", // 304px
|
"7.5": "1.875rem",
|
||||||
80: "20rem", // 320px
|
"8.5": "2.125rem",
|
||||||
96: "24rem", // 384px
|
|
||||||
},
|
},
|
||||||
borderRadius: {
|
borderRadius: {
|
||||||
// Design system border radius tokens from Figma
|
xsmall: "0.25rem",
|
||||||
xsmall: "0.25rem", // 4px
|
small: "0.5rem",
|
||||||
small: "0.5rem", // 8px
|
medium: "0.75rem",
|
||||||
medium: "0.75rem", // 12px
|
large: "1rem",
|
||||||
large: "1rem", // 16px
|
xlarge: "1.25rem",
|
||||||
xlarge: "1.25rem", // 20px
|
"2xlarge": "1.5rem",
|
||||||
"2xlarge": "1.5rem", // 24px
|
full: "9999px",
|
||||||
full: "9999px", // For pill buttons
|
|
||||||
|
|
||||||
// Legacy values - kept for backward compatibility
|
|
||||||
lg: "var(--radius)",
|
lg: "var(--radius)",
|
||||||
md: "calc(var(--radius) - 2px)",
|
md: "calc(var(--radius) - 2px)",
|
||||||
sm: "calc(var(--radius) - 4px)",
|
sm: "calc(var(--radius) - 4px)",
|
||||||
@@ -136,16 +126,28 @@ const config = {
|
|||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
"accordion-down": {
|
"accordion-down": {
|
||||||
from: { height: "0" },
|
from: {
|
||||||
to: { height: "var(--radix-accordion-content-height)" },
|
height: "0",
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
height: "var(--radix-accordion-content-height)",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"accordion-up": {
|
"accordion-up": {
|
||||||
from: { height: "var(--radix-accordion-content-height)" },
|
from: {
|
||||||
to: { height: "0" },
|
height: "var(--radix-accordion-content-height)",
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
height: "0",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"fade-in": {
|
"fade-in": {
|
||||||
"0%": { opacity: "0" }, // Start with opacity 0
|
"0%": {
|
||||||
"100%": { opacity: "1" }, // End with opacity 1
|
opacity: "0",
|
||||||
|
},
|
||||||
|
"100%": {
|
||||||
|
opacity: "1",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
animation: {
|
animation: {
|
||||||
|
|||||||
Reference in New Issue
Block a user