diff --git a/apps/file-gateway-api/go.mod b/apps/file-gateway-api/go.mod index 073b869..71131c4 100644 --- a/apps/file-gateway-api/go.mod +++ b/apps/file-gateway-api/go.mod @@ -3,9 +3,9 @@ module github.com/blocknextai/file-gateway-api go 1.26.5 require ( - github.com/aws/aws-sdk-go-v2 v1.43.3 - github.com/aws/aws-sdk-go-v2/credentials v1.19.33 - github.com/aws/aws-sdk-go-v2/service/s3 v1.106.4 + github.com/aws/aws-sdk-go-v2 v1.43.4 + github.com/aws/aws-sdk-go-v2/credentials v1.19.34 + github.com/aws/aws-sdk-go-v2/service/s3 v1.107.0 github.com/blocknextai/go-packages v0.0.0 github.com/caarlos0/env/v11 v11.4.1 github.com/gofiber/fiber/v3 v3.4.0 @@ -14,21 +14,21 @@ require ( require ( github.com/andybalholm/brotli v1.2.2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35 // indirect - github.com/aws/smithy-go v1.27.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.28 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.36 // indirect + github.com/aws/smithy-go v1.27.7 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/gabriel-vasile/mimetype v1.4.15 // indirect github.com/gofiber/schema v1.8.3 // indirect github.com/gofiber/utils/v2 v2.4.1 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.19.1 // indirect + github.com/klauspost/compress v1.19.2 // indirect github.com/mattn/go-colorable v0.1.15 // indirect github.com/mattn/go-isatty v0.0.24 // indirect github.com/philhofer/fwd v1.2.0 // indirect diff --git a/apps/file-gateway-api/go.sum b/apps/file-gateway-api/go.sum index f435184..89d002f 100644 --- a/apps/file-gateway-api/go.sum +++ b/apps/file-gateway-api/go.sum @@ -1,29 +1,29 @@ github.com/andybalholm/brotli v1.2.2 h1:HzTuoo2ErYQqf5qvcJInB8uvqSVxRttzkFexPWtnceM= github.com/andybalholm/brotli v1.2.2/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= -github.com/aws/aws-sdk-go-v2 v1.43.3 h1:XJIcfv8uDs2ukdQsoAC8/Ebu1ejxwzlayl2ZsiFns2A= -github.com/aws/aws-sdk-go-v2 v1.43.3/go.mod h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ= +github.com/aws/aws-sdk-go-v2 v1.43.4 h1:b9FTvbRwy+JCsfp2Wp6wV/KbOx3Aj7nkoFb2cRX0IhE= +github.com/aws/aws-sdk-go-v2 v1.43.4/go.mod h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 h1:aiuaKlDweRC5qExJondpWjOgyzMHpofpwspGXUtwn4c= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16/go.mod h1:nG/LOlmox9BDe9HvQnXWzgcK8uKbgBMZ/Hp5pVt/21I= -github.com/aws/aws-sdk-go-v2/credentials v1.19.33 h1:/e5V3EWfeDiW6cuRxHsC8gbwko4/vvVYPJR2afBKFFY= -github.com/aws/aws-sdk-go-v2/credentials v1.19.33/go.mod h1:ZxAmkcyOM9beY/WO9oxp2oVPXiP3rq5N1/p4NbenJdE= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34 h1:vuIfjzoeqhQMGJyOBU3t0ZEjn2jrN8Bbg1N4CgjzM5Q= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34/go.mod h1:hP28cN4CPJLZHirdQPrZR50JcLN4ApRJP2tzG8cRlhY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34 h1:9faHsnqxJ1vDvB4wMZy/ajIDyz5QhllQjjc72RJpXAw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34/go.mod h1:Yp6nIyejpa23nzlB/LhT63KTla9Jdi06nv/HH/OkAH8= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35 h1:Oe8gMKJLO5awqpa5EhAGKVnBv1s+brdWVuxM2mDa7zA= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35/go.mod h1:FZevcG9cOST/FWAAUhHIchjR9fXFXFRCWodOhx+PDLA= +github.com/aws/aws-sdk-go-v2/credentials v1.19.34 h1:y6GkSmcv5myd1ngrYbGmiLlwQqB6TQhOuN/tbSSuWDY= +github.com/aws/aws-sdk-go-v2/credentials v1.19.34/go.mod h1:w3dTcnDVoQIewjo7JG45hduAToikiIFLC4FIO7fndvw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 h1:kzVuGlatQtYinwBJEEyLAbggepCoavosiaHHX9+fD+c= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35/go.mod h1:0yLx0yEI+SfqeJMPvOtIEFoZbiQYXMGszBueiutQyaI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 h1:WK6CjihTuLisCjSKKbildJ79sGZZgbBz3iNa7VsKIhU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35/go.mod h1:KYleN57luLoe97R7vTnx8PMcVrr9gAcRECtOjl91DNg= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36 h1:jbGY4CXLzZElOXgGsexlC3Hi+3YM0rSmk4opFXKqg/k= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36/go.mod h1:uBu/9aKsS/UQGc72RAt3y54kjgYQxmhut8ZD2dXCDNE= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 h1:JJLBQxwY+AFwuPAi5ivGc1ChnTdUt4cXMv7e76m2c/Y= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15/go.mod h1:lQknBIe78MVL0cQOQDlag8KGflMbMEVFx9mB6O8ENvk= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27 h1:zwB6ltUc0UiyOsRQaMQ8jNLjKECbjhadCyl4hqV0y/c= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27/go.mod h1:ce9y+Y+hGLUyPKJZZJGoFLuFJNfCNuWZTujUJAsckQA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34 h1:sYg4qHWLqsjp15PzX7XCOHSOgKEGoZ5vQY43VvZ1pas= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34/go.mod h1:N58SSz3roKf1HzW5qRaOiyk6MbDLTKgLPvlTfJ90iyI= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35 h1:ohfdSAm4TA6nryIY7mLqe4mnSIAnAreoAPBM81ZVoIM= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35/go.mod h1:uUjphnxMb3HH3vIiOHl4dH0fGNKL+csjqRQEabbfw5k= -github.com/aws/aws-sdk-go-v2/service/s3 v1.106.4 h1:nN+nb2rhWmPOMwFA+e6xDJZJ0h/VAI39XVBzn52Fn8A= -github.com/aws/aws-sdk-go-v2/service/s3 v1.106.4/go.mod h1:lWk6L5Q3YkaC7so1bQUJkvF7hj2KUFzdZ4w15wc2GHY= -github.com/aws/smithy-go v1.27.6 h1:0zjT8jgK3jbrTT7JJ3EE6JsMhX8JTrZ+f1sEndYDXrA= -github.com/aws/smithy-go v1.27.6/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.28 h1:Q1TF1J9jVD+vFo0LzNnmNdQ9EAt52TS+MQlq9Ir+Yxo= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.28/go.mod h1:4KqXXC/p1hrotmouDFbrRoWaLy962b9PMUReCG6+uWo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35 h1:BBEElKh4a+rKshvjrfpajTe9CbpZvrbb4Jkg2PB7RzA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35/go.mod h1:zaZk983w//8beSruBVec/mr4CmDwgZitW/qzGhAAX0g= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.36 h1:EUIwBoN+q7UmhAejxgD27APiRjh1vwCFo53gSqdT0BM= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.36/go.mod h1:6u00gmlTGR6W0b2k9NBrld7MnOEmf1Spqx0VVt6AqyE= +github.com/aws/aws-sdk-go-v2/service/s3 v1.107.0 h1:OkYV+1171za+ab9otU1tGxMXhx6uZvwVEtVddjLuYTg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.107.0/go.mod h1:5FTZoQxhmLEiCAtYVk6V+t0iS/B5yGZVLZ3Wq5FDJZI= +github.com/aws/smithy-go v1.27.7 h1:Zgj5z4LfcDYoQIVk+n/yGdTkP/2y6ZT5vYxe0fp7bqE= +github.com/aws/smithy-go v1.27.7/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= @@ -48,8 +48,8 @@ github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63Y github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= -github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= +github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw= github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= diff --git a/apps/platform-api/go.mod b/apps/platform-api/go.mod index 1fa9859..1ff9316 100644 --- a/apps/platform-api/go.mod +++ b/apps/platform-api/go.mod @@ -15,7 +15,7 @@ require ( github.com/modelcontextprotocol/go-sdk v1.7.0 github.com/redis/go-redis/v9 v9.22.0 github.com/robfig/cron/v3 v3.0.1 - github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 + github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 github.com/valyala/fasthttp v1.73.0 ) @@ -30,7 +30,7 @@ require ( github.com/gofiber/utils/v2 v2.4.1 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/holiman/uint256 v1.3.2 // indirect - github.com/klauspost/compress v1.19.1 // indirect + github.com/klauspost/compress v1.19.2 // indirect github.com/mattn/go-colorable v0.1.15 // indirect github.com/mattn/go-isatty v0.0.24 // indirect github.com/philhofer/fwd v1.2.0 // indirect diff --git a/apps/platform-api/go.sum b/apps/platform-api/go.sum index bf0c814..0258f09 100644 --- a/apps/platform-api/go.sum +++ b/apps/platform-api/go.sum @@ -70,8 +70,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= -github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= -github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= +github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw= github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU= github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ= @@ -102,8 +102,8 @@ github.com/redis/go-redis/v9 v9.22.0 h1:laDvpYXTJtZLloinw1fA5Kqd6HAEH2XKxOkG/PDq github.com/redis/go-redis/v9 v9.22.0/go.mod h1:y2g0Wj8rQvuK0ELM+oxSudcLtC09JScs98I/X9gRWY4= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/savsgio/gotils v0.0.0-20250924091648-bce9a52d7761 h1:McifyVxygw1d67y6vxUqls2D46J8W9nrki9c8c0eVvE= github.com/savsgio/gotils v0.0.0-20250924091648-bce9a52d7761/go.mod h1:Vi9gvHvTw4yCUHIznFl5TPULS7aXwgaTByGeBY75Wko= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= diff --git a/apps/platform-api/internal/mcp/application/getallservers/mapper.go b/apps/platform-api/internal/mcp/application/getallservers/mapper.go index da6384e..c5b3aef 100644 --- a/apps/platform-api/internal/mcp/application/getallservers/mapper.go +++ b/apps/platform-api/internal/mcp/application/getallservers/mapper.go @@ -17,6 +17,7 @@ func MapGetAllServersQueryToGetAllServersResponse( ID: server.GetID(), Name: server.GetName(), Description: server.GetDescription(), + Icon: server.GetIcon(), Version: server.GetVersion(), Instructions: server.GetInstructions(), URL: url, diff --git a/apps/platform-api/internal/mcp/application/getallservers/response.go b/apps/platform-api/internal/mcp/application/getallservers/response.go index 4365bf5..64e5346 100644 --- a/apps/platform-api/internal/mcp/application/getallservers/response.go +++ b/apps/platform-api/internal/mcp/application/getallservers/response.go @@ -1,6 +1,7 @@ package getallservers import ( + nodeEngineDomainMCP "github.com/blocknextai/platform-api/internal/nodeengine/domain/mcp" nodeEngineDomainNodes "github.com/blocknextai/platform-api/internal/nodeengine/domain/nodes" ) @@ -8,6 +9,7 @@ type ServerResponse struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` + Icon nodeEngineDomainMCP.ServerIcon `json:"icon,omitzero"` Version string `json:"version,omitempty"` Instructions string `json:"instructions,omitempty"` URL string `json:"url,omitempty"` diff --git a/apps/platform-api/internal/nodeengine/credentials/airtable_api.go b/apps/platform-api/internal/nodeengine/credentials/airtable_api.go index 8b48afb..9899eaf 100644 --- a/apps/platform-api/internal/nodeengine/credentials/airtable_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/airtable_api.go @@ -12,8 +12,7 @@ func NewAirtableAPICredential() *domain.Credential { Name: "Airtable", Description: "Airtable personal access token domain.", Icon: domain.CredentialIcon{ - Light: "airtable", - Dark: "airtable", + Brand: "airtable", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/anthropic_api.go b/apps/platform-api/internal/nodeengine/credentials/anthropic_api.go index d0c0025..8f2fd74 100644 --- a/apps/platform-api/internal/nodeengine/credentials/anthropic_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/anthropic_api.go @@ -12,8 +12,7 @@ func NewAnthropicAPICredential() *domain.Credential { Name: "Anthropic", Description: "Anthropic API credentials for accessing Claude models.", Icon: domain.CredentialIcon{ - Light: "anthropic", - Dark: "anthropic", + Brand: "anthropic", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/chatgpt_api.go b/apps/platform-api/internal/nodeengine/credentials/chatgpt_api.go index 2f90773..89a89d0 100644 --- a/apps/platform-api/internal/nodeengine/credentials/chatgpt_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/chatgpt_api.go @@ -12,8 +12,7 @@ func NewChatgptAPICredential() *domain.Credential { Name: "ChatGPT", Description: "OpenAI API credentials for ChatGPT models.", Icon: domain.CredentialIcon{ - Light: "chatgpt", - Dark: "chatgpt", + Brand: "chatgpt", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/coingecko_api.go b/apps/platform-api/internal/nodeengine/credentials/coingecko_api.go index 02a39b3..f68007f 100644 --- a/apps/platform-api/internal/nodeengine/credentials/coingecko_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/coingecko_api.go @@ -12,8 +12,7 @@ func NewCoingeckoAPICredential() *domain.Credential { Name: "CoinGecko", Description: "CoinGecko API credentials for cryptocurrency market data.", Icon: domain.CredentialIcon{ - Light: "coingecko", - Dark: "coingecko", + Brand: "coingecko", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/deepl_api.go b/apps/platform-api/internal/nodeengine/credentials/deepl_api.go index aca7034..8259b15 100644 --- a/apps/platform-api/internal/nodeengine/credentials/deepl_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/deepl_api.go @@ -12,8 +12,7 @@ func NewDeeplAPICredential() *domain.Credential { Name: "DeepL", Description: "DeepL API credentials for translation services.", Icon: domain.CredentialIcon{ - Light: "deepl", - Dark: "deepl", + Brand: "deepl", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/deepseek_api.go b/apps/platform-api/internal/nodeengine/credentials/deepseek_api.go index de15be6..4cb4041 100644 --- a/apps/platform-api/internal/nodeengine/credentials/deepseek_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/deepseek_api.go @@ -12,8 +12,7 @@ func NewDeepseekAPICredential() *domain.Credential { Name: "DeepSeek", Description: "DeepSeek API credentials for AI chat models.", Icon: domain.CredentialIcon{ - Light: "deepseek", - Dark: "deepseek", + Brand: "deepseek", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/discord_api.go b/apps/platform-api/internal/nodeengine/credentials/discord_api.go index d8a70c7..8103f6c 100644 --- a/apps/platform-api/internal/nodeengine/credentials/discord_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/discord_api.go @@ -12,8 +12,7 @@ func NewDiscordAPICredential() *domain.Credential { Name: "Discord", Description: "Discord bot credentials for messaging and media.", Icon: domain.CredentialIcon{ - Light: "discord", - Dark: "discord", + Brand: "discord", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/elevenlabs_api.go b/apps/platform-api/internal/nodeengine/credentials/elevenlabs_api.go index 67d1150..ede5c8e 100644 --- a/apps/platform-api/internal/nodeengine/credentials/elevenlabs_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/elevenlabs_api.go @@ -12,8 +12,7 @@ func NewElevenlabsAPICredential() *domain.Credential { Name: "ElevenLabs", Description: "ElevenLabs API credentials for text-to-speech generation.", Icon: domain.CredentialIcon{ - Light: "elevenlabs", - Dark: "elevenlabs", + Brand: "elevenlabs", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/facebook_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/facebook_oauth2.go index a168631..f5c87d4 100644 --- a/apps/platform-api/internal/nodeengine/credentials/facebook_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/facebook_oauth2.go @@ -19,8 +19,7 @@ func NewFacebookOAuth2Credential(redirectURL string) *domain.Credential { Name: "Facebook", Description: "Facebook OAuth2 credentials for managing pages and posts.", Icon: domain.CredentialIcon{ - Light: "facebook", - Dark: "facebook", + Brand: "facebook", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/gemini_api.go b/apps/platform-api/internal/nodeengine/credentials/gemini_api.go index b8de8cc..7b1e757 100644 --- a/apps/platform-api/internal/nodeengine/credentials/gemini_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/gemini_api.go @@ -12,8 +12,7 @@ func NewGeminiAPICredential() *domain.Credential { Name: "Gemini", Description: "Google Gemini API domain.", Icon: domain.CredentialIcon{ - Light: "gemini", - Dark: "gemini", + Brand: "gemini", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/gmail_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/gmail_oauth2.go index 62768a8..8a1b0e9 100644 --- a/apps/platform-api/internal/nodeengine/credentials/gmail_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/gmail_oauth2.go @@ -19,8 +19,7 @@ func NewGmailOAuth2Credential(redirectURL string) *domain.Credential { Name: "Gmail", Description: "Gmail OAuth2 credentials for sending and reading email.", Icon: domain.CredentialIcon{ - Light: "gmail", - Dark: "gmail", + Brand: "gmail", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/google_docs_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/google_docs_oauth2.go index 4503b2e..1203a52 100644 --- a/apps/platform-api/internal/nodeengine/credentials/google_docs_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/google_docs_oauth2.go @@ -19,8 +19,7 @@ func NewGoogleDocsOAuth2Credential(redirectURL string) *domain.Credential { Name: "Google Docs", Description: "Google Docs OAuth2 credentials for managing documents.", Icon: domain.CredentialIcon{ - Light: "google_docs", - Dark: "google_docs", + Brand: "google_docs", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/google_drive_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/google_drive_oauth2.go index 1c64840..5325b25 100644 --- a/apps/platform-api/internal/nodeengine/credentials/google_drive_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/google_drive_oauth2.go @@ -19,8 +19,7 @@ func NewGoogleDriveOAuth2Credential(redirectURL string) *domain.Credential { Name: "Google Drive", Description: "Google Drive OAuth2 credentials for managing files and folders.", Icon: domain.CredentialIcon{ - Light: "google_drive", - Dark: "google_drive", + Brand: "google_drive", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/google_keep_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/google_keep_oauth2.go index c2a37de..842fb71 100644 --- a/apps/platform-api/internal/nodeengine/credentials/google_keep_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/google_keep_oauth2.go @@ -19,8 +19,7 @@ func NewGoogleKeepOAuth2Credential(redirectURL string) *domain.Credential { Name: "Google Keep", Description: "Google Keep OAuth2 credentials for managing notes.", Icon: domain.CredentialIcon{ - Light: "google_keep", - Dark: "google_keep", + Brand: "google_keep", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/google_sheets_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/google_sheets_oauth2.go index 867be1f..ffba73c 100644 --- a/apps/platform-api/internal/nodeengine/credentials/google_sheets_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/google_sheets_oauth2.go @@ -19,8 +19,7 @@ func NewGoogleSheetsOAuth2Credential(redirectURL string) *domain.Credential { Name: "Google Sheets", Description: "Google Sheets OAuth2 credentials for managing spreadsheets.", Icon: domain.CredentialIcon{ - Light: "google_sheets", - Dark: "google_sheets", + Brand: "google_sheets", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/instagram_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/instagram_oauth2.go index dd3b2df..2dccf3b 100644 --- a/apps/platform-api/internal/nodeengine/credentials/instagram_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/instagram_oauth2.go @@ -19,8 +19,7 @@ func NewInstagramOAuth2Credential(redirectURL string) *domain.Credential { Name: "Instagram", Description: "Instagram OAuth2 credentials for publishing posts and stories.", Icon: domain.CredentialIcon{ - Light: "instagram", - Dark: "instagram", + Brand: "instagram", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/linkedin_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/linkedin_oauth2.go index 6f2e617..22be5a4 100644 --- a/apps/platform-api/internal/nodeengine/credentials/linkedin_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/linkedin_oauth2.go @@ -19,8 +19,7 @@ func NewLinkedinOAuth2Credential(redirectURL string) *domain.Credential { Name: "LinkedIn", Description: "LinkedIn OAuth2 credentials for publishing posts.", Icon: domain.CredentialIcon{ - Light: "linkedin", - Dark: "linkedin", + Brand: "linkedin", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/notion_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/notion_oauth2.go index 789b14c..c07fea6 100644 --- a/apps/platform-api/internal/nodeengine/credentials/notion_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/notion_oauth2.go @@ -18,8 +18,7 @@ func NewNotionOAuth2Credential(redirectURL string) *domain.Credential { Name: "Notion", Description: "Notion OAuth2 credentials for managing pages and databases.", Icon: domain.CredentialIcon{ - Light: "notion", - Dark: "notion", + Brand: "notion", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/piapi_api.go b/apps/platform-api/internal/nodeengine/credentials/piapi_api.go index 55d2b96..1f7541e 100644 --- a/apps/platform-api/internal/nodeengine/credentials/piapi_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/piapi_api.go @@ -12,8 +12,7 @@ func NewPiapiAPICredential() *domain.Credential { Name: "PiApi", Description: "PiAPI credentials for image, video, and audio generation.", Icon: domain.CredentialIcon{ - Light: "piapi", - Dark: "piapi", + Brand: "piapi", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/sendgrid_api.go b/apps/platform-api/internal/nodeengine/credentials/sendgrid_api.go index 0dccde3..783076c 100644 --- a/apps/platform-api/internal/nodeengine/credentials/sendgrid_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/sendgrid_api.go @@ -12,8 +12,7 @@ func NewSendgridAPICredential() *domain.Credential { Name: "SendGrid", Description: "SendGrid API credentials for sending email.", Icon: domain.CredentialIcon{ - Light: "sendgrid", - Dark: "sendgrid", + Brand: "sendgrid", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/slack_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/slack_oauth2.go index 85a612b..55e0c15 100644 --- a/apps/platform-api/internal/nodeengine/credentials/slack_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/slack_oauth2.go @@ -20,8 +20,7 @@ func NewSlackOAuth2Credential(redirectURL string) *domain.Credential { Name: "Slack", Description: "Slack OAuth2 credentials for sending messages and media.", Icon: domain.CredentialIcon{ - Light: "slack", - Dark: "slack", + Brand: "slack", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/soundcloud_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/soundcloud_oauth2.go index 18f6f41..c2a95d6 100644 --- a/apps/platform-api/internal/nodeengine/credentials/soundcloud_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/soundcloud_oauth2.go @@ -18,8 +18,7 @@ func NewSoundcloudOAuth2Credential(redirectURL string) *domain.Credential { Name: "SoundCloud", Description: "SoundCloud OAuth2 credentials for managing tracks and playlists.", Icon: domain.CredentialIcon{ - Light: "soundcloud", - Dark: "soundcloud", + Brand: "soundcloud", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/sunomusic_api.go b/apps/platform-api/internal/nodeengine/credentials/sunomusic_api.go index c4fae3b..1e4e752 100644 --- a/apps/platform-api/internal/nodeengine/credentials/sunomusic_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/sunomusic_api.go @@ -12,8 +12,7 @@ func NewSunomusicAPICredential() *domain.Credential { Name: "Suno Music", Description: "Suno Music API credentials for music and lyrics generation.", Icon: domain.CredentialIcon{ - Light: "sunomusic", - Dark: "sunomusic", + Brand: "sunomusic", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/telegram_api.go b/apps/platform-api/internal/nodeengine/credentials/telegram_api.go index c055b86..f07d78b 100644 --- a/apps/platform-api/internal/nodeengine/credentials/telegram_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/telegram_api.go @@ -12,8 +12,7 @@ func NewTelegramAPICredential() *domain.Credential { Name: "Telegram", Description: "Telegram bot credentials for messaging.", Icon: domain.CredentialIcon{ - Light: "telegram", - Dark: "telegram", + Brand: "telegram", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/tiktok_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/tiktok_oauth2.go index 0c0381e..134ac6a 100644 --- a/apps/platform-api/internal/nodeengine/credentials/tiktok_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/tiktok_oauth2.go @@ -19,8 +19,7 @@ func NewTiktokOAuth2Credential(redirectURL string) *domain.Credential { Name: "TikTok", Description: "TikTok OAuth2 credentials for publishing videos.", Icon: domain.CredentialIcon{ - Light: "tiktok", - Dark: "tiktok", + Brand: "tiktok", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/veo_api.go b/apps/platform-api/internal/nodeengine/credentials/veo_api.go index 5feee76..1b742ed 100644 --- a/apps/platform-api/internal/nodeengine/credentials/veo_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/veo_api.go @@ -12,8 +12,7 @@ func NewVeoAPICredential() *domain.Credential { Name: "Veo", Description: "Google Veo API credentials for video generation.", Icon: domain.CredentialIcon{ - Light: "veo", - Dark: "veo", + Brand: "veo", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/whatsapp_api.go b/apps/platform-api/internal/nodeengine/credentials/whatsapp_api.go index 348b882..0245a5a 100644 --- a/apps/platform-api/internal/nodeengine/credentials/whatsapp_api.go +++ b/apps/platform-api/internal/nodeengine/credentials/whatsapp_api.go @@ -12,8 +12,7 @@ func NewWhatsappAPICredential() *domain.Credential { Name: "WhatsApp", Description: "WhatsApp Business API credentials for sending messages.", Icon: domain.CredentialIcon{ - Light: "whatsapp", - Dark: "whatsapp", + Brand: "whatsapp", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/x_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/x_oauth2.go index 4334caa..e5390d0 100644 --- a/apps/platform-api/internal/nodeengine/credentials/x_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/x_oauth2.go @@ -19,8 +19,7 @@ func NewXOAuth2Credential(redirectURL string) *domain.Credential { Name: "X (Twitter)", Description: "X (Twitter) OAuth2 credentials for publishing posts.", Icon: domain.CredentialIcon{ - Light: "x", - Dark: "x", + Brand: "x", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/credentials/youtube_oauth2.go b/apps/platform-api/internal/nodeengine/credentials/youtube_oauth2.go index fa94184..77c7fb6 100644 --- a/apps/platform-api/internal/nodeengine/credentials/youtube_oauth2.go +++ b/apps/platform-api/internal/nodeengine/credentials/youtube_oauth2.go @@ -19,8 +19,7 @@ func NewYoutubeOAuth2Credential(redirectURL string) *domain.Credential { Name: "YouTube", Description: "YouTube OAuth2 credentials for uploading and managing videos.", Icon: domain.CredentialIcon{ - Light: "youtube", - Dark: "youtube", + Brand: "youtube", }, Schema: &gjs.Schema{ Type: "object", diff --git a/apps/platform-api/internal/nodeengine/domain/credentials/credential_icon.go b/apps/platform-api/internal/nodeengine/domain/credentials/credential_icon.go index f7b107b..526431d 100644 --- a/apps/platform-api/internal/nodeengine/domain/credentials/credential_icon.go +++ b/apps/platform-api/internal/nodeengine/domain/credentials/credential_icon.go @@ -1,6 +1,5 @@ package credentials type CredentialIcon struct { - Light string `json:"light,omitempty"` - Dark string `json:"dark,omitempty"` + Brand string `json:"brand,omitempty"` } diff --git a/apps/platform-api/internal/nodeengine/domain/mcp/server.go b/apps/platform-api/internal/nodeengine/domain/mcp/server.go index cfe38be..66d894a 100644 --- a/apps/platform-api/internal/nodeengine/domain/mcp/server.go +++ b/apps/platform-api/internal/nodeengine/domain/mcp/server.go @@ -8,6 +8,7 @@ type Server struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` + Icon ServerIcon `json:"icon,omitzero"` Version string `json:"version,omitempty"` Instructions string `json:"instructions,omitempty"` Tools []nodes.NodeManager `json:"tools,omitempty"` @@ -18,6 +19,7 @@ type ServerManager interface { GetID() string GetName() string GetDescription() string + GetIcon() ServerIcon GetVersion() string GetInstructions() string GetTools() []nodes.NodeManager @@ -37,6 +39,10 @@ func (s *Server) GetDescription() string { return s.Description } +func (s *Server) GetIcon() ServerIcon { + return s.Icon +} + func (s *Server) GetVersion() string { return s.Version } diff --git a/apps/platform-api/internal/nodeengine/domain/mcp/server_icon.go b/apps/platform-api/internal/nodeengine/domain/mcp/server_icon.go new file mode 100644 index 0000000..af01bfa --- /dev/null +++ b/apps/platform-api/internal/nodeengine/domain/mcp/server_icon.go @@ -0,0 +1,5 @@ +package mcp + +type ServerIcon struct { + Brand string `json:"brand,omitempty"` +} diff --git a/apps/platform-api/internal/nodeengine/domain/nodes/node.go b/apps/platform-api/internal/nodeengine/domain/nodes/node.go index 0d3ea55..3c53509 100644 --- a/apps/platform-api/internal/nodeengine/domain/nodes/node.go +++ b/apps/platform-api/internal/nodeengine/domain/nodes/node.go @@ -10,6 +10,8 @@ type Node struct { Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` Icon NodeIcon `json:"icon"` + Inputs []NodeHandle `json:"inputs"` + Outputs []NodeHandle `json:"outputs"` InputSchema *gjs.Schema `json:"inputSchema,omitempty"` OutputSchema *gjs.Schema `json:"outputSchema,omitempty"` Categories []string `json:"categories,omitempty"` @@ -27,6 +29,10 @@ type NodeManager interface { GetName() string GetDescription() string GetIcon() NodeIcon + GetInputs() []NodeHandle + SetInputs(handles []NodeHandle) + GetOutputs() []NodeHandle + SetOutputs(handles []NodeHandle) GetInputSchema() *gjs.Schema GetOutputSchema() *gjs.Schema GetCategories() []string @@ -58,6 +64,22 @@ func (n *Node) GetIcon() NodeIcon { return n.Icon } +func (n *Node) GetInputs() []NodeHandle { + return n.Inputs +} + +func (n *Node) SetInputs(handles []NodeHandle) { + n.Inputs = handles +} + +func (n *Node) GetOutputs() []NodeHandle { + return n.Outputs +} + +func (n *Node) SetOutputs(handles []NodeHandle) { + n.Outputs = handles +} + func (n *Node) GetInputSchema() *gjs.Schema { return n.InputSchema } diff --git a/apps/platform-api/internal/nodeengine/domain/nodes/node_handle.go b/apps/platform-api/internal/nodeengine/domain/nodes/node_handle.go new file mode 100644 index 0000000..4ca5f10 --- /dev/null +++ b/apps/platform-api/internal/nodeengine/domain/nodes/node_handle.go @@ -0,0 +1,6 @@ +package nodes + +type NodeHandle struct { + Key string `json:"key"` + Label string `json:"label,omitempty"` +} diff --git a/apps/platform-api/internal/nodeengine/domain/nodes/node_icon.go b/apps/platform-api/internal/nodeengine/domain/nodes/node_icon.go index 55d3064..590de8b 100644 --- a/apps/platform-api/internal/nodeengine/domain/nodes/node_icon.go +++ b/apps/platform-api/internal/nodeengine/domain/nodes/node_icon.go @@ -1,6 +1,6 @@ package nodes type NodeIcon struct { - Light string `json:"light,omitempty"` - Dark string `json:"dark,omitempty"` + Brand string `json:"brand,omitempty"` + Glyph string `json:"glyph,omitempty"` } diff --git a/apps/platform-api/internal/nodeengine/nodes/airtable/createrecord/node.go b/apps/platform-api/internal/nodeengine/nodes/airtable/createrecord/node.go index 351c042..bbbf284 100644 --- a/apps/platform-api/internal/nodeengine/nodes/airtable/createrecord/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/airtable/createrecord/node.go @@ -17,8 +17,14 @@ func NewAirtableCreateRecordNode(nodeID string) *AirtableCreateRecordNode { Name: "Airtable Create Record", Description: "Create a new record in an Airtable base.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "airtable", + Glyph: "record", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Database"}, SubCategories: []string{"Airtable"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/airtable/listrecords/node.go b/apps/platform-api/internal/nodeengine/nodes/airtable/listrecords/node.go index 16903dd..c90ea98 100644 --- a/apps/platform-api/internal/nodeengine/nodes/airtable/listrecords/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/airtable/listrecords/node.go @@ -18,8 +18,14 @@ func NewAirtableListRecordsNode(nodeID string) *AirtableListRecordsNode { Name: "Airtable List Records", Description: "List records from an Airtable base.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "airtable", + Glyph: "list", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Database"}, SubCategories: []string{"Airtable"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/airtable/register.go b/apps/platform-api/internal/nodeengine/nodes/airtable/register.go index c78a6ba..bdd6985 100644 --- a/apps/platform-api/internal/nodeengine/nodes/airtable/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/airtable/register.go @@ -35,7 +35,10 @@ func Register() { ID: nodeID, Name: "Airtable", Description: "Tools for managing Airtable records.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "airtable", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ createRecordNode, listRecordsNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/anthropic/chat/node.go b/apps/platform-api/internal/nodeengine/nodes/anthropic/chat/node.go index 306a79b..31e4947 100644 --- a/apps/platform-api/internal/nodeengine/nodes/anthropic/chat/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/anthropic/chat/node.go @@ -18,8 +18,14 @@ func NewAnthropicChatNode(nodeID string) *AnthropicChatNode { Name: "Anthropic Chat", Description: "Generate a chat completion using Anthropic Claude.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "anthropic", + Glyph: "chat", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"AI"}, SubCategories: []string{"Anthropic"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/anthropic/register.go b/apps/platform-api/internal/nodeengine/nodes/anthropic/register.go index fa828b5..967ab6f 100644 --- a/apps/platform-api/internal/nodeengine/nodes/anthropic/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/anthropic/register.go @@ -25,7 +25,10 @@ func Register() { ID: nodeID, Name: "Anthropic", Description: "Tools for chat completions with Anthropic Claude.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "anthropic", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ chatNode, }, diff --git a/apps/platform-api/internal/nodeengine/nodes/chatgpt/chat/node.go b/apps/platform-api/internal/nodeengine/nodes/chatgpt/chat/node.go index e2df7ca..8a9abde 100644 --- a/apps/platform-api/internal/nodeengine/nodes/chatgpt/chat/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/chatgpt/chat/node.go @@ -18,8 +18,14 @@ func NewChatgptChatNode(nodeID string) *ChatgptChatNode { Name: "ChatGPT Chat", Description: "Generate a chat completion using OpenAI ChatGPT.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "chatgpt", + Glyph: "chat", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"AI"}, SubCategories: []string{"ChatGPT"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/chatgpt/register.go b/apps/platform-api/internal/nodeengine/nodes/chatgpt/register.go index 51fd195..cc864a8 100644 --- a/apps/platform-api/internal/nodeengine/nodes/chatgpt/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/chatgpt/register.go @@ -25,7 +25,10 @@ func Register() { ID: nodeID, Name: "ChatGPT", Description: "Tools for chat completions with OpenAI ChatGPT.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "chatgpt", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ chatNode, }, diff --git a/apps/platform-api/internal/nodeengine/nodes/coingecko/airdroptracker/node.go b/apps/platform-api/internal/nodeengine/nodes/coingecko/airdroptracker/node.go index 723f30b..612a04e 100644 --- a/apps/platform-api/internal/nodeengine/nodes/coingecko/airdroptracker/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/coingecko/airdroptracker/node.go @@ -18,8 +18,14 @@ func NewCoingeckoAirdropTrackerNode(nodeID string) *CoingeckoAirdropTrackerNode Name: "Coingecko Airdrop Tracker", Description: "Track cryptocurrency airdrops via CoinGecko.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "coingecko", + Glyph: "target", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Blockchain"}, SubCategories: []string{"CoinGecko"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/coingecko/pricemonitor/node.go b/apps/platform-api/internal/nodeengine/nodes/coingecko/pricemonitor/node.go index 8d73c57..1633abf 100644 --- a/apps/platform-api/internal/nodeengine/nodes/coingecko/pricemonitor/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/coingecko/pricemonitor/node.go @@ -18,8 +18,14 @@ func NewCoingeckoPriceMonitorNode(nodeID string) *CoingeckoPriceMonitorNode { Name: "Coingecko Price Monitor", Description: "Monitor cryptocurrency prices via CoinGecko.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "coingecko", + Glyph: "trending", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Blockchain"}, SubCategories: []string{"CoinGecko"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/coingecko/register.go b/apps/platform-api/internal/nodeengine/nodes/coingecko/register.go index 5d17d7b..00c5752 100644 --- a/apps/platform-api/internal/nodeengine/nodes/coingecko/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/coingecko/register.go @@ -35,7 +35,10 @@ func Register() { ID: nodeID, Name: "CoinGecko", Description: "Tools for tracking cryptocurrency markets via CoinGecko.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "coingecko", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ airdropTrackerNode, priceMonitorNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/deepl/register.go b/apps/platform-api/internal/nodeengine/nodes/deepl/register.go index e6cad32..f00eb4f 100644 --- a/apps/platform-api/internal/nodeengine/nodes/deepl/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/deepl/register.go @@ -25,7 +25,10 @@ func Register() { ID: nodeID, Name: "DeepL", Description: "Tools for translation via DeepL.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "deepl", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ translateNode, }, diff --git a/apps/platform-api/internal/nodeengine/nodes/deepl/translate/node.go b/apps/platform-api/internal/nodeengine/nodes/deepl/translate/node.go index 7b0aa70..3a456b4 100644 --- a/apps/platform-api/internal/nodeengine/nodes/deepl/translate/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/deepl/translate/node.go @@ -18,8 +18,14 @@ func NewDeeplTranslateNode(nodeID string) *DeeplTranslateNode { Name: "DeepL Translate", Description: "Translate text using DeepL.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "deepl", + Glyph: "translate", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"AI"}, SubCategories: []string{"DeepL"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/deepseek/chat/node.go b/apps/platform-api/internal/nodeengine/nodes/deepseek/chat/node.go index 93c87e2..2fa7ebc 100644 --- a/apps/platform-api/internal/nodeengine/nodes/deepseek/chat/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/deepseek/chat/node.go @@ -18,8 +18,14 @@ func NewDeepseekChatNode(nodeID string) *DeepseekChatNode { Name: "DeepSeek Chat", Description: "Generate a chat completion using DeepSeek.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "deepseek", + Glyph: "chat", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"AI"}, SubCategories: []string{"DeepSeek"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/deepseek/register.go b/apps/platform-api/internal/nodeengine/nodes/deepseek/register.go index b1d13d9..b45cc2c 100644 --- a/apps/platform-api/internal/nodeengine/nodes/deepseek/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/deepseek/register.go @@ -25,7 +25,10 @@ func Register() { ID: nodeID, Name: "DeepSeek", Description: "Tools for chat completions with DeepSeek models.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "deepseek", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ chatNode, }, diff --git a/apps/platform-api/internal/nodeengine/nodes/discord/register.go b/apps/platform-api/internal/nodeengine/nodes/discord/register.go index b5d53ee..532fd3a 100644 --- a/apps/platform-api/internal/nodeengine/nodes/discord/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/discord/register.go @@ -40,7 +40,10 @@ func Register(fileGateway filegateway.FileGateway) { ID: nodeID, Name: "Discord", Description: "Tools for sending messages and media to Discord.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "discord", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ sendMessageNode, sendMediaNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/discord/sendmedia/node.go b/apps/platform-api/internal/nodeengine/nodes/discord/sendmedia/node.go index 9fba2f2..556142e 100644 --- a/apps/platform-api/internal/nodeengine/nodes/discord/sendmedia/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/discord/sendmedia/node.go @@ -17,8 +17,14 @@ func NewDiscordSendMediaNode(nodeID string) *DiscordSendMediaNode { Name: "Discord Send Media", Description: "Send a media file to a Discord channel.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "discord", + Glyph: "image", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Discord"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/discord/sendmessage/node.go b/apps/platform-api/internal/nodeengine/nodes/discord/sendmessage/node.go index b1755d3..38ccb15 100644 --- a/apps/platform-api/internal/nodeengine/nodes/discord/sendmessage/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/discord/sendmessage/node.go @@ -17,8 +17,14 @@ func NewDiscordSendMessageNode(nodeID string) *DiscordSendMessageNode { Name: "Discord Send Message", Description: "Send a text message to a Discord channel.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "discord", + Glyph: "chat", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Discord"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/elevenlabs/register.go b/apps/platform-api/internal/nodeengine/nodes/elevenlabs/register.go index 334e379..f602051 100644 --- a/apps/platform-api/internal/nodeengine/nodes/elevenlabs/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/elevenlabs/register.go @@ -26,7 +26,10 @@ func Register(fileGateway filegateway.FileGateway) { ID: nodeID, Name: "ElevenLabs", Description: "Tools for text-to-speech and audio synthesis via ElevenLabs.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "elevenlabs", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ textToSpeechNode, }, diff --git a/apps/platform-api/internal/nodeengine/nodes/elevenlabs/texttospeech/node.go b/apps/platform-api/internal/nodeengine/nodes/elevenlabs/texttospeech/node.go index eb45d91..59b1a9a 100644 --- a/apps/platform-api/internal/nodeengine/nodes/elevenlabs/texttospeech/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/elevenlabs/texttospeech/node.go @@ -18,8 +18,14 @@ func NewElevenlabsTextToSpeechNode(nodeID string) *ElevenlabsTextToSpeechNode { Name: "ElevenLabs Text To Speech", Description: "Convert text to speech using ElevenLabs.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "elevenlabs", + Glyph: "speaker", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Audio"}, SubCategories: []string{"ElevenLabs"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/facebook/publishmediapost/node.go b/apps/platform-api/internal/nodeengine/nodes/facebook/publishmediapost/node.go index 3ca278d..3916eb7 100644 --- a/apps/platform-api/internal/nodeengine/nodes/facebook/publishmediapost/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/facebook/publishmediapost/node.go @@ -17,8 +17,14 @@ func NewFacebookPublishMediaPostNode(nodeID string) *FacebookPublishMediaPostNod Name: "Facebook Publish Media Post", Description: "Publish a post with media to a Facebook page.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "facebook", + Glyph: "image", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Facebook"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/facebook/publishpost/node.go b/apps/platform-api/internal/nodeengine/nodes/facebook/publishpost/node.go index b59f9a6..930a0ba 100644 --- a/apps/platform-api/internal/nodeengine/nodes/facebook/publishpost/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/facebook/publishpost/node.go @@ -17,8 +17,14 @@ func NewFacebookPublishPostNode(nodeID string) *FacebookPublishPostNode { Name: "Facebook Publish Post", Description: "Publish a text post to a Facebook page.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "facebook", + Glyph: "send", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Facebook"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/facebook/publishstory/node.go b/apps/platform-api/internal/nodeengine/nodes/facebook/publishstory/node.go index 5ecda4a..88bd1b8 100644 --- a/apps/platform-api/internal/nodeengine/nodes/facebook/publishstory/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/facebook/publishstory/node.go @@ -17,8 +17,14 @@ func NewFacebookPublishStoryNode(nodeID string) *FacebookPublishStoryNode { Name: "Facebook Publish Story", Description: "Publish a story to a Facebook page.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "facebook", + Glyph: "story", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Facebook"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/facebook/register.go b/apps/platform-api/internal/nodeengine/nodes/facebook/register.go index 5c27891..23261df 100644 --- a/apps/platform-api/internal/nodeengine/nodes/facebook/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/facebook/register.go @@ -45,7 +45,10 @@ func Register() { ID: nodeID, Name: "Facebook", Description: "Tools for publishing posts, media, and stories to Facebook pages.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "facebook", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ publishPostNode, publishMediaPostNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/gemini/chat/node.go b/apps/platform-api/internal/nodeengine/nodes/gemini/chat/node.go index 9f2bf11..b55da49 100644 --- a/apps/platform-api/internal/nodeengine/nodes/gemini/chat/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/gemini/chat/node.go @@ -18,8 +18,14 @@ func NewGeminiChatNode(nodeID string) *GeminiChatNode { Name: "Gemini Chat", Description: "Generate a chat completion using Google Gemini.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "gemini", + Glyph: "chat", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"AI"}, SubCategories: []string{"Gemini"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/gemini/nanobanana/node.go b/apps/platform-api/internal/nodeengine/nodes/gemini/nanobanana/node.go index 0afa5d3..f127e25 100644 --- a/apps/platform-api/internal/nodeengine/nodes/gemini/nanobanana/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/gemini/nanobanana/node.go @@ -18,8 +18,14 @@ func NewGeminiImageGenerationNode(nodeID string) *GeminiImageGenerationNode { Name: "Gemini Nano Banana", Description: "Generate an image from a text prompt using Google Gemini Nano Banana.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "gemini", + Glyph: "image", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Image"}, SubCategories: []string{"Gemini"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/gemini/register.go b/apps/platform-api/internal/nodeengine/nodes/gemini/register.go index c407d3d..a1733e4 100644 --- a/apps/platform-api/internal/nodeengine/nodes/gemini/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/gemini/register.go @@ -36,7 +36,10 @@ func Register(fileGatewayService filegateway.FileGateway) { ID: nodeID, Name: "Gemini", Description: "Tools for chat completions and image generation with Google Gemini.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "gemini", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ nanoBananaNode, chatNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/docs/createorupdate/node.go b/apps/platform-api/internal/nodeengine/nodes/google/docs/createorupdate/node.go index d11d961..9f3bb61 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/docs/createorupdate/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/docs/createorupdate/node.go @@ -17,8 +17,14 @@ func NewGoogleDocsCreateOrUpdateNode(nodeID string) *GoogleDocsCreateOrUpdateNod Name: "Google Docs Create or Update", Description: "Create a new Google Docs document or update an existing one with the provided content.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_docs", + Glyph: "pencil", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Docs"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/docs/readdocs/node.go b/apps/platform-api/internal/nodeengine/nodes/google/docs/readdocs/node.go index b09971b..07ba573 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/docs/readdocs/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/docs/readdocs/node.go @@ -17,8 +17,14 @@ func NewGoogleDocsReadDocsNode(nodeID string) *GoogleDocsReadDocsNode { Name: "Google Docs Read", Description: "Read the plain text content of a Google Docs document.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_docs", + Glyph: "eye", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Docs"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/docs/register.go b/apps/platform-api/internal/nodeengine/nodes/google/docs/register.go index ae35156..314f741 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/docs/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/docs/register.go @@ -35,7 +35,10 @@ func Register() { ID: nodeID, Name: "Google Docs", Description: "Tools for creating, updating, and reading Google Docs.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "google_docs", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ createOrUpdateNode, readDocsNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/drive/createfolder/node.go b/apps/platform-api/internal/nodeengine/nodes/google/drive/createfolder/node.go index 6a4b171..aef5fc5 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/drive/createfolder/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/drive/createfolder/node.go @@ -18,8 +18,14 @@ func NewGoogleDriveCreateFolderNode(nodeID string) *GoogleDriveCreateFolderNode Name: "Google Drive Create Folder", Description: "Create a new folder in Google Drive.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_drive", + Glyph: "folder", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Drive"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/drive/createtextfile/node.go b/apps/platform-api/internal/nodeengine/nodes/google/drive/createtextfile/node.go index fbef502..e65bd91 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/drive/createtextfile/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/drive/createtextfile/node.go @@ -18,8 +18,14 @@ func NewGoogleDriveCreateTextFileNode(nodeID string) *GoogleDriveCreateTextFileN Name: "Google Drive Create Text File", Description: "Create a plain text file in Google Drive.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_drive", + Glyph: "plus", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Drive"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/drive/getfile/node.go b/apps/platform-api/internal/nodeengine/nodes/google/drive/getfile/node.go index 2502084..1fe071e 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/drive/getfile/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/drive/getfile/node.go @@ -17,8 +17,14 @@ func NewGoogleDriveGetFileNode(nodeID string) *GoogleDriveGetFileNode { Name: "Google Drive Get File", Description: "Retrieve a file from Google Drive along with its metadata.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_drive", + Glyph: "file", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Drive"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/drive/register.go b/apps/platform-api/internal/nodeengine/nodes/google/drive/register.go index cc04317..28008c2 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/drive/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/drive/register.go @@ -56,7 +56,10 @@ func Register(fileGateway filegateway.FileGateway) { ID: nodeID, Name: "Google Drive", Description: "Tools for managing files and folders in Google Drive.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "google_drive", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ createFolderNode, createTextFileNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/drive/uploadfile/node.go b/apps/platform-api/internal/nodeengine/nodes/google/drive/uploadfile/node.go index 3781382..c871486 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/drive/uploadfile/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/drive/uploadfile/node.go @@ -18,8 +18,14 @@ func NewGoogleDriveUploadFileNode(nodeID string) *GoogleDriveUploadFileNode { Name: "Google Drive Upload File", Description: "Upload one or more files to Google Drive from a list of source URLs.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_drive", + Glyph: "upload", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Drive"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/gmail/organizeemails/node.go b/apps/platform-api/internal/nodeengine/nodes/google/gmail/organizeemails/node.go index 2b4e7ad..ef01efe 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/gmail/organizeemails/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/gmail/organizeemails/node.go @@ -17,8 +17,14 @@ func NewGmailOrganizeEmailsNode(nodeID string) *GmailOrganizeEmailsNode { Name: "Gmail Organize Emails", Description: "Organize Gmail messages by applying labels, stars, categories, read state, or trash actions to messages matching a search query.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "gmail", + Glyph: "organize", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Mailing"}, SubCategories: []string{"Gmail"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/gmail/register.go b/apps/platform-api/internal/nodeengine/nodes/google/gmail/register.go index f138271..b5932e9 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/gmail/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/gmail/register.go @@ -45,7 +45,10 @@ func Register() { ID: nodeID, Name: "Gmail", Description: "Tools for organizing, searching, and sending Gmail emails.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "gmail", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ organizeEmailsNode, searchEmailsNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/gmail/searchemails/node.go b/apps/platform-api/internal/nodeengine/nodes/google/gmail/searchemails/node.go index 36f126f..ee1b196 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/gmail/searchemails/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/gmail/searchemails/node.go @@ -17,8 +17,14 @@ func NewGmailSearchEmailsNode(nodeID string) *GmailSearchEmailsNode { Name: "Gmail Search Emails", Description: "Search Gmail messages using Gmail's standard search syntax and return matching email summaries.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "gmail", + Glyph: "search", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Mailing"}, SubCategories: []string{"Gmail"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/gmail/sendemail/node.go b/apps/platform-api/internal/nodeengine/nodes/google/gmail/sendemail/node.go index 88eae63..2d34787 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/gmail/sendemail/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/gmail/sendemail/node.go @@ -17,8 +17,14 @@ func NewGmailSendEmailNode(nodeID string) *GmailSendEmailNode { Name: "Gmail Send Email", Description: "Send an email through Gmail.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "gmail", + Glyph: "send", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Mailing"}, SubCategories: []string{"Gmail"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/keep/createnote/node.go b/apps/platform-api/internal/nodeengine/nodes/google/keep/createnote/node.go index 4e4a363..160ef6e 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/keep/createnote/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/keep/createnote/node.go @@ -18,8 +18,14 @@ func NewGoogleKeepCreateNoteNode(nodeID string) *GoogleKeepCreateNoteNode { Name: "Google Keep Create Note", Description: "Create a new note in Google Keep.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_keep", + Glyph: "note", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Keep"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/keep/deletenote/node.go b/apps/platform-api/internal/nodeengine/nodes/google/keep/deletenote/node.go index 714a2ff..77e261d 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/keep/deletenote/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/keep/deletenote/node.go @@ -17,8 +17,14 @@ func NewGoogleKeepDeleteNoteNode(nodeID string) *GoogleKeepDeleteNoteNode { Name: "Google Keep Delete Note", Description: "Delete a note from Google Keep. This removes the note immediately and cannot be undone.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_keep", + Glyph: "trash", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Keep"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/keep/getnote/node.go b/apps/platform-api/internal/nodeengine/nodes/google/keep/getnote/node.go index d4eff62..d0f965c 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/keep/getnote/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/keep/getnote/node.go @@ -18,8 +18,14 @@ func NewGoogleKeepGetNoteNode(nodeID string) *GoogleKeepGetNoteNode { Name: "Google Keep Get Note", Description: "Get a single note from Google Keep by its resource name.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_keep", + Glyph: "eye", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Keep"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/keep/listnotes/node.go b/apps/platform-api/internal/nodeengine/nodes/google/keep/listnotes/node.go index c34a5cb..9aa8d3b 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/keep/listnotes/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/keep/listnotes/node.go @@ -18,8 +18,14 @@ func NewGoogleKeepListNotesNode(nodeID string) *GoogleKeepListNotesNode { Name: "Google Keep List Notes", Description: "List notes from Google Keep with optional filtering and pagination.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_keep", + Glyph: "list", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Keep"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/keep/register.go b/apps/platform-api/internal/nodeengine/nodes/google/keep/register.go index 73ae67a..0365049 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/keep/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/keep/register.go @@ -55,7 +55,10 @@ func Register() { ID: nodeID, Name: "Google Keep", Description: "Tools for creating, reading, listing, and deleting Google Keep notes.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "google_keep", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ createNoteNode, getNoteNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/sheets/adddatatospreadsheet/node.go b/apps/platform-api/internal/nodeengine/nodes/google/sheets/adddatatospreadsheet/node.go index 5e61fc9..84d5bf5 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/sheets/adddatatospreadsheet/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/sheets/adddatatospreadsheet/node.go @@ -18,8 +18,14 @@ func NewGoogleSheetsAddDataToSpreadsheetNode(nodeID string) *GoogleSheetsAddData Version: "0.0.1", Description: "Append rows of data to a Google Sheets spreadsheet.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_sheets", + Glyph: "plus", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Sheets"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/sheets/createspreadsheet/node.go b/apps/platform-api/internal/nodeengine/nodes/google/sheets/createspreadsheet/node.go index 6972c7b..d15a165 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/sheets/createspreadsheet/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/sheets/createspreadsheet/node.go @@ -17,8 +17,14 @@ func NewGoogleSheetsCreateSpreadsheetNode(nodeID string) *GoogleSheetsCreateSpre Name: "Google Sheets Create Spreadsheet", Description: "Create a new Google Sheets spreadsheet with the given title.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_sheets", + Glyph: "table", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Sheets"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/sheets/deletespreadsheet/node.go b/apps/platform-api/internal/nodeengine/nodes/google/sheets/deletespreadsheet/node.go index 955435c..e6771b5 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/sheets/deletespreadsheet/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/sheets/deletespreadsheet/node.go @@ -17,8 +17,14 @@ func NewGoogleSheetsDeleteSpreadsheetNode(nodeID string) *GoogleSheetsDeleteSpre Name: "Google Sheets Delete Spreadsheet", Description: "Delete a Google Sheets spreadsheet by its identifier.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_sheets", + Glyph: "trash", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Sheets"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/sheets/readspreadsheet/node.go b/apps/platform-api/internal/nodeengine/nodes/google/sheets/readspreadsheet/node.go index 1f6ccc8..bfa1a7d 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/sheets/readspreadsheet/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/sheets/readspreadsheet/node.go @@ -18,8 +18,14 @@ func NewGoogleSheetsReadSpreadsheetNode(nodeID string) *GoogleSheetsReadSpreadsh Name: "Google Sheets Read Spreadsheet", Description: "Read rows from a Google Sheets spreadsheet, optionally filtering and limiting results.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_sheets", + Glyph: "eye", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Sheets"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/sheets/register.go b/apps/platform-api/internal/nodeengine/nodes/google/sheets/register.go index 59b59b7..029d65e 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/sheets/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/sheets/register.go @@ -65,7 +65,10 @@ func Register() { ID: nodeID, Name: "Google Sheets", Description: "Tools for creating, reading, updating, and deleting Google Sheets data.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "google_sheets", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ createSpreadsheetNode, readSpreadsheetNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/sheets/update/node.go b/apps/platform-api/internal/nodeengine/nodes/google/sheets/update/node.go index 7956dfd..fa0629f 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/sheets/update/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/sheets/update/node.go @@ -17,8 +17,14 @@ func NewGoogleSheetsUpdateNode(nodeID string) *GoogleSheetsUpdateNode { Name: "Google Sheets Update Cell", Description: "Update a single cell in a Google Sheets spreadsheet by row number and column.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "google_sheets", + Glyph: "pencil", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Google Workspace"}, SubCategories: []string{"Google Sheets"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/youtube/register.go b/apps/platform-api/internal/nodeengine/nodes/google/youtube/register.go index f2253ed..8e67eb6 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/youtube/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/youtube/register.go @@ -26,7 +26,10 @@ func Register(fileGateway filegateway.FileGateway) { ID: nodeID, Name: "YouTube", Description: "Tools for uploading videos to YouTube.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "youtube", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ uploadVideoNode, }, diff --git a/apps/platform-api/internal/nodeengine/nodes/google/youtube/uploadvideo/node.go b/apps/platform-api/internal/nodeengine/nodes/google/youtube/uploadvideo/node.go index 2364c6a..efc3565 100644 --- a/apps/platform-api/internal/nodeengine/nodes/google/youtube/uploadvideo/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/google/youtube/uploadvideo/node.go @@ -18,8 +18,14 @@ func NewYouTubeUploadVideoNode(nodeID string) *YouTubeUploadVideoNode { Name: "YouTube Upload Video", Description: "Upload a video file to YouTube with the given metadata and privacy setting.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "youtube", + Glyph: "film", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"YouTube"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/instagram/publishpost/node.go b/apps/platform-api/internal/nodeengine/nodes/instagram/publishpost/node.go index a035d43..c3c0c7b 100644 --- a/apps/platform-api/internal/nodeengine/nodes/instagram/publishpost/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/instagram/publishpost/node.go @@ -17,8 +17,14 @@ func NewInstagramPublishPostNode(nodeID string) *InstagramPublishPostNode { Name: "Instagram Publish Post", Description: "Publish a post to an Instagram account.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "instagram", + Glyph: "send", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Instagram"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/instagram/publishreels/node.go b/apps/platform-api/internal/nodeengine/nodes/instagram/publishreels/node.go index 4fed3e2..0119d3a 100644 --- a/apps/platform-api/internal/nodeengine/nodes/instagram/publishreels/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/instagram/publishreels/node.go @@ -18,8 +18,14 @@ func NewInstagramPublishReelsNode(nodeID string) *InstagramPublishReelsNode { Name: "Instagram Publish Reels", Description: "Publish a Reel to an Instagram account.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "instagram", + Glyph: "film", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Instagram"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/instagram/publishstory/node.go b/apps/platform-api/internal/nodeengine/nodes/instagram/publishstory/node.go index 166b57a..6faa0bf 100644 --- a/apps/platform-api/internal/nodeengine/nodes/instagram/publishstory/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/instagram/publishstory/node.go @@ -17,8 +17,14 @@ func NewInstagramPublishStoryNode(nodeID string) *InstagramPublishStoryNode { Name: "Instagram Publish Story", Description: "Publish a story to an Instagram account.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "instagram", + Glyph: "story", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Instagram"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/instagram/register.go b/apps/platform-api/internal/nodeengine/nodes/instagram/register.go index 681ba10..284cd16 100644 --- a/apps/platform-api/internal/nodeengine/nodes/instagram/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/instagram/register.go @@ -45,7 +45,10 @@ func Register() { ID: nodeID, Name: "Instagram", Description: "Tools for publishing posts, stories, and reels to Instagram.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "instagram", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ publishPostNode, publishStoryNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/linkedin/publishmediapost/node.go b/apps/platform-api/internal/nodeengine/nodes/linkedin/publishmediapost/node.go index db2159b..0a73013 100644 --- a/apps/platform-api/internal/nodeengine/nodes/linkedin/publishmediapost/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/linkedin/publishmediapost/node.go @@ -18,8 +18,14 @@ func NewLinkedinPublishMediaPostNode(nodeID string) *LinkedinPublishMediaPostNod Name: "LinkedIn Publish Media Post", Description: "Publish a post with media to a LinkedIn account.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "linkedin", + Glyph: "image", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"LinkedIn"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/linkedin/publishpost/node.go b/apps/platform-api/internal/nodeengine/nodes/linkedin/publishpost/node.go index 8a50651..e2cabed 100644 --- a/apps/platform-api/internal/nodeengine/nodes/linkedin/publishpost/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/linkedin/publishpost/node.go @@ -18,8 +18,14 @@ func NewLinkedinPublishPostNode(nodeID string) *LinkedinPublishPostNode { Name: "LinkedIn Publish Post", Description: "Publish a post to a LinkedIn account.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "linkedin", + Glyph: "send", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"LinkedIn"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/linkedin/register.go b/apps/platform-api/internal/nodeengine/nodes/linkedin/register.go index df601f3..ff9f26e 100644 --- a/apps/platform-api/internal/nodeengine/nodes/linkedin/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/linkedin/register.go @@ -36,7 +36,10 @@ func Register(fileGateway filegateway.FileGateway) { ID: nodeID, Name: "LinkedIn", Description: "Tools for publishing posts and media to LinkedIn.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "linkedin", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ publishPostNode, publishMediaPostNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/notion/createpage/node.go b/apps/platform-api/internal/nodeengine/nodes/notion/createpage/node.go index 260a421..1954920 100644 --- a/apps/platform-api/internal/nodeengine/nodes/notion/createpage/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/notion/createpage/node.go @@ -17,8 +17,14 @@ func NewNotionCreatePageNode(nodeID string) *NotionCreatePageNode { Name: "Notion Create Page", Description: "Create a new page in a Notion workspace.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "notion", + Glyph: "plus", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Notion"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/notion/getpage/node.go b/apps/platform-api/internal/nodeengine/nodes/notion/getpage/node.go index 54c6417..c51b57d 100644 --- a/apps/platform-api/internal/nodeengine/nodes/notion/getpage/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/notion/getpage/node.go @@ -17,8 +17,14 @@ func NewNotionGetPageNode(nodeID string) *NotionGetPageNode { Name: "Notion Get Page", Description: "Retrieve a page from a Notion workspace.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "notion", + Glyph: "eye", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Notion"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/notion/register.go b/apps/platform-api/internal/nodeengine/nodes/notion/register.go index 42b234b..abdde39 100644 --- a/apps/platform-api/internal/nodeengine/nodes/notion/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/notion/register.go @@ -55,7 +55,10 @@ func Register() { ID: nodeID, Name: "Notion", Description: "Tools for managing Notion pages.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "notion", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ createPageNode, updatePageNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/notion/searchpages/node.go b/apps/platform-api/internal/nodeengine/nodes/notion/searchpages/node.go index 6e678ab..ff88778 100644 --- a/apps/platform-api/internal/nodeengine/nodes/notion/searchpages/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/notion/searchpages/node.go @@ -18,8 +18,14 @@ func NewNotionSearchPagesNode(nodeID string) *NotionSearchPagesNode { Name: "Notion Search Pages", Description: "Search for pages in a Notion workspace.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "notion", + Glyph: "search", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Notion"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/notion/updatepage/node.go b/apps/platform-api/internal/nodeengine/nodes/notion/updatepage/node.go index 29e0b29..5c236d5 100644 --- a/apps/platform-api/internal/nodeengine/nodes/notion/updatepage/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/notion/updatepage/node.go @@ -17,8 +17,14 @@ func NewNotionUpdatePageNode(nodeID string) *NotionUpdatePageNode { Name: "Notion Update Page", Description: "Update an existing page in a Notion workspace.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "notion", + Glyph: "pencil", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Notion"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/piapi/audiogen/node.go b/apps/platform-api/internal/nodeengine/nodes/piapi/audiogen/node.go index 0b45fd2..b4e3dbb 100644 --- a/apps/platform-api/internal/nodeengine/nodes/piapi/audiogen/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/piapi/audiogen/node.go @@ -18,8 +18,14 @@ func NewPiAPIAudioGenNode(nodeID string) *PiAPIAudioGenNode { Name: "PiAPI Audio Generation", Description: "Generate audio using PiAPI.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "piapi", + Glyph: "speaker", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Audio"}, SubCategories: []string{"PiApi"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/piapi/imagegen/node.go b/apps/platform-api/internal/nodeengine/nodes/piapi/imagegen/node.go index d2b317f..6d2365d 100644 --- a/apps/platform-api/internal/nodeengine/nodes/piapi/imagegen/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/piapi/imagegen/node.go @@ -18,8 +18,14 @@ func NewPiAPIImageGenNode(nodeID string) *PiAPIImageGenNode { Name: "PiAPI Image Generation", Description: "Generate an image using PiAPI.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "piapi", + Glyph: "image", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Image"}, SubCategories: []string{"PiApi"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/piapi/register.go b/apps/platform-api/internal/nodeengine/nodes/piapi/register.go index 32654d9..aac2896 100644 --- a/apps/platform-api/internal/nodeengine/nodes/piapi/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/piapi/register.go @@ -45,7 +45,10 @@ func Register() { ID: nodeID, Name: "PiAPI", Description: "Tools for AI image, video, and audio generation via PiAPI.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "piapi", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ imageGenNode, videoGenNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/piapi/videogen/node.go b/apps/platform-api/internal/nodeengine/nodes/piapi/videogen/node.go index b42d930..430d7ad 100644 --- a/apps/platform-api/internal/nodeengine/nodes/piapi/videogen/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/piapi/videogen/node.go @@ -18,8 +18,14 @@ func NewPiAPIVideoGenNode(nodeID string) *PiAPIVideoGenNode { Name: "PiAPI Video Generation", Description: "Generate a video using PiAPI.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "piapi", + Glyph: "film", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Video"}, SubCategories: []string{"PiApi"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/sendgrid/register.go b/apps/platform-api/internal/nodeengine/nodes/sendgrid/register.go index 5732082..92b0f6c 100644 --- a/apps/platform-api/internal/nodeengine/nodes/sendgrid/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/sendgrid/register.go @@ -23,7 +23,10 @@ func Register() { ID: "sendgrid", Name: "SendGrid", Description: "Tools for sending emails via SendGrid.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "sendgrid", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ sendEmailNode, }, diff --git a/apps/platform-api/internal/nodeengine/nodes/sendgrid/sendemail/node.go b/apps/platform-api/internal/nodeengine/nodes/sendgrid/sendemail/node.go index 7aaddfa..f3fab1a 100644 --- a/apps/platform-api/internal/nodeengine/nodes/sendgrid/sendemail/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/sendgrid/sendemail/node.go @@ -17,8 +17,14 @@ func NewSendgridSendEmailNode(nodeID string) *SendgridSendEmailNode { Name: "SendGrid Send Email", Description: "Send an email through SendGrid.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "sendgrid", + Glyph: "send", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Mailing"}, SubCategories: []string{"SendGrid"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/slack/register.go b/apps/platform-api/internal/nodeengine/nodes/slack/register.go index 8beb2c4..793c6fd 100644 --- a/apps/platform-api/internal/nodeengine/nodes/slack/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/slack/register.go @@ -40,7 +40,10 @@ func Register(fileGateway filegateway.FileGateway) { ID: nodeID, Name: "Slack", Description: "Tools for sending messages and media to Slack.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "slack", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ sendMessageNode, sendMediaNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/slack/sendmedia/node.go b/apps/platform-api/internal/nodeengine/nodes/slack/sendmedia/node.go index da3302a..a6a5fe7 100644 --- a/apps/platform-api/internal/nodeengine/nodes/slack/sendmedia/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/slack/sendmedia/node.go @@ -17,8 +17,14 @@ func NewSlackSendMediaNode(nodeID string) *SlackSendMediaNode { Name: "Slack Send Media", Description: "Send a media file to a Slack channel.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "slack", + Glyph: "image", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Slack"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/slack/sendmessage/node.go b/apps/platform-api/internal/nodeengine/nodes/slack/sendmessage/node.go index e7cbcbb..7edc676 100644 --- a/apps/platform-api/internal/nodeengine/nodes/slack/sendmessage/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/slack/sendmessage/node.go @@ -17,8 +17,14 @@ func NewSlackSendMessageNode(nodeID string) *SlackSendMessageNode { Name: "Slack Send Message", Description: "Send a text message to a Slack channel.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "slack", + Glyph: "chat", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Slack"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/soundcloud/createplaylist/node.go b/apps/platform-api/internal/nodeengine/nodes/soundcloud/createplaylist/node.go index 573fa9d..f726789 100644 --- a/apps/platform-api/internal/nodeengine/nodes/soundcloud/createplaylist/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/soundcloud/createplaylist/node.go @@ -17,8 +17,14 @@ func NewSoundCloudCreatePlaylistNode(nodeID string) *SoundCloudCreatePlaylistNod Name: "SoundCloud Create Playlist", Description: "Create a new playlist on SoundCloud.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "soundcloud", + Glyph: "list", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"SoundCloud"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/soundcloud/createtrack/node.go b/apps/platform-api/internal/nodeengine/nodes/soundcloud/createtrack/node.go index c3a2a90..99e90d0 100644 --- a/apps/platform-api/internal/nodeengine/nodes/soundcloud/createtrack/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/soundcloud/createtrack/node.go @@ -17,8 +17,14 @@ func NewSoundCloudCreateTrackNode(nodeID string) *SoundCloudCreateTrackNode { Name: "SoundCloud Create Track", Description: "Upload a new track to SoundCloud.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "soundcloud", + Glyph: "music", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"SoundCloud"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/soundcloud/register.go b/apps/platform-api/internal/nodeengine/nodes/soundcloud/register.go index 9c062f2..c62f1a5 100644 --- a/apps/platform-api/internal/nodeengine/nodes/soundcloud/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/soundcloud/register.go @@ -36,7 +36,10 @@ func Register(fileGateway filegateway.FileGateway) { ID: nodeID, Name: "SoundCloud", Description: "Tools for managing SoundCloud tracks and playlists.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "soundcloud", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ createTrackNode, createPlaylistNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/sunomusic/createlyrics/node.go b/apps/platform-api/internal/nodeengine/nodes/sunomusic/createlyrics/node.go index 2afaef4..e7578cc 100644 --- a/apps/platform-api/internal/nodeengine/nodes/sunomusic/createlyrics/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/sunomusic/createlyrics/node.go @@ -17,8 +17,14 @@ func NewSunoMusicCreateLyricsNode(nodeID string) *SunoMusicCreateLyricsNode { Name: "Suno Create Lyrics", Description: "Generate song lyrics using Suno.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "sunomusic", + Glyph: "note", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Audio"}, SubCategories: []string{"Suno"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/sunomusic/createmusic/node.go b/apps/platform-api/internal/nodeengine/nodes/sunomusic/createmusic/node.go index 37cce16..5754cad 100644 --- a/apps/platform-api/internal/nodeengine/nodes/sunomusic/createmusic/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/sunomusic/createmusic/node.go @@ -18,8 +18,14 @@ func NewSunoMusicCreateMusicNode(nodeID string) *SunoMusicCreateMusicNode { Name: "Suno Create Music", Description: "Generate a music track using Suno.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "sunomusic", + Glyph: "music", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Audio"}, SubCategories: []string{"Suno"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/sunomusic/register.go b/apps/platform-api/internal/nodeengine/nodes/sunomusic/register.go index 3a0a3e3..9baf176 100644 --- a/apps/platform-api/internal/nodeengine/nodes/sunomusic/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/sunomusic/register.go @@ -35,7 +35,10 @@ func Register() { ID: nodeID, Name: "Suno Music", Description: "Tools for generating music and lyrics via Suno.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "sunomusic", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ createMusicNode, createLyricsNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/system/condition/executor.go b/apps/platform-api/internal/nodeengine/nodes/system/condition/executor.go index aff67ae..80accd9 100644 --- a/apps/platform-api/internal/nodeengine/nodes/system/condition/executor.go +++ b/apps/platform-api/internal/nodeengine/nodes/system/condition/executor.go @@ -42,6 +42,10 @@ func (e *ConditionExecutor) ExecuteWithContext(ctx context.Context, credentials case <-ctx.Done(): return nil, ctx.Err() default: + // TODO: only the first item is evaluated, so a node fed 10 items decides + // the whole flow from item 0. Routing items per branch needs the runner + // to carry item identity and keep outputs per edge; see the branching + // notes before changing this. input, err := e.validator.Parse(data[0]) if err != nil { return nil, err diff --git a/apps/platform-api/internal/nodeengine/nodes/system/condition/node.go b/apps/platform-api/internal/nodeengine/nodes/system/condition/node.go index 5a08cd5..5dfd749 100644 --- a/apps/platform-api/internal/nodeengine/nodes/system/condition/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/system/condition/node.go @@ -18,8 +18,14 @@ func NewConditionNode(nodeID string) *ConditionNode { Name: "Condition", Description: "Branch the workflow based on a conditional expression.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Glyph: "branch", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "true", Label: "True"}, + {Key: "false", Label: "False"}, }, Categories: []string{"System"}, SubCategories: []string{"System"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/system/sleep/node.go b/apps/platform-api/internal/nodeengine/nodes/system/sleep/node.go index 4c9d0f2..7f1c0a8 100644 --- a/apps/platform-api/internal/nodeengine/nodes/system/sleep/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/system/sleep/node.go @@ -18,8 +18,13 @@ func NewSleepNode(nodeID string) *SleepNode { Name: "Sleep", Description: "Pause the workflow for a specified duration.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Glyph: "clock", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"System"}, SubCategories: []string{"System"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/system/starter/node.go b/apps/platform-api/internal/nodeengine/nodes/system/starter/node.go index 900cf35..eb97499 100644 --- a/apps/platform-api/internal/nodeengine/nodes/system/starter/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/system/starter/node.go @@ -17,8 +17,11 @@ func NewStarterNode(nodeID string) *StarterNode { Name: "Starter", Description: "Entry point that starts the workflow execution.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Glyph: "play", + }, + Inputs: []nodes.NodeHandle{}, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"System"}, SubCategories: []string{"System"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/telegram/register.go b/apps/platform-api/internal/nodeengine/nodes/telegram/register.go index ed65556..cf7037b 100644 --- a/apps/platform-api/internal/nodeengine/nodes/telegram/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/telegram/register.go @@ -39,7 +39,10 @@ func Register() { ID: nodeID, Name: "Telegram", Description: "Tools for sending messages and media via Telegram.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "telegram", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ sendMessageNode, sendMediaNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/telegram/sendmedia/node.go b/apps/platform-api/internal/nodeengine/nodes/telegram/sendmedia/node.go index bf46e3d..e4dd68c 100644 --- a/apps/platform-api/internal/nodeengine/nodes/telegram/sendmedia/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/telegram/sendmedia/node.go @@ -17,8 +17,14 @@ func NewTelegramSendMediaNode(nodeID string) *TelegramSendMediaNode { Name: "Telegram Send Media", Description: "Send a media file to a Telegram chat.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "telegram", + Glyph: "image", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Telegram"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/telegram/sendmessage/node.go b/apps/platform-api/internal/nodeengine/nodes/telegram/sendmessage/node.go index b37ec4e..79400e5 100644 --- a/apps/platform-api/internal/nodeengine/nodes/telegram/sendmessage/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/telegram/sendmessage/node.go @@ -17,8 +17,14 @@ func NewTelegramSendMessageNode(nodeID string) *TelegramSendMessageNode { Name: "Telegram Send Message", Description: "Send a text message to a Telegram chat.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "telegram", + Glyph: "chat", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"Telegram"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/tiktok/publishpost/node.go b/apps/platform-api/internal/nodeengine/nodes/tiktok/publishpost/node.go index bdbf453..d65dbff 100644 --- a/apps/platform-api/internal/nodeengine/nodes/tiktok/publishpost/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/tiktok/publishpost/node.go @@ -17,8 +17,14 @@ func NewTiktokPublishPostNode(nodeID string) *TiktokPublishPostNode { Name: "TikTok Publish Post", Description: "Publish a video post to a TikTok account.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "tiktok", + Glyph: "send", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"TikTok"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/tiktok/register.go b/apps/platform-api/internal/nodeengine/nodes/tiktok/register.go index d9fcdec..b83f706 100644 --- a/apps/platform-api/internal/nodeengine/nodes/tiktok/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/tiktok/register.go @@ -26,7 +26,10 @@ func Register(fileGateway filegateway.FileGateway) { ID: nodeID, Name: "TikTok", Description: "Tools for publishing posts to TikTok.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "tiktok", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ publishPostNode, }, diff --git a/apps/platform-api/internal/nodeengine/nodes/veo/node.go b/apps/platform-api/internal/nodeengine/nodes/veo/node.go index 923b3fd..9d3dcda 100644 --- a/apps/platform-api/internal/nodeengine/nodes/veo/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/veo/node.go @@ -18,8 +18,14 @@ func NewVeoNode(nodeID string) *VeoNode { Name: "Veo", Description: "Generate a video from a text prompt using Veo.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "veo", + Glyph: "film", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Video"}, SubCategories: []string{"Veo"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/veo/register.go b/apps/platform-api/internal/nodeengine/nodes/veo/register.go index 2f60b1d..7ad3107 100644 --- a/apps/platform-api/internal/nodeengine/nodes/veo/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/veo/register.go @@ -24,7 +24,10 @@ func Register(fileGatewayService filegateway.FileGateway) { ID: nodeID, Name: "Veo", Description: "Tools for video generation via Google Veo.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "veo", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ veoNode, }, diff --git a/apps/platform-api/internal/nodeengine/nodes/whatsapp/register.go b/apps/platform-api/internal/nodeengine/nodes/whatsapp/register.go index 05ff32a..abcc46a 100644 --- a/apps/platform-api/internal/nodeengine/nodes/whatsapp/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/whatsapp/register.go @@ -49,7 +49,10 @@ func Register() { ID: nodeID, Name: "WhatsApp", Description: "Tools for sending text messages, templates, and media via WhatsApp.", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "whatsapp", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ sendMessageNode, sendTemplateNode, diff --git a/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendmedia/node.go b/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendmedia/node.go index 084463d..6b5dbb6 100644 --- a/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendmedia/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendmedia/node.go @@ -17,8 +17,14 @@ func NewWhatsAppSendMediaNode(nodeID string) *WhatsAppSendMediaNode { Name: "WhatsApp Send Media", Description: "Send a media message via WhatsApp.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "whatsapp", + Glyph: "image", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"WhatsApp"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendtemplate/node.go b/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendtemplate/node.go index 493d8e9..55bb508 100644 --- a/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendtemplate/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendtemplate/node.go @@ -18,8 +18,14 @@ func NewWhatsAppSendTemplateNode(nodeID string) *WhatsAppSendTemplateNode { Name: "WhatsApp Send Template", Description: "Send a template message via WhatsApp.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "whatsapp", + Glyph: "file", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"WhatsApp"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendtextmessage/node.go b/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendtextmessage/node.go index 5e958aa..b3a097e 100644 --- a/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendtextmessage/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/whatsapp/sendtextmessage/node.go @@ -17,8 +17,14 @@ func NewWhatsAppSendTextMessageNode(nodeID string) *WhatsAppSendTextMessageNode Name: "WhatsApp Send Text Message", Description: "Send a text message via WhatsApp.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "whatsapp", + Glyph: "chat", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"WhatsApp"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/x/publishmediapost/node.go b/apps/platform-api/internal/nodeengine/nodes/x/publishmediapost/node.go index a68e853..c222446 100644 --- a/apps/platform-api/internal/nodeengine/nodes/x/publishmediapost/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/x/publishmediapost/node.go @@ -17,8 +17,14 @@ func NewXPublishMediaPostNode(nodeID string) *XPublishMediaPostNode { Name: "X Publish Media Post", Description: "Publish a post with media to an X (Twitter) account.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "x", + Glyph: "image", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"X"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/x/publishpost/node.go b/apps/platform-api/internal/nodeengine/nodes/x/publishpost/node.go index 9d6e781..9dc1753 100644 --- a/apps/platform-api/internal/nodeengine/nodes/x/publishpost/node.go +++ b/apps/platform-api/internal/nodeengine/nodes/x/publishpost/node.go @@ -18,8 +18,14 @@ func NewXPublishPostNode(nodeID string) *XPublishPostNode { Name: "X Publish Post", Description: "Publish a post to an X (Twitter) account.", Icon: nodes.NodeIcon{ - Light: nodeID, - Dark: nodeID, + Brand: "x", + Glyph: "send", + }, + Inputs: []nodes.NodeHandle{ + {Key: "in"}, + }, + Outputs: []nodes.NodeHandle{ + {Key: "out"}, }, Categories: []string{"Publishing"}, SubCategories: []string{"X"}, diff --git a/apps/platform-api/internal/nodeengine/nodes/x/register.go b/apps/platform-api/internal/nodeengine/nodes/x/register.go index db55824..b04b03f 100644 --- a/apps/platform-api/internal/nodeengine/nodes/x/register.go +++ b/apps/platform-api/internal/nodeengine/nodes/x/register.go @@ -36,7 +36,10 @@ func Register(fileGateway filegateway.FileGateway) { ID: nodeID, Name: "X", Description: "Tools for publishing posts and media to X (Twitter).", - Version: "0.0.1", + Icon: mcp.ServerIcon{ + Brand: "x", + }, + Version: "0.0.1", Tools: []nodes.NodeManager{ publishPostNode, publishMediaPostNode, diff --git a/apps/platform/eslint.config.js b/apps/platform/eslint.config.js index d8230e2..fa6f046 100644 --- a/apps/platform/eslint.config.js +++ b/apps/platform/eslint.config.js @@ -3,6 +3,7 @@ import globals from 'globals' import reactHooks from 'eslint-plugin-react-hooks' import reactRefresh from 'eslint-plugin-react-refresh' import eslintConfigPrettier from 'eslint-config-prettier' +import tseslint from 'typescript-eslint' export default [ { ignores: ['dist'] }, @@ -32,4 +33,24 @@ export default [ }, }, eslintConfigPrettier, + { + // After the prettier config, which switches `curly` off — every branch + // states its scope, however short the body. + files: ['**/*.{js,jsx,ts,tsx}'], + languageOptions: { + parser: tseslint.parser, + parserOptions: { ecmaFeatures: { jsx: true } }, + }, + plugins: { '@typescript-eslint': tseslint.plugin }, + rules: { + curly: ['error', 'all'], + 'no-unused-vars': 'off', + // Unused imports and locals are dead weight; only underscore-prefixed + // arguments are allowed to stay. + '@typescript-eslint/no-unused-vars': [ + 'error', + { argsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' }, + ], + }, + }, ] diff --git a/apps/platform/package.json b/apps/platform/package.json index 0b615b6..f1896e8 100644 --- a/apps/platform/package.json +++ b/apps/platform/package.json @@ -33,7 +33,7 @@ "i18next": "26.3.6", "i18next-browser-languagedetector": "8.2.1", "i18next-http-backend": "4.0.1", - "lucide-react": "1.28.0", + "lucide-react": "1.29.0", "radix-ui": "1.6.7", "react": "19.2.8", "react-dom": "19.2.8", @@ -43,7 +43,7 @@ "react-timeago": "8.3.0", "remark-gfm": "4.0.1", "sonner": "2.0.7", - "swr": "2.4.2", + "swr": "2.5.0", "tailwind-merge": "3.6.0", "tailwindcss": "4.3.3", "zod": "4.4.3", @@ -54,18 +54,20 @@ "@types/geopattern": "1.2.9", "@types/react": "19.2.18", "@types/react-dom": "19.2.4", - "daisyui": "5.7.9", + "daisyui": "5.7.16", "eslint": "10.8.0", "eslint-config-prettier": "10.1.8", "eslint-plugin-react-hooks": "7.1.1", "eslint-plugin-react-refresh": "0.5.3", - "globals": "17.8.0", + "globals": "17.9.0", "husky": "9.1.7", "lint-staged": "17.3.0", "prettier": "3.9.6", - "shadcn": "4.16.1", + "shadcn": "4.16.2", "tw-animate-css": "1.4.0", - "vite": "8.2.0", + "typescript": "6.0.3", + "typescript-eslint": "8.66.0", + "vite": "8.2.1", "vite-plugin-remove-console": "2.2.0" }, "trustedDependencies": [ diff --git a/apps/platform/public/assets/icons/brands/airtable/dark.svg b/apps/platform/public/assets/icons/brands/airtable/dark.svg new file mode 100644 index 0000000..d665cd6 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/airtable/dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/airtable/light.svg b/apps/platform/public/assets/icons/brands/airtable/light.svg new file mode 100644 index 0000000..d665cd6 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/airtable/light.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/anthropic/dark.svg b/apps/platform/public/assets/icons/brands/anthropic/dark.svg new file mode 100644 index 0000000..53e1e5a --- /dev/null +++ b/apps/platform/public/assets/icons/brands/anthropic/dark.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/anthropic/light.svg b/apps/platform/public/assets/icons/brands/anthropic/light.svg new file mode 100644 index 0000000..53e1e5a --- /dev/null +++ b/apps/platform/public/assets/icons/brands/anthropic/light.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/chatgpt/dark.svg b/apps/platform/public/assets/icons/brands/chatgpt/dark.svg new file mode 100644 index 0000000..a9dd189 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/chatgpt/dark.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/chatgpt/light.svg b/apps/platform/public/assets/icons/brands/chatgpt/light.svg new file mode 100644 index 0000000..f1593b5 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/chatgpt/light.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/coingecko/dark.svg b/apps/platform/public/assets/icons/brands/coingecko/dark.svg new file mode 100644 index 0000000..63bb108 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/coingecko/dark.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/coingecko/light.svg b/apps/platform/public/assets/icons/brands/coingecko/light.svg new file mode 100644 index 0000000..63bb108 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/coingecko/light.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/deepl/dark.svg b/apps/platform/public/assets/icons/brands/deepl/dark.svg new file mode 100644 index 0000000..de6bbeb --- /dev/null +++ b/apps/platform/public/assets/icons/brands/deepl/dark.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/deepl/light.svg b/apps/platform/public/assets/icons/brands/deepl/light.svg new file mode 100644 index 0000000..de6bbeb --- /dev/null +++ b/apps/platform/public/assets/icons/brands/deepl/light.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/deepseek/dark.svg b/apps/platform/public/assets/icons/brands/deepseek/dark.svg new file mode 100644 index 0000000..023fc12 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/deepseek/dark.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/deepseek/light.svg b/apps/platform/public/assets/icons/brands/deepseek/light.svg new file mode 100644 index 0000000..023fc12 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/deepseek/light.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/discord/dark.svg b/apps/platform/public/assets/icons/brands/discord/dark.svg new file mode 100644 index 0000000..72e1638 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/discord/dark.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/discord/light.svg b/apps/platform/public/assets/icons/brands/discord/light.svg new file mode 100644 index 0000000..72e1638 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/discord/light.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/elevenlabs/dark.svg b/apps/platform/public/assets/icons/brands/elevenlabs/dark.svg new file mode 100644 index 0000000..ae54e65 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/elevenlabs/dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/platform/public/assets/icons/brands/elevenlabs/light.svg b/apps/platform/public/assets/icons/brands/elevenlabs/light.svg new file mode 100644 index 0000000..2632523 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/elevenlabs/light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/platform/public/assets/icons/brands/facebook/dark.svg b/apps/platform/public/assets/icons/brands/facebook/dark.svg new file mode 100644 index 0000000..1e5d22b --- /dev/null +++ b/apps/platform/public/assets/icons/brands/facebook/dark.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/facebook/light.svg b/apps/platform/public/assets/icons/brands/facebook/light.svg new file mode 100644 index 0000000..1e5d22b --- /dev/null +++ b/apps/platform/public/assets/icons/brands/facebook/light.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/gemini/dark.svg b/apps/platform/public/assets/icons/brands/gemini/dark.svg new file mode 100644 index 0000000..50d172c --- /dev/null +++ b/apps/platform/public/assets/icons/brands/gemini/dark.svg @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/gemini/light.svg b/apps/platform/public/assets/icons/brands/gemini/light.svg new file mode 100644 index 0000000..50d172c --- /dev/null +++ b/apps/platform/public/assets/icons/brands/gemini/light.svg @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/gmail/dark.svg b/apps/platform/public/assets/icons/brands/gmail/dark.svg new file mode 100644 index 0000000..1f48bd4 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/gmail/dark.svg @@ -0,0 +1,22 @@ + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/gmail/light.svg b/apps/platform/public/assets/icons/brands/gmail/light.svg new file mode 100644 index 0000000..1f48bd4 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/gmail/light.svg @@ -0,0 +1,22 @@ + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/google_docs/dark.svg b/apps/platform/public/assets/icons/brands/google_docs/dark.svg new file mode 100644 index 0000000..c372163 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/google_docs/dark.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/apps/platform/public/assets/icons/brands/google_docs/light.svg b/apps/platform/public/assets/icons/brands/google_docs/light.svg new file mode 100644 index 0000000..c372163 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/google_docs/light.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/apps/platform/public/assets/icons/brands/google_drive/dark.svg b/apps/platform/public/assets/icons/brands/google_drive/dark.svg new file mode 100644 index 0000000..2422dd2 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/google_drive/dark.svg @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/google_drive/light.svg b/apps/platform/public/assets/icons/brands/google_drive/light.svg new file mode 100644 index 0000000..2422dd2 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/google_drive/light.svg @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/google_keep/dark.svg b/apps/platform/public/assets/icons/brands/google_keep/dark.svg new file mode 100644 index 0000000..85e7ff4 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/google_keep/dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/google_keep/light.svg b/apps/platform/public/assets/icons/brands/google_keep/light.svg new file mode 100644 index 0000000..85e7ff4 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/google_keep/light.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/google_sheets/dark.svg b/apps/platform/public/assets/icons/brands/google_sheets/dark.svg new file mode 100644 index 0000000..509e400 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/google_sheets/dark.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/apps/platform/public/assets/icons/brands/google_sheets/light.svg b/apps/platform/public/assets/icons/brands/google_sheets/light.svg new file mode 100644 index 0000000..509e400 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/google_sheets/light.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/apps/platform/public/assets/icons/brands/instagram/dark.svg b/apps/platform/public/assets/icons/brands/instagram/dark.svg new file mode 100644 index 0000000..a29bb97 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/instagram/dark.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/instagram/light.svg b/apps/platform/public/assets/icons/brands/instagram/light.svg new file mode 100644 index 0000000..a29bb97 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/instagram/light.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/linkedin/dark.svg b/apps/platform/public/assets/icons/brands/linkedin/dark.svg new file mode 100644 index 0000000..d32f684 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/linkedin/dark.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/apps/platform/public/assets/icons/brands/linkedin/light.svg b/apps/platform/public/assets/icons/brands/linkedin/light.svg new file mode 100644 index 0000000..d32f684 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/linkedin/light.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/apps/platform/public/assets/icons/brands/notion/dark.svg b/apps/platform/public/assets/icons/brands/notion/dark.svg new file mode 100644 index 0000000..50511cf --- /dev/null +++ b/apps/platform/public/assets/icons/brands/notion/dark.svg @@ -0,0 +1,20 @@ + + + + + diff --git a/apps/platform/public/assets/icons/brands/notion/light.svg b/apps/platform/public/assets/icons/brands/notion/light.svg new file mode 100644 index 0000000..50511cf --- /dev/null +++ b/apps/platform/public/assets/icons/brands/notion/light.svg @@ -0,0 +1,20 @@ + + + + + diff --git a/apps/platform/public/assets/icons/brands/piapi/dark.svg b/apps/platform/public/assets/icons/brands/piapi/dark.svg new file mode 100644 index 0000000..14658ea --- /dev/null +++ b/apps/platform/public/assets/icons/brands/piapi/dark.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/piapi/light.svg b/apps/platform/public/assets/icons/brands/piapi/light.svg new file mode 100644 index 0000000..14658ea --- /dev/null +++ b/apps/platform/public/assets/icons/brands/piapi/light.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/sendgrid/dark.svg b/apps/platform/public/assets/icons/brands/sendgrid/dark.svg new file mode 100644 index 0000000..e2eeb79 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/sendgrid/dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/sendgrid/light.svg b/apps/platform/public/assets/icons/brands/sendgrid/light.svg new file mode 100644 index 0000000..e2eeb79 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/sendgrid/light.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/slack/dark.svg b/apps/platform/public/assets/icons/brands/slack/dark.svg new file mode 100644 index 0000000..7c6e1e4 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/slack/dark.svg @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/slack/light.svg b/apps/platform/public/assets/icons/brands/slack/light.svg new file mode 100644 index 0000000..7c6e1e4 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/slack/light.svg @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/soundcloud/dark.svg b/apps/platform/public/assets/icons/brands/soundcloud/dark.svg new file mode 100644 index 0000000..44430de --- /dev/null +++ b/apps/platform/public/assets/icons/brands/soundcloud/dark.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/soundcloud/light.svg b/apps/platform/public/assets/icons/brands/soundcloud/light.svg new file mode 100644 index 0000000..44430de --- /dev/null +++ b/apps/platform/public/assets/icons/brands/soundcloud/light.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/sunomusic/dark.svg b/apps/platform/public/assets/icons/brands/sunomusic/dark.svg new file mode 100644 index 0000000..a53a3eb --- /dev/null +++ b/apps/platform/public/assets/icons/brands/sunomusic/dark.svg @@ -0,0 +1,8 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/sunomusic/light.svg b/apps/platform/public/assets/icons/brands/sunomusic/light.svg new file mode 100644 index 0000000..f5bfe0d --- /dev/null +++ b/apps/platform/public/assets/icons/brands/sunomusic/light.svg @@ -0,0 +1,8 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/telegram/dark.svg b/apps/platform/public/assets/icons/brands/telegram/dark.svg new file mode 100644 index 0000000..628b14b --- /dev/null +++ b/apps/platform/public/assets/icons/brands/telegram/dark.svg @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/telegram/light.svg b/apps/platform/public/assets/icons/brands/telegram/light.svg new file mode 100644 index 0000000..628b14b --- /dev/null +++ b/apps/platform/public/assets/icons/brands/telegram/light.svg @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/tiktok/dark.svg b/apps/platform/public/assets/icons/brands/tiktok/dark.svg new file mode 100644 index 0000000..ba7c518 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/tiktok/dark.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/apps/platform/public/assets/icons/brands/tiktok/light.svg b/apps/platform/public/assets/icons/brands/tiktok/light.svg new file mode 100644 index 0000000..147cc2c --- /dev/null +++ b/apps/platform/public/assets/icons/brands/tiktok/light.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/apps/platform/public/assets/icons/brands/veo/dark.svg b/apps/platform/public/assets/icons/brands/veo/dark.svg new file mode 100644 index 0000000..50d172c --- /dev/null +++ b/apps/platform/public/assets/icons/brands/veo/dark.svg @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/veo/light.svg b/apps/platform/public/assets/icons/brands/veo/light.svg new file mode 100644 index 0000000..50d172c --- /dev/null +++ b/apps/platform/public/assets/icons/brands/veo/light.svg @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/whatsapp/dark.svg b/apps/platform/public/assets/icons/brands/whatsapp/dark.svg new file mode 100644 index 0000000..e9fc431 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/whatsapp/dark.svg @@ -0,0 +1,24 @@ + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/whatsapp/light.svg b/apps/platform/public/assets/icons/brands/whatsapp/light.svg new file mode 100644 index 0000000..e9fc431 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/whatsapp/light.svg @@ -0,0 +1,24 @@ + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/x/dark.svg b/apps/platform/public/assets/icons/brands/x/dark.svg new file mode 100644 index 0000000..485af02 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/x/dark.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/x/light.svg b/apps/platform/public/assets/icons/brands/x/light.svg new file mode 100644 index 0000000..5b8eebd --- /dev/null +++ b/apps/platform/public/assets/icons/brands/x/light.svg @@ -0,0 +1,6 @@ + + + diff --git a/apps/platform/public/assets/icons/brands/youtube/dark.svg b/apps/platform/public/assets/icons/brands/youtube/dark.svg new file mode 100644 index 0000000..b1f3c71 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/youtube/dark.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/brands/youtube/light.svg b/apps/platform/public/assets/icons/brands/youtube/light.svg new file mode 100644 index 0000000..b1f3c71 --- /dev/null +++ b/apps/platform/public/assets/icons/brands/youtube/light.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/apps/platform/public/assets/icons/glyphs/branch.svg b/apps/platform/public/assets/icons/glyphs/branch.svg new file mode 100644 index 0000000..70c7df8 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/branch.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/chat.svg b/apps/platform/public/assets/icons/glyphs/chat.svg new file mode 100644 index 0000000..1cf9585 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/chat.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/clock.svg b/apps/platform/public/assets/icons/glyphs/clock.svg new file mode 100644 index 0000000..a139253 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/clock.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/eye.svg b/apps/platform/public/assets/icons/glyphs/eye.svg new file mode 100644 index 0000000..2415ab4 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/eye.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/file.svg b/apps/platform/public/assets/icons/glyphs/file.svg new file mode 100644 index 0000000..101aa72 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/file.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/film.svg b/apps/platform/public/assets/icons/glyphs/film.svg new file mode 100644 index 0000000..90f12af --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/film.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/folder.svg b/apps/platform/public/assets/icons/glyphs/folder.svg new file mode 100644 index 0000000..b6ffb4f --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/folder.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/image.svg b/apps/platform/public/assets/icons/glyphs/image.svg new file mode 100644 index 0000000..bf27ae6 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/image.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/list.svg b/apps/platform/public/assets/icons/glyphs/list.svg new file mode 100644 index 0000000..4f55502 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/list.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/music.svg b/apps/platform/public/assets/icons/glyphs/music.svg new file mode 100644 index 0000000..40ad103 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/music.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/note.svg b/apps/platform/public/assets/icons/glyphs/note.svg new file mode 100644 index 0000000..2232f32 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/note.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/organize.svg b/apps/platform/public/assets/icons/glyphs/organize.svg new file mode 100644 index 0000000..d68a44a --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/organize.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/pencil.svg b/apps/platform/public/assets/icons/glyphs/pencil.svg new file mode 100644 index 0000000..6a752d6 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/pencil.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/play.svg b/apps/platform/public/assets/icons/glyphs/play.svg new file mode 100644 index 0000000..3658d0d --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/play.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/plus.svg b/apps/platform/public/assets/icons/glyphs/plus.svg new file mode 100644 index 0000000..6a7f549 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/record.svg b/apps/platform/public/assets/icons/glyphs/record.svg new file mode 100644 index 0000000..2ea8eba --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/record.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/search.svg b/apps/platform/public/assets/icons/glyphs/search.svg new file mode 100644 index 0000000..5e48905 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/send.svg b/apps/platform/public/assets/icons/glyphs/send.svg new file mode 100644 index 0000000..eaed8b9 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/send.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/speaker.svg b/apps/platform/public/assets/icons/glyphs/speaker.svg new file mode 100644 index 0000000..ee12a9d --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/speaker.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/story.svg b/apps/platform/public/assets/icons/glyphs/story.svg new file mode 100644 index 0000000..687269a --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/story.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/table.svg b/apps/platform/public/assets/icons/glyphs/table.svg new file mode 100644 index 0000000..adc057d --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/table.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/target.svg b/apps/platform/public/assets/icons/glyphs/target.svg new file mode 100644 index 0000000..e32c9e9 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/target.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/translate.svg b/apps/platform/public/assets/icons/glyphs/translate.svg new file mode 100644 index 0000000..4c225fe --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/translate.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/trash.svg b/apps/platform/public/assets/icons/glyphs/trash.svg new file mode 100644 index 0000000..523aca7 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/trash.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/trending.svg b/apps/platform/public/assets/icons/glyphs/trending.svg new file mode 100644 index 0000000..d9f2f29 --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/trending.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/assets/icons/glyphs/upload.svg b/apps/platform/public/assets/icons/glyphs/upload.svg new file mode 100644 index 0000000..b6a117a --- /dev/null +++ b/apps/platform/public/assets/icons/glyphs/upload.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/platform/public/locales/en/ui.json b/apps/platform/public/locales/en/ui.json index a609555..00861c2 100644 --- a/apps/platform/public/locales/en/ui.json +++ b/apps/platform/public/locales/en/ui.json @@ -2,36 +2,48 @@ "ui.text.aboutThisAgent": "About This Agent", "ui.text.aboutThisProject": "About this project", "ui.text.account": "account", + "ui.text.accountTitle": "Account", "ui.text.actions": "Actions", "ui.text.activate": "Activate", "ui.text.active": "Active", - "ui.text.allRightsReserved": "All rights reserved.", - "ui.text.annotationPlaceholder": "Annotate your flows any way you'd like.", - "ui.text.api": "API", - "ui.text.apiKey": "API Key", - "ui.text.apiKeyCreated": "API Key Created", - "ui.text.apiKeyCreatedDescription": "Copy your API key now. You won't be able to see it again.", - "ui.text.apiKeyDetailsDescription": "Review and manage this API key.", - "ui.text.apiKeys": "API Keys", - "ui.text.apiKeysDescription": "Manage API keys to trigger workflows programmatically.", - "ui.text.apiTrigger": "API Trigger", - "ui.text.apiTriggerDescription": "Trigger this flow from your own code using the API.", + "ui.text.activeSessions": "Active Sessions", + "ui.text.addAnnotationToFlow": "Add annotation to your flow", "ui.text.addCustomName": "Add Custom Name for this Node", "ui.text.addDocuments": "Add Documents (Max 3)", "ui.text.addGalleryImages": "Add Gallery Images (Max 10)", "ui.text.addItem": "Add Item", "ui.text.addLink": "Add Link", "ui.text.addOrganization": "Add Organization", + "ui.text.add_email": "Add email", + "ui.text.add_email_description": "Add an email address to enable email sign-in.", + "ui.text.add_email_failed": "Failed to add email. Please try again.", + "ui.text.add_email_sent": "Verification email sent", + "ui.text.add_email_sent_description": "We've sent a verification link to {{email}}. Click it to finish adding your email.", "ui.text.advanced": "Advanced", + "ui.text.agent": "Agent", "ui.text.agents": "Agents", + "ui.text.aiFlowBuilderDescription": "Let AI generate a workflow for you. Describe what you want and it will be created on the canvas.", "ui.text.alias": "Alias", "ui.text.all": "All", + "ui.text.allRightsReserved": "All rights reserved.", "ui.text.allowOthersEdit": "Allow others to edit this workflow", "ui.text.allowOthersToEdit": "Allow others to edit this workflow", "ui.text.allowOthersToEditDescription": "When enabled, other users with access can make changes to this workflow", "ui.text.alreadyPaidVerifyManually": "Already paid? Verify manually", + "ui.text.already_have_account": "Already have an account?", "ui.text.amount": "Amount", "ui.text.annotationNode": "Annotation", + "ui.text.annotationPlaceholder": "Annotate your flows any way you'd like.", + "ui.text.api": "API", + "ui.text.apiKey": "API Key", + "ui.text.apiKeyCreated": "API Key Created", + "ui.text.apiKeyCreatedDescription": "Copy your API key now. You won't be able to see it again.", + "ui.text.apiKeyDetailsDescription": "Review and manage this API key.", + "ui.text.apiKeys": "API Keys", + "ui.text.apiKeysDescription": "Manage API keys to trigger workflows programmatically.", + "ui.text.apiTrigger": "API Trigger", + "ui.text.apiTriggerDescription": "Trigger this flow from your own code using the API.", + "ui.text.appearance": "Appearance", "ui.text.apply": "Apply", "ui.text.archive": "Archive", "ui.text.archived": "Archived", @@ -39,11 +51,23 @@ "ui.text.areYouSure": "Are you absolutely sure?", "ui.text.attachFile": "Attach File", "ui.text.attachFiles": "Attach Files", + "ui.text.attachImageLink": "Attach an image link", + "ui.text.attachment": "Attachment", + "ui.text.attachments": "Attachments", + "ui.text.audioOutput": "Audio", "ui.text.authCompletedDescription": "Authentication is completed, close this window... and return to BlockNext", + "ui.text.authFailedDescription": "We couldn't complete your {{provider}} authentication. Please try again or contact support if the problem persists.", + "ui.text.authProviderFailed": "{{provider}} authentication failed. Please try again.", + "ui.text.authWaitDescription": "Please wait while we complete your authentication with {{provider}}. This may take a few moments.", + "ui.text.authenticationFailed": "Authentication Failed", + "ui.text.authorRole.system": "System", + "ui.text.authorRole.user": "You", "ui.text.authorize": "Authorize", + "ui.text.autoRenew": "Auto Renew", "ui.text.automatedTriggers": "Automated triggers for your workflows", "ui.text.back": "Back", "ui.text.backToLogin": "Back to Login", + "ui.text.back_to_sign_in": "Back to sign in", "ui.text.basic": "Basic", "ui.text.basicInformation": "Basic Information", "ui.text.billedAnnually": "Billed annually", @@ -63,6 +87,7 @@ "ui.text.cancel": "Cancel", "ui.text.cancelExecutionConfirmation": "This action cannot be undone. This will Terminate the running Execution and remove your data from our servers.", "ui.text.cancelled": "Cancelled", + "ui.text.cancelling": "Cancelling...", "ui.text.cannotBeUndone": "This action cannot be undone.", "ui.text.cardNumber": "Card number", "ui.text.category.ai": "AI", @@ -82,6 +107,17 @@ "ui.text.category.utility": "Utility", "ui.text.category.video": "Video", "ui.text.changeFlowTitle": "Change flow title", + "ui.text.change_email": "Change email", + "ui.text.change_email_description": "Update the email address on your account.", + "ui.text.change_email_failed": "Failed to change email. Please try again.", + "ui.text.change_email_sent": "Confirmation email sent", + "ui.text.change_email_sent_description": "We've sent a confirmation link to {{email}}. Click it to finish updating your email.", + "ui.text.change_password": "Change password", + "ui.text.change_password_description": "Update the password used to sign in to your account.", + "ui.text.change_password_failed": "Failed to change password. Please try again.", + "ui.text.change_password_success": "Your password has been changed.", + "ui.text.changelog": "Changelog", + "ui.text.changelogPlaceholder": "Describe what changed in this version (optional)", "ui.text.checkingBlockchain": "Checking the blockchain for your transaction...", "ui.text.chooseColor": "Choose your preferred color", "ui.text.chooseLanguage": "Choose your preferred language", @@ -90,47 +126,57 @@ "ui.text.clearLink": "Clear link", "ui.text.clearSearch": "Clear search", "ui.text.clearSelection": "Clear Selection", + "ui.text.clickNodeForSettings": "Configure Node Settings", + "ui.text.clickNodeForSettingsDescription": "Click any node on the canvas to open its settings panel, where you can write instructions and adjust parameters.", "ui.text.clickToUpload": "Click to upload", "ui.text.close": "Close", "ui.text.closeSidebar": "Close sidebar", "ui.text.color": "Color", + "ui.text.comingSoon": "Coming Soon", "ui.text.completed": "Completed", "ui.text.completedAt": "Completed At", + "ui.text.completingAuth": "Completing {{provider}} {{action}}", "ui.text.concurrentTasks": "Concurrent Tasks", "ui.text.configuration": "Configuration", "ui.text.confirmPassword": "Confirm Password", + "ui.text.confirm_email_change_title": "Confirming email change", "ui.text.confirmed": "Confirmed", "ui.text.connectAdditionalAccounts": "Connect Additional Accounts", "ui.text.connectOtherAccounts": "Connect your other accounts to this profile", "ui.text.connectYour": "Connect your", + "ui.text.connectYourAccount": "Connect your {{provider}} account", + "ui.text.connectionFailed": "Connection failed", "ui.text.connectionPoints": "Connection Points", "ui.text.continue": "Continue", "ui.text.continueOnError": "Continue on Error", "ui.text.continueOnErrorDescription": "Continue workflow execution even if this node fails", + "ui.text.continue_with": "Continue with {{provider}}", + "ui.text.continue_with_sso": "Continue with SSO", "ui.text.copiedToClipboard": "Copied to clipboard", - "ui.text.copyId": "Copy ID", "ui.text.copy": "Copy", + "ui.text.copyId": "Copy ID", + "ui.text.copyImage": "Copy Image", "ui.text.copyImageLink": "Copy image link", "ui.text.copyImageToClipboard": "Copy image to clipboard", + "ui.text.copyLink": "Copy Link", "ui.text.create": "Create", "ui.text.createApiKey": "Create API Key", "ui.text.createApiKeyDescription": "Give your API key a name to identify it later.", "ui.text.createFirstOrgDescription": "Create your first organization to start collaborating with your team", "ui.text.createFirstOrganization": "Create your first organization to start collaborating with your team", "ui.text.createFirstTrigger": "Create First Trigger", + "ui.text.createFlow": "Create Flow", + "ui.text.createNewVersion": "Create new version", "ui.text.createOrganization": "Create Organization", "ui.text.createOrganizationFailed": "Organization could not be created. Please try again.", "ui.text.createYourFirstOrganization": "Create your first organization", - "ui.text.creating": "Creating...", - "ui.text.createFlow": "Create Flow", - "ui.text.createNewVersion": "Create new version", + "ui.text.create_account": "Create account", "ui.text.created": "Created", - "ui.text.changelog": "Changelog", - "ui.text.changelogPlaceholder": "Describe what changed in this version (optional)", "ui.text.createdBy": "Created By", "ui.text.createdByOrgMembers": "Created by Organization Members", "ui.text.createdByOrganizationMembers": "Created by Organization Members", "ui.text.createdByYou": "Created by You", + "ui.text.creating": "Creating...", "ui.text.credentialSourceType": "Source", "ui.text.credentialSourceTypeOwner": "Owner", "ui.text.credentialSourceTypePlatform": "Platform", @@ -140,70 +186,9 @@ "ui.text.cronPattern": "Cron Pattern", "ui.text.current": "Current", "ui.text.currentItemInfo": "Current Item Information", - "ui.text.downloadImage": "Download image", - "ui.text.editLink": "Edit link", - "ui.text.editor.blockquote": "Blockquote", - "ui.text.editor.bold": "Bold", - "ui.text.editor.bulletList": "Bullet list", - "ui.text.editor.clearFormatting": "Clear formatting", - "ui.text.editor.code": "Code", - "ui.text.editor.codeBlock": "Code block", - "ui.text.editor.color.black": "Black", - "ui.text.editor.color.blue": "Blue", - "ui.text.editor.color.blueSubtle": "Blue subtle", - "ui.text.editor.color.boldBlue": "Bold blue", - "ui.text.editor.color.boldGreen": "Bold green", - "ui.text.editor.color.boldOrange": "Bold orange", - "ui.text.editor.color.boldPurple": "Bold purple", - "ui.text.editor.color.boldRed": "Bold red", - "ui.text.editor.color.boldTeal": "Bold teal", - "ui.text.editor.color.default": "Default", - "ui.text.editor.color.gray": "Gray", - "ui.text.editor.color.green": "Green", - "ui.text.editor.color.greenSubtle": "Green subtle", - "ui.text.editor.color.orange": "Orange", - "ui.text.editor.color.purple": "Purple", - "ui.text.editor.color.purpleSubtle": "Purple subtle", - "ui.text.editor.color.red": "Red", - "ui.text.editor.color.redSubtle": "Red subtle", - "ui.text.editor.color.teal": "Teal", - "ui.text.editor.color.tealSubtle": "Teal subtle", - "ui.text.editor.color.white": "White", - "ui.text.editor.color.yellowSubtle": "Yellow subtle", - "ui.text.editor.divider": "Divider", - "ui.text.editor.heading1": "Heading 1", - "ui.text.editor.heading2": "Heading 2", - "ui.text.editor.heading3": "Heading 3", - "ui.text.editor.heading4": "Heading 4", - "ui.text.editor.heading5": "Heading 5", - "ui.text.editor.heading6": "Heading 6", - "ui.text.editor.insertElements": "Insert elements", - "ui.text.editor.italic": "Italic", - "ui.text.editor.lists": "Lists", - "ui.text.editor.moreFormatting": "More formatting", - "ui.text.editor.moreOptions": "More options", - "ui.text.editor.normalText": "Normal Text", - "ui.text.editor.numberedList": "Numbered list", - "ui.text.editor.palette1": "Palette 1", - "ui.text.editor.palette2": "Palette 2", - "ui.text.editor.palette3": "Palette 3", - "ui.text.editor.strikethrough": "Strikethrough", - "ui.text.editor.textColor": "Text color", - "ui.text.editor.textStyles": "Text styles", - "ui.text.editor.underline": "Underline", - "ui.text.failedToLoadImage": "Failed to load image", - "ui.text.goToNextPage": "Go to next page", - "ui.text.goToPreviousPage": "Go to previous page", - "ui.text.image": "Image", - "ui.text.insertLink": "Insert link", - "ui.text.link": "Link", - "ui.text.loading": "Loading", - "ui.text.maxDocumentSize": "Max document size is {{max}}", - "ui.text.maxGallerySize": "Max gallery size is {{max}}", - "ui.text.more": "More", - "ui.text.morePages": "More pages", - "ui.text.noChangelog": "No changelog provided for this version.", - "ui.text.noVersionsYet": "No versions yet.", + "ui.text.currentSession": "Current", + "ui.text.current_password": "Current password", + "ui.text.current_password_required": "Current password is required", "ui.text.customizeAgent": "You can customize your agent step by step", "ui.text.customizeExperience": "Customize your Experience", "ui.text.cvc": "CVC", @@ -214,6 +199,7 @@ "ui.text.date": "Date", "ui.text.dayFreeTrial": "day free trial", "ui.text.delete": "Delete", + "ui.text.deleteApiKeyConfirmation": "This action cannot be undone. This will permanently delete your API key.", "ui.text.deleteBulkHistoryConfirmation": "This action cannot be undone. This will permanently delete {{count}} selected history item(s) and remove your data from our servers.", "ui.text.deleteFlowConfirmation": "This action cannot be undone. This will permanently delete your Flow and remove your data from our servers.", "ui.text.deleteFlowWarning": "This action cannot be undone. This will permanently delete your Flow and remove your data from our servers.", @@ -227,7 +213,6 @@ "ui.text.deleteSelected": "Delete Selected", "ui.text.deleteSelectedTriggerWarning": "This action cannot be undone. This will permanently delete", "ui.text.deleteSelectedTriggerWarning2": "selected trigger(s) and remove them from our servers.", - "ui.text.deleteApiKeyConfirmation": "This action cannot be undone. This will permanently delete your API key.", "ui.text.deleteTriggerConfirmation": "This action cannot be undone. This will permanently delete your trigger and remove it from our servers.", "ui.text.deleteTriggerWarning": "This action cannot be undone. This will permanently delete your trigger and remove it from our servers.", "ui.text.deleteTriggersBulkConfirmation": "This action cannot be undone. This will permanently delete {{count}} selected trigger(s) and remove them from our servers.", @@ -239,14 +224,19 @@ "ui.text.detailedDescriptionDescription": "Provide a comprehensive description of your workflow", "ui.text.detailedDescriptionText": "Update the comprehensive description of your workflow", "ui.text.details": "Details", + "ui.text.device": "Device", "ui.text.disabled": "Disabled", "ui.text.disabledDescription": "Skip this node during workflow execution", "ui.text.displayName": "Display Name", + "ui.text.displayTextOptional": "Display Text (optional)", + "ui.text.displaysMobileSidebar": "Displays the mobile sidebar.", "ui.text.disputed": "Disputed", "ui.text.docs": "Docs", - "ui.text.done": "Done", "ui.text.documents": "Documents", + "ui.text.done": "Done", "ui.text.downgrade": "Downgrade", + "ui.text.download": "Download", + "ui.text.downloadImage": "Download image", "ui.text.draft": "Draft", "ui.text.dragAndDropDescription": "Drag any node from here and drop it onto the canvas to add it to your workflow.", "ui.text.dragAndDropNodes": "Drag & Drop Nodes", @@ -258,39 +248,101 @@ "ui.text.editFlow": "Edit Flow", "ui.text.editFlowDescription": "Edit flows title and description", "ui.text.editFlowsTitleAndDescription": "Edit flows title and description", + "ui.text.editLink": "Edit link", "ui.text.editOrganizationDetails": "Edit your organization's details", "ui.text.editPermissions": "Edit Permissions", "ui.text.editPermissionsDescription": "Control who can modify this workflow", "ui.text.edited": "Edited", + "ui.text.editor.blockquote": "Blockquote", + "ui.text.editor.bold": "Bold", + "ui.text.editor.bulletList": "Bullet list", + "ui.text.editor.clearFormatting": "Clear formatting", + "ui.text.editor.code": "Code", + "ui.text.editor.codeBlock": "Code block", + "ui.text.editor.color.black": "Black", + "ui.text.editor.color.blue": "Blue", + "ui.text.editor.color.blueSubtle": "Blue subtle", + "ui.text.editor.color.boldBlue": "Bold blue", + "ui.text.editor.color.boldGreen": "Bold green", + "ui.text.editor.color.boldOrange": "Bold orange", + "ui.text.editor.color.boldPurple": "Bold purple", + "ui.text.editor.color.boldRed": "Bold red", + "ui.text.editor.color.boldTeal": "Bold teal", + "ui.text.editor.color.default": "Default", + "ui.text.editor.color.gray": "Gray", + "ui.text.editor.color.green": "Green", + "ui.text.editor.color.greenSubtle": "Green subtle", + "ui.text.editor.color.orange": "Orange", + "ui.text.editor.color.purple": "Purple", + "ui.text.editor.color.purpleSubtle": "Purple subtle", + "ui.text.editor.color.red": "Red", + "ui.text.editor.color.redSubtle": "Red subtle", + "ui.text.editor.color.teal": "Teal", + "ui.text.editor.color.tealSubtle": "Teal subtle", + "ui.text.editor.color.white": "White", + "ui.text.editor.color.yellowSubtle": "Yellow subtle", + "ui.text.editor.divider": "Divider", + "ui.text.editor.heading1": "Heading 1", + "ui.text.editor.heading2": "Heading 2", + "ui.text.editor.heading3": "Heading 3", + "ui.text.editor.heading4": "Heading 4", + "ui.text.editor.heading5": "Heading 5", + "ui.text.editor.heading6": "Heading 6", + "ui.text.editor.insertElements": "Insert elements", + "ui.text.editor.italic": "Italic", + "ui.text.editor.lists": "Lists", + "ui.text.editor.moreFormatting": "More formatting", + "ui.text.editor.moreOptions": "More options", + "ui.text.editor.normalText": "Normal Text", + "ui.text.editor.numberedList": "Numbered list", + "ui.text.editor.palette1": "Palette 1", + "ui.text.editor.palette2": "Palette 2", + "ui.text.editor.palette3": "Palette 3", + "ui.text.editor.strikethrough": "Strikethrough", + "ui.text.editor.textColor": "Text color", + "ui.text.editor.textStyles": "Text styles", + "ui.text.editor.underline": "Underline", "ui.text.emailAddress": "Email Address", "ui.text.emailDescription": "Enter the email address of the user", "ui.text.emailPlaceholder": "user@example.com", "ui.text.emailRequired": "Email is required", + "ui.text.email_change_confirmed": "Your email has been updated.", + "ui.text.email_change_failed": "Failed to confirm email change. The link may have expired.", + "ui.text.email_verification_failed": "Email verification failed. The link may have expired.", + "ui.text.email_verified": "Your email has been verified.", "ui.text.emptyWorkflow": "Workspace is empty.
Get started by creating a new flow.", "ui.text.emptyWorkflowTitle": "Create Your First Journey", + "ui.text.enabled": "Enabled", + "ui.text.endDate": "End", "ui.text.english": "English", "ui.text.enterCompellingName": "Enter a compelling name for your workflow", + "ui.text.enterDisplayText": "Enter display text", "ui.text.enterIdentifier": "Please enter the required information", "ui.text.enterNewTitleAndDescription": "Enter a new title and description for the duplicated flow.", "ui.text.enterOrgName": "Enter your organization name", "ui.text.enterOrganizationName": "Enter your organization name", + "ui.text.enterUrl": "Enter URL", "ui.text.error": "Error", - "ui.text.errorTitle": "Something went wrong", "ui.text.errorLoadingWorkflow": "Error loading workflow. Please try again.", "ui.text.errorMessage": "Error Message", + "ui.text.errorTitle": "Something went wrong", "ui.text.event": "Event", "ui.text.every15Minutes": "Every 15 minutes", "ui.text.every30Minutes": "Every 30 minutes", "ui.text.everyDay": "Every day", "ui.text.everyHour": "Every hour", "ui.text.executionSteps": "Execution Steps", + "ui.text.expired": "Expired", "ui.text.expires": "Expires", "ui.text.expiryDate": "Expiry", "ui.text.explore": "Explore", "ui.text.failed": "Failed", + "ui.text.failedToAction": "Failed to {{action}}", + "ui.text.failedToLoadImage": "Failed to load image", "ui.text.failure": "Failure", "ui.text.feature": "Feature", "ui.text.fileFormats": "PNG, JPG, MP4, MOV (MAX. 10MB)", + "ui.text.fileTooLarge": "File is too large. Maximum size is 10MB.", "ui.text.fileTypes": "PNG, JPG, MP4, MOV (MAX. 10MB)", "ui.text.files": "Files", "ui.text.finish": "Finish", @@ -299,9 +351,14 @@ "ui.text.flashLiteAI": "Flash-Lite AI", "ui.text.flow": "Flow", "ui.text.flowCopyTitle": "{{title}} (Copy)", + "ui.text.flowToolbar": "Flow Toolbar", + "ui.text.flowToolbarDescription": "Revert unsaved changes, run a test, or save your flow.", "ui.text.flows": "Flows", "ui.text.for": "for", "ui.text.forFree": "for free", + "ui.text.forgot_password": "Forgot password?", + "ui.text.forgot_password_description": "Enter your email and we'll send you a link to reset your password.", + "ui.text.forgot_password_title": "Reset your password", "ui.text.free": "Free", "ui.text.fullEarlyAccess": "Full Early Access", "ui.text.funding": "Funding", @@ -331,31 +388,42 @@ "ui.text.githubDescription": "Enter the GitHub username", "ui.text.githubPlaceholder": "username", "ui.text.goBack": "Go Back", - "ui.text.gotIt": "Got it", "ui.text.goToDashboard": "Go to Dashboard", "ui.text.goToHome": "Go to Home", + "ui.text.goToNextPage": "Go to next page", + "ui.text.goToPreviousPage": "Go to previous page", "ui.text.googleAccount": "Google Account", "ui.text.googleDescription": "Enter the Google email of the user", "ui.text.googlePlaceholder": "user@gmail.com", + "ui.text.gotIt": "Got it", "ui.text.hasUnsavedChanges": "You have unsaved changes", "ui.text.helpUsUnderstand": "Help us understand the issue", "ui.text.hide": "Hide", "ui.text.history": "History", "ui.text.home": "Home", "ui.text.howShouldFlowStart": "How should this flow start?", + "ui.text.image": "Image", + "ui.text.imageActionSuccess": "Image action success", + "ui.text.imageOutput": "Image", "ui.text.imageSizeLimit": "Image size must be less than 5MB", + "ui.text.imageValidationError": "Image validation error", "ui.text.images": "Images", "ui.text.inactive": "Inactive", "ui.text.initialSupply": "Initial Supply", "ui.text.initialSupplyError": "Initial supply must be a valid number", "ui.text.initialSupplyHelp": "Enter the total supply in wei (18 decimals)", "ui.text.inputs": "Inputs", + "ui.text.insertLink": "Insert link", + "ui.text.insufficientBalance": "Insufficient balance.", "ui.text.invalid": "Invalid", + "ui.text.invalidCallbackUrl": "Invalid callback URL. Please try again.", "ui.text.invalidDate": "Invalid Date", "ui.text.invalidEmail": "Please enter a valid email address", "ui.text.invalidGithub": "Please enter a valid GitHub username", "ui.text.invalidGoogle": "Please enter a valid Google email", + "ui.text.invalidOAuthResponse": "Invalid OAuth response. Please try again.", "ui.text.invalidProvider": "Invalid invitation method", + "ui.text.invalidStateParameter": "Invalid state parameter. Please try again.", "ui.text.invalidTxHashFormat": "Invalid transaction hash format. It should start with 0x and be 66 characters long.", "ui.text.invalidWallet": "Please enter a valid wallet address", "ui.text.invitationMethod": "Invitation Method", @@ -367,26 +435,35 @@ "ui.text.inviteMethod": "Invitation Method", "ui.text.inviteTitle": "Invite Member", "ui.text.inviting": "Inviting...", - "ui.text.markAllAsRead": "Mark all as read", - "ui.text.markAsRead": "Mark as read", + "ui.text.item": "Item", "ui.text.itemsCount": "{{count}} item", "ui.text.itemsCount_other": "{{count}} items", "ui.text.keepCancelled": "Keep Cancelled", "ui.text.language": "Language", "ui.text.lastActive": "Last Active", - "ui.text.lastUsed": "Last Used", "ui.text.lastUpdated": "Last Updated", + "ui.text.lastUsed": "Last Used", + "ui.text.leaveWithoutSaving": "Leave Without Saving", "ui.text.left": "Left", "ui.text.leftTo": "Left To", "ui.text.light": "Light", "ui.text.limitedEarlyAccess": "Limited Early Access", + "ui.text.link": "Link", "ui.text.linkedAccounts": "Linked Accounts", + "ui.text.linkingAccount": "Linking Account", "ui.text.listCaption": "A list of your organization members.", "ui.text.liveOffline": "Offline", "ui.text.liveOnline": "Live", "ui.text.liveReconnecting": "Reconnecting", + "ui.text.loading": "Loading", "ui.text.locked": "Locked", "ui.text.logOut": "Log out", + "ui.text.magic_link_consume_failed": "Failed to sign you in with this magic link. It may have expired.", + "ui.text.magic_link_consuming_title": "Signing you in", + "ui.text.magic_link_failed": "Failed to send magic link. Please try again.", + "ui.text.magic_link_sent": "Magic link sent", + "ui.text.magic_link_sent_description": "We've sent a sign-in link to {{email}}. Click it to continue.", + "ui.text.manageActiveSessions": "Manage your active sessions across devices.", "ui.text.manageConnectedAccounts": "Manage your connected accounts", "ui.text.manageOrgDetails": "Manage your organization's details and settings", "ui.text.manageOrganizationSettings": "Manage your organization's details and settings", @@ -394,12 +471,17 @@ "ui.text.manual": "Manual", "ui.text.manualTriggerDescription": "Run this flow manually with a prompt", "ui.text.manualVerification": "Manual Verification", + "ui.text.markAllAsRead": "Mark all as read", + "ui.text.markAsRead": "Mark as read", "ui.text.max": "Max", - "ui.text.maxRetries": "Max Retries", + "ui.text.maxDocumentSize": "Max document size is {{max}}", + "ui.text.maxGallerySize": "Max gallery size is {{max}}", + "ui.text.maxRetries": "Max Retries", "ui.text.maxRetriesDescription": "Maximum number of retry attempts on failure", "ui.text.maxSupply": "Max Supply", "ui.text.maxSupplyHelp": "Enter the maximum supply in wei (18 decimals)", "ui.text.mcpConnectionUrl": "Connection URL", + "ui.text.mcpCopyUrl": "Copy URL", "ui.text.mcpNoSearchResults": "No servers match your search.", "ui.text.mcpNoServersAvailable": "No MCP servers available yet.", "ui.text.mcpSearchPlaceholder": "Search servers...", @@ -413,9 +495,14 @@ "ui.text.members": "Members", "ui.text.membersTitle": "Organization Members", "ui.text.metamaskAccount": "MetaMask Wallet", + "ui.text.metamaskCallbackNotSupported": "MetaMask callback not supported via URL.", "ui.text.metamaskDescription": "Enter the MetaMask wallet address", + "ui.text.metamaskNotInstalled": "MetaMask is not installed", "ui.text.metamaskPlaceholder": "0x...", + "ui.text.metamask_login_failed": "MetaMask login failed", "ui.text.monthly": "Monthly", + "ui.text.more": "More", + "ui.text.morePages": "More pages", "ui.text.mostPopular": "Most Popular", "ui.text.myApiKey": "My API Key", "ui.text.myOrganization": "My Organization", @@ -428,67 +515,65 @@ "ui.text.never": "Never", "ui.text.neverUsed": "Never used", "ui.text.new": "New", + "ui.text.new_email": "New email", + "ui.text.new_password": "New password", "ui.text.next": "Next", + "ui.text.no": "No", + "ui.text.noActiveSessions": "No active sessions", "ui.text.noAdvancedSettings": "No advanced settings available for this node.", "ui.text.noApiKeys": "No API keys yet", "ui.text.noApiKeysDescription": "Create API keys to trigger workflows programmatically.", + "ui.text.noChangelog": "No changelog provided for this version.", "ui.text.noChargesMade": "No charges were made", "ui.text.noCredentials": "No credentials", "ui.text.noCredentialsDescription": "Use credentials to connect with external services or create and store custom sensitive information such as API Tokens and passwords", "ui.text.noCredentialsYet": "No credentials yet", "ui.text.noDescriptionProvided": "No description provided.", "ui.text.noEarlyAccess": "No Early Access", + "ui.text.noEndDate": "No end date", "ui.text.noFlows": "No Flows", "ui.text.noLinkedAccounts": "No linked accounts found", + "ui.text.noMessagesYet": "No messages yet", + "ui.text.noNodesFound": "No nodes found", + "ui.text.noNodesFoundDescription": "Try a different keyword or browse providers.", "ui.text.noNotifications": "No notifications yet", "ui.text.noNotificationsDescription": "You're all caught up. New notifications will appear here.", "ui.text.noOrganizationsYet": "No organizations yet", "ui.text.noProvidersAvailable": "No providers available", "ui.text.noRunHistoryDescription": "Once you start running workflows, their history will appear here for tracking and debugging.", "ui.text.noRunHistoryYet": "No run history yet", + "ui.text.noSearchResults": "No results found", + "ui.text.noSearchResultsDescription": "Try a different search term.", "ui.text.noTriggersDescription": "Create triggers to automatically run your workflows based on schedules or events.", "ui.text.noTriggersYet": "No triggers yet", - "ui.text.noWorkflowsFound": "No workflows found matching", + "ui.text.noVersionsYet": "No versions yet.", "ui.text.noWorkflowsAvailable": "No workflows available yet", - "ui.text.openLinkInNewTab": "Open link in a new tab", - "ui.text.pagination": "Pagination", - "ui.text.platformLogo": "Platform logo", - "ui.text.platformPreview": "Platform preview", - "ui.text.previous": "Previous", - "ui.text.privacyPolicy": "Privacy Policy", - "ui.text.removeImage": "Remove image", - "ui.text.required": "This field is required", - "ui.text.revokeAndRegenerateConfirmation": "This will invalidate the current key. Any integrations using it will stop working until updated with the new key.", - "ui.text.revokeAndRegenerateHint": "Invalidates the current key and creates a new one with the same settings.", - "ui.text.starterNode": "Starter", - "ui.text.starterNodeDescription": "Initiates workflow execution manually or automatically", - "ui.text.termsAndConditions": "Terms and Conditions", - "ui.text.toggleSidebar": "Toggle Sidebar", - "ui.text.unknown": "Unknown", - "ui.text.validationFailed": "Validation failed", - "ui.text.verifiedFlow": "Verified Flow", - "ui.text.verifiedOrganization": "Verified Organization", - "ui.text.verifiedUser": "Verified User", - "ui.text.viewImage": "View image", - "ui.text.viewProfile": "View Profile", + "ui.text.noWorkflowsFound": "No workflows found matching", + "ui.text.no_account": "Don't have an account?", "ui.text.nodeCategories": "Node Categories", "ui.text.nodeCategoriesDescription": "Browse nodes organized by categories. Click on any category to explore available nodes.", "ui.text.notifications": "Notifications", + "ui.text.objectOutput": "Object", "ui.text.off": "OFF", "ui.text.oneTime": "One-time", + "ui.text.oops": "Oops", + "ui.text.openInNewTab": "Open in New Tab", + "ui.text.openLink": "Open", + "ui.text.openLinkInNewTab": "Open link in a new tab", "ui.text.openMenu": "Open menu", "ui.text.openSidebar": "Open sidebar", "ui.text.optional": "Optional", + "ui.text.or": "OR", "ui.text.orEnterCustomAmount": "Or enter a custom amount", "ui.text.orgNameRequired": "Organization name is required", "ui.text.organization": "Organization", "ui.text.organizationDetails": "Organization Details", "ui.text.organizationFlows": "Organization Flows", + "ui.text.organizationId": "Organization ID", "ui.text.organizationIdRequired": "Organization ID is required", + "ui.text.organizationMembers": "Organization Members", "ui.text.organizationName": "Organization Name*", "ui.text.organizationSettings": "Organization Settings", - "ui.text.organizationMembers": "Organization Members", - "ui.text.oops": "Oops", "ui.text.organizations": "Organizations", "ui.text.otherOrganizations": "Other Organizations", "ui.text.outputs": "Outputs", @@ -496,35 +581,54 @@ "ui.text.own_token_selling": "Own Token Selling", "ui.text.pageNotFound": "Page Not Found", "ui.text.pageNotFoundDescription": "The page you're looking for doesn't exist or has been moved. Try going back to the home page.", + "ui.text.pagination": "Pagination", "ui.text.paid": "Paid", "ui.text.password": "Password", + "ui.text.password_login_failed": "Email or password is incorrect", + "ui.text.password_reset_failed": "Failed to reset password. The link may have expired.", + "ui.text.password_reset_request_failed": "Failed to send reset link. Please try again.", + "ui.text.password_reset_sent": "If an account exists for that email, a password reset link has been sent.", + "ui.text.password_reset_success": "Your password has been reset.", + "ui.text.password_too_short": "Password must be at least 8 characters", + "ui.text.passwords_do_not_match": "Passwords do not match", "ui.text.paste": "Paste", "ui.text.pause": "Pause", "ui.text.payFee": "Pay Fee", "ui.text.payWithMetamask": "Pay with MetaMask", "ui.text.pending": "Pending", "ui.text.perMonth": "/month", + "ui.text.period": "Period", "ui.text.pin": "Pin", "ui.text.pinned": "Pinned", "ui.text.platform": "Platform", + "ui.text.platformLogo": "Platform logo", "ui.text.platformNamePlaceholder": "Platform name (e.g., LinkedIn)", + "ui.text.platformPreview": "Platform preview", "ui.text.platformSession": "Session ID", "ui.text.pleaseAttachFile": "Please attach a file.", + "ui.text.pleaseEnterDescription": "Please enter a description.", + "ui.text.pleaseEnterReply": "Please enter a message.", + "ui.text.pleaseEnterSubject": "Please enter a subject.", "ui.text.pleaseEnterTitleAndDescription": "Please enter a title and description.", "ui.text.pleaseEnterTxHash": "Please enter a transaction hash", "ui.text.pleaseFillAllFields": "Please fill in all fields", "ui.text.pleaseSelectImageFile": "Please select an image file", + "ui.text.pleaseSelectType": "Please select a type.", "ui.text.pleaseWait": "Please wait...", "ui.text.preferences": "Preferences", + "ui.text.previous": "Previous", "ui.text.primary": "Primary", + "ui.text.privacyPolicy": "Privacy Policy", "ui.text.proAI": "Pro AI", "ui.text.processing": "Processing...", + "ui.text.profile": "Profile", "ui.text.projectProgress": "Project Progress", "ui.text.prompt": "Prompt", "ui.text.provideDescription": "Provide a description for this step", "ui.text.provideEssentialDetails": "Provide essential details about your organization", "ui.text.provideOrgDetails": "Provide essential details about your organization", "ui.text.provider": "Provider", + "ui.text.provider_not_found": "Authentication provider not found", "ui.text.publicationType": "Publication Type", "ui.text.publicationTypeDescription": "Choose how to share this workflow", "ui.text.rawExecutionData": "Raw Execution Data", @@ -535,26 +639,53 @@ "ui.text.recipient": "Recipient", "ui.text.redirectionIn": "Redirection in {{seconds}} seconds", "ui.text.refunded": "Refunded", + "ui.text.regenerateToken": "Regenerate Token", + "ui.text.regenerateTokenConfirmation": "This will invalidate the current webhook token. Any external service using it must be updated with the new token.", + "ui.text.regenerating": "Regenerating...", + "ui.text.register_failed": "Registration failed. Please try again.", + "ui.text.register_verification_sent": "Verification email sent", + "ui.text.register_verification_sent_description": "We've sent a verification link to {{email}}. Click it to finish creating your account and sign in.", + "ui.text.register_verification_title": "Check your email", "ui.text.remove": "Remove", "ui.text.removeAccountWarning": "Are you sure you want to remove the linked account", "ui.text.removeDescription": "This action will remove the member from the organization.\nYou need to invite the member again if you want to add them to your organization again.", + "ui.text.removeImage": "Remove image", "ui.text.removeLinkedAccount": "Remove Linked Account", + "ui.text.removeLinkedAccountConfirmation": "Are you sure you want to remove the linked account \"{{name}}\" ({{provider}})? This action cannot be undone.", "ui.text.removeMember": "Remove Member", "ui.text.removeMemberDescription": "This will remove the member from your organization. They will lose access to all organization resources.", + "ui.text.removeWebhookSecretConfirmation": "Remove the webhook secret? Deliveries will no longer be verified against it.", "ui.text.removing": "Removing...", - "ui.text.regenerateToken": "Regenerate Token", - "ui.text.regenerateTokenConfirmation": "This will invalidate the current webhook token. Any external service using it must be updated with the new token.", - "ui.text.regenerating": "Regenerating...", "ui.text.rename": "Rename", "ui.text.renameNode": "Rename Node", "ui.text.report": "Report", + "ui.text.request_new_link": "Request a new link", + "ui.text.required": "This field is required", "ui.text.resendVerification": "Resend verification", + "ui.text.reset_password": "Reset password", + "ui.text.reset_password_description": "Enter your new password below.", + "ui.text.reset_password_title": "Set a new password", + "ui.text.reset_token_missing": "The reset link is invalid or has expired.", + "ui.text.restoring": "Restoring...", "ui.text.result": "Result", "ui.text.resultCount": "{{count}} result", "ui.text.resultCount_other": "{{count}} results", "ui.text.results": "Results", "ui.text.retryDelay": "Retry Delay (ms)", "ui.text.retryDelayDescription": "Delay between retry attempts in milliseconds", + "ui.text.revertAllChanges": "Revert All Changes", + "ui.text.revoke": "Revoke", + "ui.text.revokeAll": "Revoke All", + "ui.text.revokeAllOtherSessions": "Revoke All Other Sessions", + "ui.text.revokeAllSessionsConfirm": "Revoke all other sessions?", + "ui.text.revokeAllSessionsDescription": "This will sign you out from all other devices. Your current session will remain active.", + "ui.text.revokeAndRegenerate": "Revoke & Regenerate", + "ui.text.revokeAndRegenerateConfirmation": "This will invalidate the current key. Any integrations using it will stop working until updated with the new key.", + "ui.text.revokeAndRegenerateHint": "Invalidates the current key and creates a new one with the same settings.", + "ui.text.revokeCurrentSession": "Revoke current session?", + "ui.text.revokeCurrentSessionDescription": "This will sign you out of your current session. You will need to sign in again.", + "ui.text.revokeThisSession": "Revoke this session?", + "ui.text.revokeThisSessionDescription": "This will sign out the device using this session ({{device}}).", "ui.text.right": "Right", "ui.text.rightClickDescription": "You can right-click on any node to see additional settings and configuration options.", "ui.text.rightClickForSettings": "Right-Click for Settings", @@ -574,6 +705,7 @@ "ui.text.runAs": "Run as", "ui.text.runBy": "Run By", "ui.text.runFirstFlow": "Run First Flow", + "ui.text.runFlow": "Run Flow", "ui.text.runHistory": "Run History", "ui.text.runHistoryDescription": "Flow run history for your organization", "ui.text.save": "Save", @@ -585,8 +717,8 @@ "ui.text.saveOrganizationSettings": "Save Organization Settings", "ui.text.saving": "Saving...", "ui.text.schedule": "Schedule", - "ui.text.scheduled": "Scheduled", "ui.text.scheduleTriggerDescription": "Run this flow on a recurring schedule", + "ui.text.scheduled": "Scheduled", "ui.text.scheduled_tasks": "Scheduled Tasks", "ui.text.scopeMcpInvoke": "Invoke MCP tools", "ui.text.scopeWorkflowsTrigger": "Trigger workflows programmatically", @@ -599,10 +731,13 @@ "ui.text.searchNotifications": "Search notifications", "ui.text.searchOrganizations": "Search organizations by Title or Description", "ui.text.searchPlaceholder": "Search workflows, status, or task ID...", + "ui.text.searchResults": "Search results", "ui.text.searchTriggers": "Search triggers by type, pattern, or ID...", "ui.text.searchWorkflows": "Search workflows by Title, Description, or Creator", "ui.text.searchWorkflowsPlaceholder": "Search workflows by Title, Description, or Creator", "ui.text.sectionFailedToLoadDescription": "This section failed to load. The rest of the app still works.", + "ui.text.security": "Security", + "ui.text.securityDescription": "Manage your password and email address.", "ui.text.seeBeyond": "See Beyond", "ui.text.select": "Select", "ui.text.selectANode": "Select a Node", @@ -611,6 +746,7 @@ "ui.text.selectCancelled": "Select Cancelled", "ui.text.selectCredentials": "Please select credentials to use", "ui.text.selectFailed": "Select Failed", + "ui.text.selectImage": "Select image", "ui.text.selectInactive": "Select Inactive", "ui.text.selectInvitationMethod": "Select invitation method", "ui.text.selectMethod": "Select invitation method", @@ -620,34 +756,61 @@ "ui.text.selectWebhookSource": "Select a webhook source", "ui.text.selectionsByBlockNext": "Selections by BlockNext", "ui.text.send": "Send", + "ui.text.sendReply": "Send Reply", + "ui.text.send_confirmation_email": "Send confirmation email", + "ui.text.send_magic_link": "Sign in with magic link", + "ui.text.send_reset_link": "Send reset link", + "ui.text.send_verification_email": "Send verification email", "ui.text.sending": "Sending...", - "ui.text.security": "Security", - "ui.text.securityDescription": "Manage your password and email address.", + "ui.text.sessionDataAppearAfterLogin": "Your session data will appear here after signing in.", "ui.text.sessionId": "Session ID", + "ui.text.sessions": "Sessions", "ui.text.setSchedule": "Set Schedule", "ui.text.setTimerForAgent": "Set Timer for this agent", + "ui.text.set_password": "Set password", + "ui.text.set_password_description": "Set a password to sign in with email.", + "ui.text.set_password_failed": "Failed to set password. Please try again.", "ui.text.settings": "Settings", "ui.text.show": "Show", "ui.text.showingResults": "Showing {{from}} to {{to}} of {{total}} results", "ui.text.sidebarDescription": "Click here to open the sidebar where you can access all available nodes and tools for building your workflow.", "ui.text.sidebarMenu": "Sidebar Menu", + "ui.text.sidebarTitle": "Sidebar", "ui.text.signIn": "Sign in", "ui.text.signInDescription": "Log in to unlock tailored content and stay connected with your community.", + "ui.text.sign_in": "Sign in", + "ui.text.sign_in.description": "Log in to unlock tailored content and stay connected with your community.", + "ui.text.sign_in.title": "Sign in", + "ui.text.sign_up.description": "Create an account to get started.", + "ui.text.sign_up.title": "Sign up", "ui.text.signedInVia": "Signed in via", + "ui.text.signingIn": "Signing In", "ui.text.skip": "Skip", "ui.text.somethingWentWrong": "Something went wrong. Please try again.", + "ui.text.startDate": "Start", "ui.text.startTour": "Start Tour", "ui.text.started": "Started", "ui.text.startedAt": "Started At", + "ui.text.starterNode": "Starter", + "ui.text.starterNodeDescription": "Initiates workflow execution manually or automatically", "ui.text.status": "Status", "ui.text.status.cancelled": "Cancelled", + "ui.text.status.closed": "Closed", "ui.text.status.failed": "Failed", + "ui.text.status.in_progress": "In Progress", + "ui.text.status.open": "Open", "ui.text.status.pending": "Pending", + "ui.text.status.rejected": "Rejected", + "ui.text.status.resolved": "Resolved", "ui.text.status.running": "Running", "ui.text.status.skipped": "Skipped", "ui.text.status.success": "Success", + "ui.text.stayOnPage": "Stay on Page", "ui.text.step": "Step", "ui.text.storeItems": "Store Items", + "ui.text.subject": "Subject", + "ui.text.subjectTooLong": "Subject must be 255 characters or fewer.", + "ui.text.submit": "Submit", "ui.text.success": "Success", "ui.text.successful": "Successful", "ui.text.summary": "Summary", @@ -656,12 +819,19 @@ "ui.text.symbolLengthError": "Symbol must be between 2 and 10 characters", "ui.text.system": "System", "ui.text.terminate": "Terminate", + "ui.text.terminated": "Terminated", + "ui.text.termsAndConditions": "Terms and Conditions", "ui.text.theme": "Theme", "ui.text.thisItemIsFree": "This item is free", "ui.text.timeout": "Timeout (ms)", "ui.text.timeoutDescription": "Maximum execution time in milliseconds", + "ui.text.timeset": "Timeset", "ui.text.timezone": "Timezone", "ui.text.title": "Title", + "ui.text.toggleSidebar": "Toggle Sidebar", + "ui.text.toolCount": "{{count}} tool", + "ui.text.toolCount_one": "{{count}} tool", + "ui.text.toolCount_other": "{{count}} tools", "ui.text.tools": "Tools", "ui.text.top": "Top", "ui.text.topTo": "Top To", @@ -670,6 +840,8 @@ "ui.text.totalSteps": "Total Steps", "ui.text.totalSupply": "Total Supply", "ui.text.totalTransactions": "Total Transactions", + "ui.text.tourCongratulations": "You're All Set!", + "ui.text.tourCongratulationsDescription": "You've completed the tour. Start building your workflow by dragging nodes onto the canvas or let AI generate one for you.", "ui.text.transactionHash": "Transaction Hash", "ui.text.transactionNotFoundOrInvalid": "Transaction not found or invalid. Please check your transaction hash.", "ui.text.transactionRejected": "Transaction was rejected by the user", @@ -685,11 +857,14 @@ "ui.text.turkce": "Türkçe", "ui.text.txHashHint": "You can find your transaction hash in your wallet's transaction history.", "ui.text.type": "Type", + "ui.text.uiKey": "UI Key", "ui.text.undoCancellation": "Undo Cancellation", + "ui.text.unknown": "Unknown", "ui.text.unpin": "Unpin", "ui.text.unsavedChanges": "Unsaved Changes", "ui.text.unsavedChangesDescription": "You have unsaved changes. Are you sure you want to leave?", "ui.text.untitledWorkflow": "Untitled Workflow", + "ui.text.unverified": "Unverified", "ui.text.update": "Update", "ui.text.updateAvailable": "Update available", "ui.text.updateDraftVersion": "Update draft version", @@ -698,28 +873,39 @@ "ui.text.updatedOn": "Updated on", "ui.text.updating": "Updating...", "ui.text.uploadDocuments": "Upload Documents", + "ui.text.uploadFromComputer": "Upload from your computer", "ui.text.uploadGalleryImages": "Upload Gallery Images", + "ui.text.uploadImageDescription": "Upload an image from your computer", + "ui.text.url": "URL", "ui.text.usePlatformCredential": "Use Platform Credential", "ui.text.usePlatformCredentialDescription": "Use pre-configured platform credentials (no API keys required)", "ui.text.user": "User", "ui.text.userId": "User ID", + "ui.text.userRejectedTransaction": "User rejected the transaction.", "ui.text.users": "Users", "ui.text.utc": "UTC", + "ui.text.validationFailed": "Validation failed", "ui.text.verificationFailed": "Verification Failed", - "ui.text.unverified": "Unverified", "ui.text.verified": "Verified", "ui.text.verifiedByBlockNext": "Verified By BlockNext", + "ui.text.verifiedFlow": "Verified Flow", + "ui.text.verifiedOrganization": "Verified Organization", + "ui.text.verifiedUser": "Verified User", "ui.text.verifyTransaction": "Verify Transaction", "ui.text.verifyTransactionInfo": "If you already sent a transaction but it wasn't automatically detected, you can manually verify it by entering your transaction hash.", + "ui.text.verify_email_title": "Verifying your email", "ui.text.verifying": "Verifying...", "ui.text.verifyingTransaction": "Verifying Transaction", "ui.text.version": "Version", "ui.text.versionHistory": "Version History", + "ui.text.videoOutput": "Video", "ui.text.view": "View", "ui.text.viewAll": "View all", "ui.text.viewFlows": "View Flows", + "ui.text.viewImage": "View image", "ui.text.viewOnBlockExplorer": "View on Block Explorer", "ui.text.viewOrganizations": "View organizations", + "ui.text.viewProfile": "View Profile", "ui.text.viewRawData": "View Raw Data", "ui.text.wallet": "Wallet", "ui.text.walletAddress": "Wallet Address", @@ -728,6 +914,13 @@ "ui.text.webhook": "Webhook", "ui.text.webhookCreated": "Webhook Created", "ui.text.webhookCreatedDescription": "Your webhook trigger has been created. Copy the token below to configure your external service.", + "ui.text.webhookSecret": "Webhook Secret", + "ui.text.webhookSecretConfigured": "A secret is set. Deliveries from verifying sources are checked against it.", + "ui.text.webhookSecretNotConfigured": "No secret set. Deliveries are accepted based on the webhook token alone.", + "ui.text.webhookSecretPlaceholder": "Paste the signing secret", + "ui.text.webhookSecretRemoved": "Webhook secret removed", + "ui.text.webhookSecretSaved": "Webhook secret saved", + "ui.text.webhookSourceVerified": "Deliveries from this source are verified against the webhook secret.", "ui.text.webhookTokenRegenerated": "Webhook Token Regenerated", "ui.text.webhookTokenRegeneratedDescription": "Your new webhook token has been generated. Copy it below — the old token is no longer valid.", "ui.text.webhookTokenWarning": "Save this token now. You won't be able to see it again for security reasons.", @@ -735,14 +928,6 @@ "ui.text.webhookUrl": "Webhook URL", "ui.text.webhookUrlReplaceToken": "Replace {token} with your webhook token to get the full URL.", "ui.text.webhookUrls": "Webhook URLs", - "ui.text.webhookSecret": "Webhook Secret", - "ui.text.webhookSourceVerified": "Deliveries from this source are verified against the webhook secret.", - "ui.text.webhookSecretPlaceholder": "Paste the signing secret", - "ui.text.webhookSecretConfigured": "A secret is set. Deliveries from verifying sources are checked against it.", - "ui.text.webhookSecretNotConfigured": "No secret set. Deliveries are accepted based on the webhook token alone.", - "ui.text.webhookSecretRemoved": "Webhook secret removed", - "ui.text.webhookSecretSaved": "Webhook secret saved", - "ui.text.removeWebhookSecretConfirmation": "Remove the webhook secret? Deliveries will no longer be verified against it.", "ui.text.webhook_triggers": "Webhook Triggers", "ui.text.welcomeDescription": "Here you can explore and experiment with flows. Create, connect, and learn how automation works, your journey starts now!", "ui.text.welcomeToBlockNext": "Welcome to BlockNext", @@ -752,190 +937,12 @@ "ui.text.workflowInformation": "Workflow Information", "ui.text.workflowSummary": "Workflow Summary", "ui.text.workflows": "Workflows", + "ui.text.writeReply": "Write a reply...", "ui.text.writeSomething": "Write something...", "ui.text.writeYourInspirationHere": "Write your inspiration here", "ui.text.writeYourInstructions": "Write your instructions", "ui.text.yearly": "Annually", - "ui.text.timeset": "Timeset", - "ui.text.organizationId": "Organization ID", - "ui.text.removeLinkedAccountConfirmation": "Are you sure you want to remove the linked account \"{{name}}\" ({{provider}})? This action cannot be undone.", - "ui.text.connectYourAccount": "Connect your {{provider}} account", - "ui.text.noActiveSessions": "No active sessions", - "ui.text.sessionDataAppearAfterLogin": "Your session data will appear here after signing in.", - "ui.text.activeSessions": "Active Sessions", - "ui.text.manageActiveSessions": "Manage your active sessions across devices.", - "ui.text.revokeAndRegenerate": "Revoke & Regenerate", - "ui.text.revokeAllOtherSessions": "Revoke All Other Sessions", - "ui.text.revokeAllSessionsConfirm": "Revoke all other sessions?", - "ui.text.revokeAllSessionsDescription": "This will sign you out from all other devices. Your current session will remain active.", - "ui.text.revokeAll": "Revoke All", - "ui.text.device": "Device", - "ui.text.currentSession": "Current", - "ui.text.revokeCurrentSession": "Revoke current session?", - "ui.text.revokeCurrentSessionDescription": "This will sign you out of your current session. You will need to sign in again.", - "ui.text.revokeThisSession": "Revoke this session?", - "ui.text.revokeThisSessionDescription": "This will sign out the device using this session ({{device}}).", - "ui.text.revoke": "Revoke", - "ui.text.stayOnPage": "Stay on Page", - "ui.text.leaveWithoutSaving": "Leave Without Saving", - "ui.text.addAnnotationToFlow": "Add annotation to your flow", - "ui.text.or": "OR", - "ui.text.autoRenew": "Auto Renew", - "ui.text.enabled": "Enabled", - "ui.text.period": "Period", - "ui.text.noSearchResults": "No results found", - "ui.text.noSearchResultsDescription": "Try a different search term.", - "ui.text.startDate": "Start", - "ui.text.endDate": "End", - "ui.text.noEndDate": "No end date", "ui.text.yes": "Yes", - "ui.text.no": "No", - "ui.text.cancelling": "Cancelling...", "ui.text.yesCancel": "Yes, Cancel", - "ui.text.restoring": "Restoring...", - "ui.text.yesRestore": "Yes, Restore", - "ui.text.invalidCallbackUrl": "Invalid callback URL. Please try again.", - "ui.text.invalidStateParameter": "Invalid state parameter. Please try again.", - "ui.text.metamaskCallbackNotSupported": "MetaMask callback not supported via URL.", - "ui.text.invalidOAuthResponse": "Invalid OAuth response. Please try again.", - "ui.text.authenticationFailed": "Authentication Failed", - "ui.text.authFailedDescription": "We couldn't complete your {{provider}} authentication. Please try again or contact support if the problem persists.", - "ui.text.completingAuth": "Completing {{provider}} {{action}}", - "ui.text.authWaitDescription": "Please wait while we complete your authentication with {{provider}}. This may take a few moments.", - "ui.text.linkingAccount": "Linking Account", - "ui.text.signingIn": "Signing In", - "ui.text.authProviderFailed": "{{provider}} authentication failed. Please try again.", - "ui.text.metamaskNotInstalled": "MetaMask is not installed", - "ui.text.userRejectedTransaction": "User rejected the transaction.", - "ui.text.insufficientBalance": "Insufficient balance.", - "ui.text.uiKey": "UI Key", - "ui.text.attachImageLink": "Attach an image link", - "ui.text.submit": "Submit", - "ui.text.uploadFromComputer": "Upload from your computer", - "ui.text.selectImage": "Select image", - "ui.text.uploadImageDescription": "Upload an image from your computer", - "ui.text.enterUrl": "Enter URL", - "ui.text.displayTextOptional": "Display Text (optional)", - "ui.text.enterDisplayText": "Enter display text", - "ui.text.openInNewTab": "Open in New Tab", - "ui.text.imageValidationError": "Image validation error", - "ui.text.copyImage": "Copy Image", - "ui.text.copyLink": "Copy Link", - "ui.text.download": "Download", - "ui.text.imageActionSuccess": "Image action success", - "ui.text.failedToAction": "Failed to {{action}}", - "ui.text.connectionFailed": "Connection failed", - "ui.text.imageOutput": "Image", - "ui.text.videoOutput": "Video", - "ui.text.audioOutput": "Audio", - "ui.text.objectOutput": "Object", - "ui.text.openLink": "Open", - "ui.text.agent": "Agent", - "ui.text.item": "Item", - "ui.text.sidebarTitle": "Sidebar", - "ui.text.displaysMobileSidebar": "Displays the mobile sidebar.", - "ui.text.accountTitle": "Account", - "ui.text.profile": "Profile", - "ui.text.appearance": "Appearance", - "ui.text.sessions": "Sessions", - "ui.text.url": "URL", - "ui.text.expired": "Expired", - "ui.text.terminated": "Terminated", - "ui.text.revertAllChanges": "Revert All Changes", - "ui.text.runFlow": "Run Flow", - "ui.text.aiFlowBuilderDescription": "Let AI generate a workflow for you. Describe what you want and it will be created on the canvas.", - "ui.text.clickNodeForSettings": "Configure Node Settings", - "ui.text.clickNodeForSettingsDescription": "Click any node on the canvas to open its settings panel, where you can write instructions and adjust parameters.", - "ui.text.flowToolbar": "Flow Toolbar", - "ui.text.flowToolbarDescription": "Revert unsaved changes, run a test, or save your flow.", - "ui.text.tourCongratulations": "You're All Set!", - "ui.text.tourCongratulationsDescription": "You've completed the tour. Start building your workflow by dragging nodes onto the canvas or let AI generate one for you.", - "ui.text.subject": "Subject", - "ui.text.fileTooLarge": "File is too large. Maximum size is 10MB.", - "ui.text.pleaseSelectType": "Please select a type.", - "ui.text.pleaseEnterSubject": "Please enter a subject.", - "ui.text.pleaseEnterDescription": "Please enter a description.", - "ui.text.subjectTooLong": "Subject must be 255 characters or fewer.", - "ui.text.pleaseEnterReply": "Please enter a message.", - "ui.text.status.open": "Open", - "ui.text.status.in_progress": "In Progress", - "ui.text.status.resolved": "Resolved", - "ui.text.status.closed": "Closed", - "ui.text.status.rejected": "Rejected", - "ui.text.writeReply": "Write a reply...", - "ui.text.sendReply": "Send Reply", - "ui.text.attachment": "Attachment", - "ui.text.authorRole.user": "You", - "ui.text.authorRole.system": "System", - "ui.text.attachments": "Attachments", - "ui.text.noMessagesYet": "No messages yet", - "ui.text.sign_in.description": "Log in to unlock tailored content and stay connected with your community.", - "ui.text.sign_in.title": "Sign in", - "ui.text.sign_up.description": "Create an account to get started.", - "ui.text.sign_up.title": "Sign up", - "ui.text.comingSoon": "Coming Soon", - "ui.text.add_email": "Add email", - "ui.text.add_email_description": "Add an email address to enable email sign-in.", - "ui.text.add_email_failed": "Failed to add email. Please try again.", - "ui.text.add_email_sent": "Verification email sent", - "ui.text.add_email_sent_description": "We've sent a verification link to {{email}}. Click it to finish adding your email.", - "ui.text.already_have_account": "Already have an account?", - "ui.text.back_to_sign_in": "Back to sign in", - "ui.text.change_email": "Change email", - "ui.text.change_email_description": "Update the email address on your account.", - "ui.text.change_email_failed": "Failed to change email. Please try again.", - "ui.text.change_email_sent": "Confirmation email sent", - "ui.text.change_email_sent_description": "We've sent a confirmation link to {{email}}. Click it to finish updating your email.", - "ui.text.change_password": "Change password", - "ui.text.change_password_description": "Update the password used to sign in to your account.", - "ui.text.change_password_failed": "Failed to change password. Please try again.", - "ui.text.change_password_success": "Your password has been changed.", - "ui.text.confirm_email_change_title": "Confirming email change", - "ui.text.continue_with": "Continue with {{provider}}", - "ui.text.continue_with_sso": "Continue with SSO", - "ui.text.create_account": "Create account", - "ui.text.current_password": "Current password", - "ui.text.current_password_required": "Current password is required", - "ui.text.email_change_confirmed": "Your email has been updated.", - "ui.text.email_change_failed": "Failed to confirm email change. The link may have expired.", - "ui.text.email_verification_failed": "Email verification failed. The link may have expired.", - "ui.text.email_verified": "Your email has been verified.", - "ui.text.forgot_password": "Forgot password?", - "ui.text.forgot_password_description": "Enter your email and we'll send you a link to reset your password.", - "ui.text.forgot_password_title": "Reset your password", - "ui.text.magic_link_consume_failed": "Failed to sign you in with this magic link. It may have expired.", - "ui.text.magic_link_consuming_title": "Signing you in", - "ui.text.magic_link_failed": "Failed to send magic link. Please try again.", - "ui.text.magic_link_sent": "Magic link sent", - "ui.text.magic_link_sent_description": "We've sent a sign-in link to {{email}}. Click it to continue.", - "ui.text.metamask_login_failed": "MetaMask login failed", - "ui.text.new_email": "New email", - "ui.text.new_password": "New password", - "ui.text.no_account": "Don't have an account?", - "ui.text.password_login_failed": "Email or password is incorrect", - "ui.text.password_reset_failed": "Failed to reset password. The link may have expired.", - "ui.text.password_reset_request_failed": "Failed to send reset link. Please try again.", - "ui.text.password_reset_sent": "If an account exists for that email, a password reset link has been sent.", - "ui.text.password_reset_success": "Your password has been reset.", - "ui.text.password_too_short": "Password must be at least 8 characters", - "ui.text.passwords_do_not_match": "Passwords do not match", - "ui.text.provider_not_found": "Authentication provider not found", - "ui.text.register_failed": "Registration failed. Please try again.", - "ui.text.register_verification_sent": "Verification email sent", - "ui.text.register_verification_sent_description": "We've sent a verification link to {{email}}. Click it to finish creating your account and sign in.", - "ui.text.register_verification_title": "Check your email", - "ui.text.request_new_link": "Request a new link", - "ui.text.reset_password": "Reset password", - "ui.text.reset_password_description": "Enter your new password below.", - "ui.text.reset_password_title": "Set a new password", - "ui.text.reset_token_missing": "The reset link is invalid or has expired.", - "ui.text.send_confirmation_email": "Send confirmation email", - "ui.text.send_magic_link": "Sign in with magic link", - "ui.text.send_reset_link": "Send reset link", - "ui.text.send_verification_email": "Send verification email", - "ui.text.set_password": "Set password", - "ui.text.set_password_description": "Set a password to sign in with email.", - "ui.text.set_password_failed": "Failed to set password. Please try again.", - "ui.text.verify_email_title": "Verifying your email", - "ui.text.sign_in": "Sign in" + "ui.text.yesRestore": "Yes, Restore" } diff --git a/apps/platform/src/components/shared/advanced-debounced-textarea.tsx b/apps/platform/src/components/shared/advanced-debounced-textarea.tsx index 1aa5732..4cf5576 100644 --- a/apps/platform/src/components/shared/advanced-debounced-textarea.tsx +++ b/apps/platform/src/components/shared/advanced-debounced-textarea.tsx @@ -22,14 +22,18 @@ export const AdvancedDebouncedTextarea = React.memo( useEffect(() => { return () => { - if (timeoutRef.current) clearTimeout(timeoutRef.current) + if (timeoutRef.current) { + clearTimeout(timeoutRef.current) + } } }, []) const handleChange = (e: React.ChangeEvent) => { const newText = e.target.value setText(newText) - if (timeoutRef.current) clearTimeout(timeoutRef.current) + if (timeoutRef.current) { + clearTimeout(timeoutRef.current) + } timeoutRef.current = setTimeout(() => { props.onChange?.(newText) }, 500) diff --git a/apps/platform/src/components/shared/app-pagination.tsx b/apps/platform/src/components/shared/app-pagination.tsx index 6e34dee..d71f177 100644 --- a/apps/platform/src/components/shared/app-pagination.tsx +++ b/apps/platform/src/components/shared/app-pagination.tsx @@ -31,11 +31,17 @@ function computePages(current: number, total: number): Array { return Array.from({ length: total }, (_, i) => i + 1) } const pages: Array = [1] - if (current > 3) pages.push('ellipsis-start') + if (current > 3) { + pages.push('ellipsis-start') + } const start = Math.max(2, current - 1) const end = Math.min(total - 1, current + 1) - for (let i = start; i <= end; i++) pages.push(i) - if (current < total - 2) pages.push('ellipsis-end') + for (let i = start; i <= end; i++) { + pages.push(i) + } + if (current < total - 2) { + pages.push('ellipsis-end') + } pages.push(total) return pages } @@ -58,7 +64,9 @@ export function AppPagination({ [currentPage, totalPages], ) - if (total <= 0) return null + if (total <= 0) { + return null + } return (
diff --git a/apps/platform/src/components/shared/custom-icons.tsx b/apps/platform/src/components/shared/custom-icons.tsx index 87f1305..8ec504b 100644 --- a/apps/platform/src/components/shared/custom-icons.tsx +++ b/apps/platform/src/components/shared/custom-icons.tsx @@ -44,10 +44,14 @@ const flowIconCache = new Map() export const FlowIcon = (seed: string) => { const cached = flowIconCache.get(seed) - if (cached) return cached + if (cached) { + return cached + } let hash = 0 - for (let i = 0; i < seed.length; i++) hash += seed.charCodeAt(i) + for (let i = 0; i < seed.length; i++) { + hash += seed.charCodeAt(i) + } const baseColor = FLOW_ICON_COLORS[hash % FLOW_ICON_COLORS.length] const dataUrl = generate(seed, { baseColor }).toDataUrl() diff --git a/apps/platform/src/components/shared/search-input.tsx b/apps/platform/src/components/shared/search-input.tsx index 2a254d1..9c3ab50 100644 --- a/apps/platform/src/components/shared/search-input.tsx +++ b/apps/platform/src/components/shared/search-input.tsx @@ -34,12 +34,16 @@ export function SearchInput({ useEffect(() => { return () => { - if (timeoutRef.current) clearTimeout(timeoutRef.current) + if (timeoutRef.current) { + clearTimeout(timeoutRef.current) + } } }, []) const fireSearch = (next: string) => { - if (timeoutRef.current) clearTimeout(timeoutRef.current) + if (timeoutRef.current) { + clearTimeout(timeoutRef.current) + } timeoutRef.current = setTimeout(() => { onSearchRef.current(next) }, debounceMs) @@ -53,7 +57,9 @@ export function SearchInput({ const handleClear = () => { setValue('') - if (timeoutRef.current) clearTimeout(timeoutRef.current) + if (timeoutRef.current) { + clearTimeout(timeoutRef.current) + } onSearchRef.current('') } diff --git a/apps/platform/src/features/api-keys/components/api-key-tab.tsx b/apps/platform/src/features/api-keys/components/api-key-tab.tsx index 11391eb..b5b8aea 100644 --- a/apps/platform/src/features/api-keys/components/api-key-tab.tsx +++ b/apps/platform/src/features/api-keys/components/api-key-tab.tsx @@ -73,7 +73,9 @@ const APIKeyTab = ({ ) const handleCreate = async () => { - if (!selectedScopes.length) return + if (!selectedScopes.length) { + return + } const created = await onCreate({ name: newKeyName || t('ui.text.apiKey', 'API Key'), scopes: selectedScopes, @@ -195,7 +197,9 @@ const APIKeyTab = ({ open={createOpen} onOpenChange={(open) => { setCreateOpen(open) - if (!open) resetCreateForm() + if (!open) { + resetCreateForm() + } }} > diff --git a/apps/platform/src/features/api-keys/hooks/use-api-keys.ts b/apps/platform/src/features/api-keys/hooks/use-api-keys.ts index 3a70151..d89a66d 100644 --- a/apps/platform/src/features/api-keys/hooks/use-api-keys.ts +++ b/apps/platform/src/features/api-keys/hooks/use-api-keys.ts @@ -58,7 +58,9 @@ export function useOrganizationApiKeys( const handleCreate = useCallback( async (payload: unknown) => { - if (!organizationId) return null + if (!organizationId) { + return null + } const res = await apiKeysService.createOrganizationApiKey( organizationId, payload as never, @@ -74,7 +76,9 @@ export function useOrganizationApiKeys( const handleRegenerate = useCallback( async (apiKeyId: string, payload: unknown) => { - if (!organizationId) return null + if (!organizationId) { + return null + } const res = await apiKeysService.regenerateOrganizationApiKey( organizationId, apiKeyId, @@ -91,7 +95,9 @@ export function useOrganizationApiKeys( const handleDelete = useCallback( async (apiKeyId: string) => { - if (!organizationId) return + if (!organizationId) { + return + } await apiKeysService.deleteOrganizationApiKey(organizationId, apiKeyId) await revalidate() }, diff --git a/apps/platform/src/features/api-keys/services/api-keys.ts b/apps/platform/src/features/api-keys/services/api-keys.ts index dc77dba..6b4ebdd 100644 --- a/apps/platform/src/features/api-keys/services/api-keys.ts +++ b/apps/platform/src/features/api-keys/services/api-keys.ts @@ -7,7 +7,9 @@ const getOrganizationApiKeys = async ( const params = new URLSearchParams() params.set('offset', String(offset)) params.set('limit', String(limit)) - if (query) params.set('query', query) + if (query) { + params.set('query', query) + } return await platformApi.get( `/organizations/${organizationId}/api-keys?${params.toString()}`, ) diff --git a/apps/platform/src/features/auth/components/providers/change-email-form.tsx b/apps/platform/src/features/auth/components/providers/change-email-form.tsx index 4f1fac8..5d9087e 100644 --- a/apps/platform/src/features/auth/components/providers/change-email-form.tsx +++ b/apps/platform/src/features/auth/components/providers/change-email-form.tsx @@ -26,7 +26,9 @@ const ChangeEmailForm = () => { } const clearError = (key: string) => { - if (!errors[key]) return + if (!errors[key]) { + return + } setErrors((prev) => { const next = { ...prev } delete next[key] @@ -37,7 +39,7 @@ const ChangeEmailForm = () => { const validate = () => { const next: Record = {} if (!newEmail.trim()) { - next.newEmail = t('ui.text.emailRequired', { ns: 'ui' }) + next.newEmail = t('ui.text.emailRequired') } if (!currentPassword) { next.currentPassword = t('ui.text.current_password_required') @@ -48,7 +50,9 @@ const ChangeEmailForm = () => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() - if (!validate()) return + if (!validate()) { + return + } setSubmitting(true) try { const response = await authService.changeEmail({ @@ -87,7 +91,7 @@ const ChangeEmailForm = () => { variant="ghost" size="sm" onClick={reset} - aria-label={t('ui.text.cancel', { ns: 'ui' })} + aria-label={t('ui.text.cancel')} disabled={submitting} > @@ -158,9 +162,7 @@ const ChangeEmailForm = () => { size="sm" tabIndex={-1} aria-label={ - showPassword - ? t('ui.text.hide', { ns: 'ui' }) - : t('ui.text.show', { ns: 'ui' }) + showPassword ? t('ui.text.hide') : t('ui.text.show') } className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7 p-0" onClick={() => setShowPassword((s) => !s)} diff --git a/apps/platform/src/features/auth/components/providers/change-password-form.tsx b/apps/platform/src/features/auth/components/providers/change-password-form.tsx index 7532609..95e3644 100644 --- a/apps/platform/src/features/auth/components/providers/change-password-form.tsx +++ b/apps/platform/src/features/auth/components/providers/change-password-form.tsx @@ -32,7 +32,9 @@ const ChangePasswordForm = () => { } const clearError = (key: string) => { - if (!errors[key]) return + if (!errors[key]) { + return + } setErrors((prev) => { const next = { ...prev } delete next[key] @@ -57,7 +59,9 @@ const ChangePasswordForm = () => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() - if (!validate()) return + if (!validate()) { + return + } setSubmitting(true) try { const response = await authService.changePassword({ @@ -96,7 +100,7 @@ const ChangePasswordForm = () => { variant="ghost" size="sm" onClick={reset} - aria-label={t('ui.text.cancel', { ns: 'ui' })} + aria-label={t('ui.text.cancel')} disabled={submitting} > @@ -141,7 +145,7 @@ const ChangePasswordForm = () => { /> { clearError('confirmPassword') @@ -208,11 +212,7 @@ const PasswordField = ({ variant="ghost" size="sm" tabIndex={-1} - aria-label={ - show - ? t('ui.text.hide', { ns: 'ui' }) - : t('ui.text.show', { ns: 'ui' }) - } + aria-label={show ? t('ui.text.hide') : t('ui.text.show')} className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7 p-0" onClick={toggleShow} > diff --git a/apps/platform/src/features/auth/components/providers/email-linked-account.tsx b/apps/platform/src/features/auth/components/providers/email-linked-account.tsx index 11b806a..6da9372 100644 --- a/apps/platform/src/features/auth/components/providers/email-linked-account.tsx +++ b/apps/platform/src/features/auth/components/providers/email-linked-account.tsx @@ -28,7 +28,7 @@ const EmailLinkedAccount = ({ onLinked }: Props) => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!email.trim()) { - setError(t('ui.text.emailRequired', { ns: 'ui' })) + setError(t('ui.text.emailRequired')) return } setSubmitting(true) @@ -55,7 +55,7 @@ const EmailLinkedAccount = ({ onLinked }: Props) => {
- {t('ui.text.emailAddress', { ns: 'ui' })} + {t('ui.text.emailAddress')}
{t('ui.text.add_email_description')} @@ -67,7 +67,7 @@ const EmailLinkedAccount = ({ onLinked }: Props) => { variant="ghost" size="sm" onClick={reset} - aria-label={t('ui.text.cancel', { ns: 'ui' })} + aria-label={t('ui.text.cancel')} disabled={submitting} > @@ -94,9 +94,7 @@ const EmailLinkedAccount = ({ onLinked }: Props) => { {expanded && !sent && (
- + { } const clearError = (key: string) => { - if (!errors[key]) return + if (!errors[key]) { + return + } setErrors((prev) => { const next = { ...prev } delete next[key] @@ -54,7 +56,9 @@ const PasswordLinkedAccount = ({ onLinked }: Props) => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() - if (!validate()) return + if (!validate()) { + return + } setSubmitting(true) try { const response = await authService.setPassword({ password }) @@ -78,9 +82,7 @@ const PasswordLinkedAccount = ({ onLinked }: Props) => {
-
- {t('ui.text.password', { ns: 'ui' })} -
+
{t('ui.text.password')}
{t('ui.text.set_password_description')}
@@ -91,7 +93,7 @@ const PasswordLinkedAccount = ({ onLinked }: Props) => { variant="ghost" size="sm" onClick={reset} - aria-label={t('ui.text.cancel', { ns: 'ui' })} + aria-label={t('ui.text.cancel')} disabled={submitting} > @@ -106,9 +108,7 @@ const PasswordLinkedAccount = ({ onLinked }: Props) => { {expanded && (
- +
{ size="sm" tabIndex={-1} aria-label={ - showPassword - ? t('ui.text.hide', { ns: 'ui' }) - : t('ui.text.show', { ns: 'ui' }) + showPassword ? t('ui.text.hide') : t('ui.text.show') } className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7 p-0" onClick={() => setShowPassword((s) => !s)} @@ -151,7 +149,7 @@ const PasswordLinkedAccount = ({ onLinked }: Props) => {
{ size="sm" tabIndex={-1} aria-label={ - showConfirmPassword - ? t('ui.text.hide', { ns: 'ui' }) - : t('ui.text.show', { ns: 'ui' }) + showConfirmPassword ? t('ui.text.hide') : t('ui.text.show') } className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7 p-0" onClick={() => setShowConfirmPassword((s) => !s)} diff --git a/apps/platform/src/features/auth/components/providers/password-register-form.tsx b/apps/platform/src/features/auth/components/providers/password-register-form.tsx index aa88d76..b4155c0 100644 --- a/apps/platform/src/features/auth/components/providers/password-register-form.tsx +++ b/apps/platform/src/features/auth/components/providers/password-register-form.tsx @@ -25,7 +25,9 @@ const PasswordRegisterForm = ({ onSubmitted }: Props) => { const validate = () => { const next: Record = {} - if (!email.trim()) next.email = t('ui.text.emailRequired', { ns: 'ui' }) + if (!email.trim()) { + next.email = t('ui.text.emailRequired') + } if (password.length < MIN_PASSWORD_LENGTH) { next.password = t('ui.text.password_too_short') } @@ -38,7 +40,9 @@ const PasswordRegisterForm = ({ onSubmitted }: Props) => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() - if (!validate()) return + if (!validate()) { + return + } setSubmitting(true) try { const response = await authService.register({ email, password }) @@ -63,7 +67,9 @@ const PasswordRegisterForm = ({ onSubmitted }: Props) => { } const clearError = (key: string) => { - if (!errors[key]) return + if (!errors[key]) { + return + } setErrors((prev) => { const next = { ...prev } delete next[key] @@ -74,9 +80,7 @@ const PasswordRegisterForm = ({ onSubmitted }: Props) => { return (
- + { )}
- +
{ variant="ghost" size="sm" tabIndex={-1} - aria-label={ - showPassword - ? t('ui.text.hide', { ns: 'ui' }) - : t('ui.text.show', { ns: 'ui' }) - } + aria-label={showPassword ? t('ui.text.hide') : t('ui.text.show')} className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7 p-0" onClick={() => setShowPassword((s) => !s)} > @@ -138,9 +136,7 @@ const PasswordRegisterForm = ({ onSubmitted }: Props) => { )}
- +
{ size="sm" tabIndex={-1} aria-label={ - showConfirmPassword - ? t('ui.text.hide', { ns: 'ui' }) - : t('ui.text.show', { ns: 'ui' }) + showConfirmPassword ? t('ui.text.hide') : t('ui.text.show') } className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7 p-0" onClick={() => setShowConfirmPassword((s) => !s)} diff --git a/apps/platform/src/features/auth/hooks/use-oauth-login.ts b/apps/platform/src/features/auth/hooks/use-oauth-login.ts index a7eaf10..537e151 100644 --- a/apps/platform/src/features/auth/hooks/use-oauth-login.ts +++ b/apps/platform/src/features/auth/hooks/use-oauth-login.ts @@ -23,6 +23,6 @@ export function useOAuthLogin(provider: string, mode: string) { url.searchParams.set('state', encodedState) window.location.href = url.toString() } - } catch (error) {} + } catch {} }, [provider, mode]) } diff --git a/apps/platform/src/features/credentials/components/credential-form-dialog.tsx b/apps/platform/src/features/credentials/components/credential-form-dialog.tsx index 930165c..606e196 100644 --- a/apps/platform/src/features/credentials/components/credential-form-dialog.tsx +++ b/apps/platform/src/features/credentials/components/credential-form-dialog.tsx @@ -42,7 +42,9 @@ const CredentialFormDialog = ({ const clearError = (key: string) => { setErrors((prev) => { - if (!prev[key]) return prev + if (!prev[key]) { + return prev + } const next = { ...prev } delete next[key] return next @@ -50,7 +52,9 @@ const CredentialFormDialog = ({ } useEffect(() => { - if (!open) setErrors({}) + if (!open) { + setErrors({}) + } }, [open]) useEffect(() => { @@ -67,20 +71,28 @@ const CredentialFormDialog = ({ ) { return selectedSecret.secretDetails.data[schema.key] } - if (schema?.default) return schema.default + if (schema?.default) { + return schema.default + } return '' } const validate = () => { const errs: Record = {} const titleValue = (selectedSecret?.label || '').toString().trim() - if (!titleValue) errs['s-t'] = true + if (!titleValue) { + errs['s-t'] = true + } if (!usePlatformCredential && selectedSecret?.provider) { for (const schema of selectedSecret.provider) { - if (schema.hidden || schema.readOnly || !schema.required) continue + if (schema.hidden || schema.readOnly || !schema.required) { + continue + } const value = (getFieldValue(schema) || '').toString().trim() - if (!value) errs[schema.key] = true + if (!value) { + errs[schema.key] = true + } } } @@ -89,13 +101,17 @@ const CredentialFormDialog = ({ } const handleSave = () => { - if (!validate()) return + if (!validate()) { + return + } saveCredentials() onOpenChange(false) } const handleAuthorize = () => { - if (!validate()) return + if (!validate()) { + return + } authorizeOAuth2() } @@ -205,7 +221,9 @@ const CredentialFormDialog = ({ if (!usePlatformCredential && selectedSecret?.provider) { for (let i = 0; i < selectedSecret.provider.length; i++) { const schema = selectedSecret.provider[i] - if (schema.hidden) continue + if (schema.hidden) { + continue + } let currentValue = '' if (selectedSecret.data && selectedSecret.data[schema.key]) { diff --git a/apps/platform/src/features/credentials/components/credential-popover.tsx b/apps/platform/src/features/credentials/components/credential-popover.tsx index ef9200f..95bd14d 100644 --- a/apps/platform/src/features/credentials/components/credential-popover.tsx +++ b/apps/platform/src/features/credentials/components/credential-popover.tsx @@ -21,13 +21,19 @@ const CredentialPopover = ({ const handleOpenChange = (next: boolean) => { setOpen(next) - if (!next) setQuery('') + if (!next) { + setQuery('') + } } const filteredSecrets = useMemo(() => { - if (!secrets) return [] + if (!secrets) { + return [] + } const q = query.trim().toLowerCase() - if (!q) return secrets + if (!q) { + return secrets + } return secrets.filter((secret: any) => t(secret.name).toLowerCase().includes(q), ) @@ -49,7 +55,7 @@ const CredentialPopover = ({ onSelect(secretCopy) }} > - + {t(secret.name)} , ) diff --git a/apps/platform/src/features/credentials/components/credential-tab.tsx b/apps/platform/src/features/credentials/components/credential-tab.tsx index 335ef94..4ec5ea0 100644 --- a/apps/platform/src/features/credentials/components/credential-tab.tsx +++ b/apps/platform/src/features/credentials/components/credential-tab.tsx @@ -91,12 +91,18 @@ const CredentialTab = ({ if (secretDetails) { setSelectedSecret((prev: any) => { - if (!prev) return prev + if (!prev) { + return prev + } const next = { ...prev } next.secretDetails = secretDetails next.sourceType = secretDetails.sourceType - if (secretDetails.data) next.data = { ...secretDetails.data } - if (secretDetails.title) next.label = secretDetails.title + if (secretDetails.data) { + next.data = { ...secretDetails.data } + } + if (secretDetails.title) { + next.label = secretDetails.title + } return next }) if (secretDetails.sourceType === 'platform') { @@ -111,8 +117,11 @@ const CredentialTab = ({ ns.label = t(ns.name) const c = JSON.parse(JSON.stringify(ns)) setSelectedSecret(c) - if (w) w(true) - else setOpen(true) + if (w) { + w(true) + } else { + setOpen(true) + } } const saveCredentials = async () => { diff --git a/apps/platform/src/features/credentials/hooks/use-credentials.ts b/apps/platform/src/features/credentials/hooks/use-credentials.ts index 0e61fff..9600518 100644 --- a/apps/platform/src/features/credentials/hooks/use-credentials.ts +++ b/apps/platform/src/features/credentials/hooks/use-credentials.ts @@ -3,13 +3,13 @@ import useSWR, { useSWRConfig } from 'swr' import credentialsService from '@/features/credentials/services/credentials' import { organizationsService } from '@/features/organizations' import { nodeEngineService } from '@/features/flow-editor' -import { secretIcons } from '@/features/flow-editor/icons' -import { resolveIconKey } from '@/features/flow-editor/hooks/use-flow-nodes' -import { useThemeStore } from '@/stores/theme-store' +import { useIconResolver } from '@/features/flow-editor/icons' import { unwrap } from '@/lib/swr' const schemaToFields = (schema: any) => { - if (!schema || !schema.properties) return [] + if (!schema || !schema.properties) { + return [] + } const required = new Set(schema.required ?? []) return Object.entries(schema.properties).map( ([key, value]: [string, any]) => ({ @@ -45,7 +45,7 @@ export function useCredentials( isUserMode: boolean, ) { const hasAccess = isUserMode || !!organizationId - const mode = useThemeStore((s) => s.getMode()) + const resolveIcon = useIconResolver() const [pagination, setPagination] = useState({ offset: 0, @@ -101,19 +101,17 @@ export function useCredentials( }) return sa.map((secret: any) => { const credential = credentialMap[secret.key] - const iconKey = credential ? resolveIconKey(credential.icon, mode) : '' return { ...secret, - icon: iconKey ? secretIcons[iconKey] : null, + icon: (credential && resolveIcon(credential.icon)) ?? null, isSupportPlatform: credential?.isSupportPlatform || false, sourceType: secret.sourceType || 'owner', } }) - }, [ca, sa, mode]) + }, [ca, sa, resolveIcon]) const secrets = useMemo(() => { return ca.map((c) => { - const iconKey = resolveIconKey(c.icon, mode) return { id: c.id, name: c.name, @@ -121,10 +119,10 @@ export function useCredentials( isOAuth2: c.isOAuth2, isSupportPlatform: c.isSupportPlatform, provider: schemaToFields(c.schema), - icon: iconKey ? secretIcons[iconKey] : undefined, + icon: resolveIcon(c.icon), } }) - }, [ca, mode]) + }, [ca, resolveIcon]) const fetchCredentials = useCallback((offset = 0, limit = 10, query = '') => { setPagination({ offset, limit, query }) @@ -136,7 +134,9 @@ export function useCredentials( const getSecretDetails = useCallback( async (secretId: string) => { - if (!hasAccess || !secretId) return null + if (!hasAccess || !secretId) { + return null + } try { const response = isUserMode ? await credentialsService.getUserCredentialById(secretId) diff --git a/apps/platform/src/features/credentials/services/credentials.ts b/apps/platform/src/features/credentials/services/credentials.ts index 589987b..9c3ffaf 100644 --- a/apps/platform/src/features/credentials/services/credentials.ts +++ b/apps/platform/src/features/credentials/services/credentials.ts @@ -8,7 +8,9 @@ const getUserCredentials = async ({ const params = new URLSearchParams() params.set('offset', String(offset)) params.set('limit', String(limit)) - if (query) params.set('query', query) + if (query) { + params.set('query', query) + } return await platformApi.get(`/users/me/credentials?${params.toString()}`) } diff --git a/apps/platform/src/features/flow-editor/components/flow-canvas.tsx b/apps/platform/src/features/flow-editor/components/flow-canvas.tsx index 8906ec6..774bc60 100644 --- a/apps/platform/src/features/flow-editor/components/flow-canvas.tsx +++ b/apps/platform/src/features/flow-editor/components/flow-canvas.tsx @@ -1,5 +1,4 @@ import coreNode from '@/features/flow-editor/nodes/core-node' -import starterNode from '@/features/flow-editor/nodes/starter-node' import coreEdge from '@/features/flow-editor/nodes/core-edge' import coreGroup from '@/features/flow-editor/nodes/core-group' import { useBreadcrumbStore } from '@/features/flow-editor/stores/breadcrumb-store' @@ -53,11 +52,12 @@ const defaultNodes = [ title: 'ui.text.starterNode', description: 'ui.text.starterNodeDescription', hide_input: true, - hide_left: true, tags: ['starter'], category: 'system', + inputs: [], + outputs: [{ key: 'out' }], }, - type: 'starter', + type: 'core', nodeId: 'system_starter', deletable: false, }, @@ -65,7 +65,7 @@ const defaultNodes = [ const nodeTypes = { core: coreNode, - starter: starterNode, + starter: coreNode, group: coreGroup, annotation: Annotation, } @@ -119,7 +119,7 @@ const FlowCanvas = ({ const { t } = useTranslation() // Hooks - const { apiNodes, nodeList, isLoading } = useNodeEngineNodes() + const { apiNodes, providerList, isLoading } = useNodeEngineNodes() const { triggerVariables } = useTriggerVariables() const { createContextNode } = useFlowNodes(apiNodes) @@ -179,11 +179,20 @@ const FlowCanvas = ({ label: node.name, description: node.description, type: node.category, + icon: node.icon, subCategory: node.subCategory, tags: node.tags, isComingSoon: node.isComingSoon || false, })) - setSelectedCategory(filtered) + setSelectedCategory( + query + ? { + label: t('ui.text.searchResults'), + nodes: filtered, + isSearch: true, + } + : null, + ) }, [apiNodes, t], ) @@ -197,6 +206,9 @@ const FlowCanvas = ({ description: apiNode?.description || '', tags: apiNode?.tags || [], category: apiNode?.category || '', + icon: apiNode?.icon, + inputs: apiNode?.inputs, + outputs: apiNode?.outputs, } }, [apiNodes], @@ -289,12 +301,21 @@ const FlowCanvas = ({ useEffect(() => { if (initialFlow) { setFunctions() + return + } + if (apiNodes.length === 0) { + return } + setNodes((current) => + current.map((n) => ({ ...n, data: { ...n.data, ...buildNodeData(n) } })), + ) }, [initialFlow, apiNodes]) const applyGeneratedFlow = useCallback( (flow) => { - if (!flow || apiNodes.length === 0) return + if (!flow || apiNodes.length === 0) { + return + } const eds = flow.edges.map((e) => ({ ...e })) const nds = flow.nodes.map((n) => { const data = buildNodeData(n) @@ -316,7 +337,9 @@ const FlowCanvas = ({ ) useEffect(() => { - if (generatedFlow) applyGeneratedFlow(generatedFlow) + if (generatedFlow) { + applyGeneratedFlow(generatedFlow) + } }, [generatedFlow, applyGeneratedFlow]) const handleApplyWorkflow = useCallback( @@ -329,6 +352,9 @@ const FlowCanvas = ({ // Node settings panel const onNodeClick = useCallback((_event, node) => { + if (node.type === 'annotation') { + return + } setSelectedNodeId(node.id) setChatOpen(false) }, []) @@ -343,13 +369,17 @@ const FlowCanvas = ({ ) const selectedNodeSchema = useMemo(() => { - if (!selectedNode) return [] + if (!selectedNode) { + return [] + } const apiNode = apiNodes.find((a) => a.id === selectedNode.nodeId) return apiNode?.schema || [] }, [selectedNode, apiNodes]) const selectedNodeHasNaturalLanguage = useMemo(() => { - if (!selectedNode) return undefined + if (!selectedNode) { + return undefined + } const apiNode = apiNodes.find((a) => a.id === selectedNode.nodeId) return apiNode?.hasNaturalLanguage }, [selectedNode, apiNodes]) @@ -385,7 +415,9 @@ const FlowCanvas = ({ const handleSetChatOpen = useCallback((v) => { setChatOpen(v) - if (v) setSelectedNodeId(null) + if (v) { + setSelectedNodeId(null) + } }, []) const nextStepInit = (fn) => { @@ -435,7 +467,7 @@ const FlowCanvas = ({ setSidebarOpen={setSidebarOpen} selectedCategory={selectedCategory} setSelectedCategory={setSelectedCategory} - nodeList={nodeList} + providerList={providerList} apiNodes={apiNodes} dragging={dragging} startDrag={startDrag} @@ -453,6 +485,9 @@ const FlowCanvas = ({ openApiSheet={ initialFlow?.id ? () => setApiSheetOpen(true) : undefined } + nodes={nodes} + apiNodes={apiNodes} + organizationId={organizationId} /> { - if (!dragging || !previewData) return null + if (!dragging || !previewData) { + return null + } const pref = getCategoryPrefs(previewData.category) const Icon = pref.icon return (
-
+
diff --git a/apps/platform/src/features/flow-editor/components/flow-run.tsx b/apps/platform/src/features/flow-editor/components/flow-run.tsx index 3b4b866..acfca0c 100644 --- a/apps/platform/src/features/flow-editor/components/flow-run.tsx +++ b/apps/platform/src/features/flow-editor/components/flow-run.tsx @@ -18,7 +18,9 @@ const FlowRun = ({ flow, setFlow }) => { const steps = [] for (let i = 0; i < flow.nodes.length; i++) { const node = flow.nodes[i] - if (node.type === 'starter') continue + if (node.type === 'starter') { + continue + } const runnerKey = node.nodeId?.replaceAll('.', '_') if (runnerKey && Runner[runnerKey]) { node.runner = Runner[runnerKey] diff --git a/apps/platform/src/features/flow-editor/components/flow-sidebar.tsx b/apps/platform/src/features/flow-editor/components/flow-sidebar.tsx index 60d6d53..150a4f3 100644 --- a/apps/platform/src/features/flow-editor/components/flow-sidebar.tsx +++ b/apps/platform/src/features/flow-editor/components/flow-sidebar.tsx @@ -1,14 +1,17 @@ import { + ChevronLeft, PanelLeft, PanelLeftClose, Search, - ChevronLeft, + SearchX, Sparkles, + StickyNote, } from 'lucide-react' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { GhostInput } from '@/components/shared/ghost-input' import { getCategoryPrefs } from '@/lib/flow-categories' +import { useIconResolver } from '@/features/flow-editor/icons' import { usePlatformFeatures } from '@/features/platform' import { useTranslation } from 'react-i18next' @@ -18,7 +21,7 @@ const FlowSidebar = ({ setSidebarOpen, selectedCategory, setSelectedCategory, - nodeList, + providerList, dragging, startDrag, annotationDrag, @@ -27,11 +30,12 @@ const FlowSidebar = ({ }) => { const { t } = useTranslation() const { workflowsGenerationEnabled } = usePlatformFeatures() + const resolveIcon = useIconResolver() const renderNodeCard = (item, key) => { const name = item.label || item.name const prefs = getCategoryPrefs(item.type || item.category) - const Icon = prefs.icon + const Icon = resolveIcon(item.icon) ?? prefs.icon const isDisabled = item.isComingSoon const cursorClass = isDisabled ? 'cursor-not-allowed' @@ -47,59 +51,51 @@ const FlowSidebar = ({
!isDisabled && startDrag(e, item.id)} role="button" tabIndex={isDisabled ? -1 : 0} aria-label={ariaLabel} aria-disabled={isDisabled} > -
- -
+
) } const renderAnnotationCard = () => { - const annotationPrefs = getCategoryPrefs('system') - const AnnotationIcon = annotationPrefs?.icon - return (
-
- -
{t('ui.text.annotationNode')}
-
-
- {t('ui.text.addAnnotationToFlow')} +
) @@ -107,82 +103,76 @@ const FlowSidebar = ({ const renderNodeList = () => { if (selectedCategory) { - const isFlat = Array.isArray(selectedCategory) - const flatItems = isFlat - ? selectedCategory - : Object.values(selectedCategory).flat() - const hasSystem = flatItems.some((cat: any) => cat.type === 'system') + const items = selectedCategory.nodes ?? [] + const hasSystem = items.some((node: any) => node.type === 'system') - let body: React.ReactNode - - if (isFlat) { - body = ( - <> - {selectedCategory.map((item, j) => renderNodeCard(item, j))} - {hasSystem && renderAnnotationCard()} - - ) - } else { - const subEntries = Object.entries( - selectedCategory as Record, - ) - body = ( - <> - {subEntries.map(([sub, items]) => ( -
- {sub && ( -
- {t(sub)} -
- )} - {items.map((item, j) => renderNodeCard(item, `${sub}-${j}`))} -
- ))} - {hasSystem && renderAnnotationCard()} - + if (items.length === 0) { + return ( +
  • +
  • ) } return ( -
  • - {body} +
  • + {items.map((item: any, j: number) => renderNodeCard(item, j))} + {hasSystem && renderAnnotationCard()}
  • ) } - const categories = Object.keys(nodeList).map((category, i) => { - const prefs = getCategoryPrefs(category) - const Icon = prefs.icon - const categoryLabel = prefs.labelKey ? t(prefs.labelKey) : category + const providers = providerList.map((provider: any) => { + const prefs = getCategoryPrefs(provider.nodes[0]?.type ?? '') + const Icon = resolveIcon(provider.icon) ?? prefs.icon return (
    setSelectedCategory(nodeList[category])} - className={`flex flex-col items-center justify-center rounded-lg transition-colors w-full min-h-33 cursor-pointer bg-current/10 dark:hover:bg-current/50 hover:bg-current/20 gap-3`} - style={{ color: prefs.color }} - data-tour={category === 'system' ? 'system-category' : undefined} + key={provider.key} + onClick={() => + setSelectedCategory({ + label: provider.label, + nodes: provider.nodes, + }) + } + style={{ borderColor: prefs.color }} + className="bg-card hover:bg-accent flex w-full cursor-pointer items-center gap-3 rounded-md border px-3 py-2.5 transition-colors" + data-tour={provider.key === 'system' ? 'system-category' : undefined} role="button" tabIndex={0} - aria-label={categoryLabel} + aria-label={provider.label} > -
    ) }) return ( -
  • - {categories} +
  • + {providers}
  • ) } - if (previewMode) return null + if (previewMode) { + return null + } return (
    @@ -219,7 +209,7 @@ const FlowSidebar = ({
    -
      +
    -
    - {(() => { - const flat = Array.isArray(selectedCategory) - ? selectedCategory - : Object.values( - selectedCategory as Record, - ).flat() - return flat[0]?.type ?? 'Results' - })()} -
    +
    {selectedCategory.label}
    ) : ( <> diff --git a/apps/platform/src/features/flow-editor/components/flow-toolbar.tsx b/apps/platform/src/features/flow-editor/components/flow-toolbar.tsx index 26a1b9f..244756a 100644 --- a/apps/platform/src/features/flow-editor/components/flow-toolbar.tsx +++ b/apps/platform/src/features/flow-editor/components/flow-toolbar.tsx @@ -17,7 +17,9 @@ const FlowToolbar = ({ }) => { const { t } = useTranslation() - if (previewMode) return null + if (previewMode) { + return null + } return (
    diff --git a/apps/platform/src/features/flow-editor/components/node-settings-panel.tsx b/apps/platform/src/features/flow-editor/components/node-settings-panel.tsx index b1f45bb..721feff 100644 --- a/apps/platform/src/features/flow-editor/components/node-settings-panel.tsx +++ b/apps/platform/src/features/flow-editor/components/node-settings-panel.tsx @@ -7,12 +7,14 @@ import { Label } from '@/components/ui/label' import { Switch } from '@/components/ui/switch' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { usePlatformFeatures } from '@/features/platform' +import { useIconResolver } from '@/features/flow-editor/icons' import { AdvancedDebouncedTextarea } from '@/components/shared/advanced-debounced-textarea' import { SchemaFieldRenderer } from '@/features/flow-editor/components/schema-field-renderer' import { DataSourcePopover } from '@/features/flow-editor/components/data-source-popover' import { flowCategoryPreferences } from '@/lib/flow-categories' import type { FlowNode, + IconSource, NodeSettings, SchemaField, } from '@/features/flow-editor/types' @@ -53,7 +55,9 @@ export function NodeSettingsPanel({ const initial: Record = {} const existing = node.parameters || {} for (const field of schema || []) { - if (field.hidden) continue + if (field.hidden) { + continue + } initial[field.key] = existing[field.key] ?? field.default ?? '' } return initial @@ -69,7 +73,9 @@ export function NodeSettingsPanel({ const initial: Record = {} const existing = node.parameters || {} for (const field of schema || []) { - if (field.hidden) continue + if (field.hidden) { + continue + } initial[field.key] = existing[field.key] ?? field.default ?? '' } setParameters(initial) @@ -100,7 +106,8 @@ export function NodeSettingsPanel({ return flowCategoryPreferences[category] }, [node.data.category]) - const Icon = prefs.icon + const resolveIcon = useIconResolver() + const Icon = resolveIcon(node.data?.icon as IconSource) ?? prefs.icon const visibleSchema = useMemo( () => (schema || []).filter((f) => !f.hidden), @@ -123,11 +130,8 @@ export function NodeSettingsPanel({ > {/* Header */}
    -
    - {Icon && } +
    + {Icon && }
    diff --git a/apps/platform/src/features/flow-editor/components/schema-field-renderer.tsx b/apps/platform/src/features/flow-editor/components/schema-field-renderer.tsx index a5eac32..1dde804 100644 --- a/apps/platform/src/features/flow-editor/components/schema-field-renderer.tsx +++ b/apps/platform/src/features/flow-editor/components/schema-field-renderer.tsx @@ -49,15 +49,25 @@ const isMultilineFormat = (format?: string) => format === 'multiline' || format === 'textarea' || format === 'multi-line' const inputTypeFor = (field: SchemaField) => { - if (field.writeOnly) return 'password' - if (field.format === 'email') return 'email' - if (field.format === 'uri' || field.format === 'url') return 'url' + if (field.writeOnly) { + return 'password' + } + if (field.format === 'email') { + return 'email' + } + if (field.format === 'uri' || field.format === 'url') { + return 'url' + } return 'text' } const stringifyComplex = (val: any) => { - if (val === undefined || val === null) return '' - if (typeof val === 'string') return val + if (val === undefined || val === null) { + return '' + } + if (typeof val === 'string') { + return val + } try { return JSON.stringify(val, null, 2) } catch { @@ -68,15 +78,23 @@ const stringifyComplex = (val: any) => { const PRIMITIVE_ITEM_TYPES = new Set(['string', 'number', 'integer', 'boolean']) const isPrimitiveItemSchema = (items: any) => { - if (!items || typeof items !== 'object') return true + if (!items || typeof items !== 'object') { + return true + } const type = items.type - if (type === undefined) return true + if (type === undefined) { + return true + } return PRIMITIVE_ITEM_TYPES.has(type) } const defaultForItemType = (type?: string) => { - if (type === 'boolean') return false - if (type === 'number' || type === 'integer') return 0 + if (type === 'boolean') { + return false + } + if (type === 'number' || type === 'integer') { + return 0 + } return '' } @@ -222,7 +240,9 @@ export function SchemaFieldRenderer({ }: SchemaFieldRendererProps) { const { t } = useTranslation() - if (field.hidden) return null + if (field.hidden) { + return null + } const labelText = t(field.title || field.key, field.title || field.key) const isReadOnly = !!field.readOnly diff --git a/apps/platform/src/features/flow-editor/hooks/use-flow-drag.ts b/apps/platform/src/features/flow-editor/hooks/use-flow-drag.ts index 481868e..34117f3 100644 --- a/apps/platform/src/features/flow-editor/hooks/use-flow-drag.ts +++ b/apps/platform/src/features/flow-editor/hooks/use-flow-drag.ts @@ -2,6 +2,8 @@ import { useState, useRef } from 'react' import { useReactFlow } from '@xyflow/react' import type { FlowNode, + IconSource, + NodeHandle, NodeOutputType, SchemaField, SetFlowNodes, @@ -17,6 +19,10 @@ interface DragItem { name: string description: string category: string + icon?: IconSource + inputs?: NodeHandle[] + outputs?: NodeHandle[] + subCategory?: string tags?: string[] isComingSoon?: boolean outputTypes?: NodeOutputType[] @@ -55,11 +61,15 @@ export function useFlowDrag({ const pane = document.querySelector( '.react-flow__pane.draggable', ) as HTMLElement - if (pane) pane.style.cursor = 'grab' + if (pane) { + pane.style.cursor = 'grab' + } document.removeEventListener('mousemove', onMouseMove) document.removeEventListener('mouseup', onMouseUp) - if (!dragData.current) return + if (!dragData.current) { + return + } const position = screenToFlowPosition({ x: e.clientX + 100, y: e.clientY, @@ -72,6 +82,9 @@ export function useFlowDrag({ tags: dragData.current.tags, title: dragData.current.name, category: dragData.current.category, + icon: dragData.current.icon, + inputs: dragData.current.inputs, + outputs: dragData.current.outputs, }, instruction: undefined, parameters: {}, @@ -95,12 +108,16 @@ export function useFlowDrag({ const pane = document.querySelector( '.react-flow__pane.draggable', ) as HTMLElement - if (pane) pane.style.cursor = 'grab' + if (pane) { + pane.style.cursor = 'grab' + } document.removeEventListener('mousemove', onMouseMove) document.removeEventListener('mouseup', onMouseUpAnnotation) - if (!dragData.current) return + if (!dragData.current) { + return + } const position = screenToFlowPosition({ x: e.clientX + 100, @@ -139,7 +156,9 @@ export function useFlowDrag({ const pane = document.querySelector( '.react-flow__pane.draggable', ) as HTMLElement - if (pane) pane.style.cursor = 'grabbing' + if (pane) { + pane.style.cursor = 'grabbing' + } document.addEventListener('mousemove', onMouseMove) document.addEventListener('mouseup', onMouseUp) } @@ -161,7 +180,9 @@ export function useFlowDrag({ const pane = document.querySelector( '.react-flow__pane.draggable', ) as HTMLElement - if (pane) pane.style.cursor = 'grabbing' + if (pane) { + pane.style.cursor = 'grabbing' + } document.addEventListener('mousemove', onMouseMove) document.addEventListener('mouseup', onMouseUpAnnotation) diff --git a/apps/platform/src/features/flow-editor/hooks/use-flow-nodes.ts b/apps/platform/src/features/flow-editor/hooks/use-flow-nodes.ts index 69654f9..9584fa1 100644 --- a/apps/platform/src/features/flow-editor/hooks/use-flow-nodes.ts +++ b/apps/platform/src/features/flow-editor/hooks/use-flow-nodes.ts @@ -2,11 +2,11 @@ import { useCallback, useEffect, useMemo, useRef } from 'react' import useSWR from 'swr' import nodeEngineService from '@/features/flow-editor/services/node-engine' import { useTranslation } from 'react-i18next' -import { useThemeStore } from '@/stores/theme-store' import type { ContextMenuItem, FlowEdge, FlowNode, + IconSource, NodeEngineNode, NodeOutputType, RendererNode, @@ -15,18 +15,13 @@ import type { SchemaField, } from '@/features/flow-editor/types' -export const resolveIconKey = (icon: any, mode: 'light' | 'dark'): string => { - if (!icon) return '' - if (typeof icon === 'string') return icon - if (mode === 'dark' && icon.dark) return icon.dark - return icon.light ?? icon.dark ?? '' -} - const normalizeKey = (value?: string) => (value ?? '').toLowerCase().replace(/\s+/g, '') const inputSchemaToFields = (schema: any): SchemaField[] => { - if (!schema?.properties) return [] + if (!schema?.properties) { + return [] + } const required = new Set(schema.required ?? []) return Object.entries(schema.properties).map( ([key, value]: [string, any]) => ({ @@ -53,7 +48,9 @@ const collectOutputPaths = ( prefix: string, acc: NodeOutputType[], ) => { - if (!node || typeof node !== 'object') return + if (!node || typeof node !== 'object') { + return + } if (node.type === 'object' && node.properties) { for (const [key, value] of Object.entries(node.properties)) { @@ -85,7 +82,9 @@ const collectOutputPaths = ( } const outputSchemaToTypes = (schema: any): NodeOutputType[] => { - if (!schema || typeof schema !== 'object') return [] + if (!schema || typeof schema !== 'object') { + return [] + } const acc: NodeOutputType[] = [] collectOutputPaths(schema, '', acc) return acc @@ -95,13 +94,19 @@ const buildNodeList = (nodes: ResolvedNode[]): RendererNodeMap => { const r: RendererNodeMap = {} for (const item of nodes) { const subCategory = item.subCategory ?? '' - if (!r[item.category]) r[item.category] = {} - if (!r[item.category][subCategory]) r[item.category][subCategory] = [] + if (!r[item.category]) { + r[item.category] = {} + } + if (!r[item.category][subCategory]) { + r[item.category][subCategory] = [] + } const labels: string[] = [] if (item.schema && item.schema.length > 0) { for (const field of item.schema) { if (Array.isArray(field.enum)) { - for (const opt of field.enum) labels.push(String(opt)) + for (const opt of field.enum) { + labels.push(String(opt)) + } } } } @@ -110,6 +115,9 @@ const buildNodeList = (nodes: ResolvedNode[]): RendererNodeMap => { label: item.name, description: item.description, type: item.category, + icon: item.icon, + inputs: item.inputs, + outputs: item.outputs, subCategory: item.subCategory, actions: labels, tags: item.tags, @@ -120,11 +128,45 @@ const buildNodeList = (nodes: ResolvedNode[]): RendererNodeMap => { return r } +const buildProviderList = (nodes: ResolvedNode[]) => { + const groups = new Map< + string, + { key: string; label: string; icon: IconSource; nodes: RendererNode[] } + >() + + for (const item of nodes) { + const label = item.provider || item.subCategory || '' + const key = item.subCategory || normalizeKey(label) + if (!groups.has(key)) { + groups.set(key, { + key, + label, + icon: { brand: item.icon?.brand }, + nodes: [], + }) + } + groups.get(key)!.nodes.push({ + id: item.id, + label: item.name, + description: item.description, + type: item.category, + icon: item.icon, + inputs: item.inputs, + outputs: item.outputs, + subCategory: item.subCategory, + actions: [], + tags: item.tags, + isComingSoon: item.isComingSoon ?? false, + }) + } + + return [...groups.values()].sort((a, b) => a.label.localeCompare(b.label)) +} + const NODES_KEY = 'node-engine-nodes' const TRIGGER_VARIABLES_KEY = 'node-engine-trigger-variables' export function useNodeEngineNodes() { - const mode = useThemeStore((s) => s.getMode()) const { data, isLoading } = useSWR(NODES_KEY, async () => { const response = await nodeEngineService.getNodes() return (response.data as NodeEngineNode[]) || [] @@ -136,9 +178,12 @@ export function useNodeEngineNodes() { id: item.id ?? '', name: item.name ?? '', description: item.description ?? '', - icon: resolveIconKey(item.icon, mode), + icon: item.icon, + inputs: item.inputs, + outputs: item.outputs, category: normalizeKey(item.categories?.[0]), subCategory: normalizeKey(item.subCategories?.[0]), + provider: item.subCategories?.[0] ?? '', tags: item.tags ?? [], supportedCredentials: item.supportedCredentials, schema: inputSchemaToFields(item.inputSchema), @@ -147,11 +192,12 @@ export function useNodeEngineNodes() { isComingSoon: item.isComingSoon, hasNaturalLanguage: item.hasNaturalLanguage, })), - [data, mode], + [data], ) const nodeList = useMemo(() => buildNodeList(apiNodes), [apiNodes]) + const providerList = useMemo(() => buildProviderList(apiNodes), [apiNodes]) - return { apiNodes, nodeList, isLoading } + return { apiNodes, nodeList, providerList, isLoading } } export function useTriggerVariables() { @@ -159,7 +205,9 @@ export function useTriggerVariables() { TRIGGER_VARIABLES_KEY, async () => { const response = await nodeEngineService.getTriggerVariables() - if (response.isSuccess && response.data) return response.data + if (response.isSuccess && response.data) { + return response.data + } return [] }, ) @@ -195,7 +243,9 @@ export function useFlowNodes(apiNodes: ResolvedNode[] = []) { from?: SourceRef, apiNodesArg?: ResolvedNode[], ): ContextMenuItem[] | undefined => { - if (node.id === '0') return undefined + if (node.id === '0') { + return undefined + } let contextMenu: ContextMenuItem[] = [] const ref = node.id @@ -204,7 +254,9 @@ export function useFlowNodes(apiNodes: ResolvedNode[] = []) { const apiNode = apiOriginRef.current.find( (n) => n.id === sourceNode.nodeId, ) - if (apiNode === undefined) return contextMenu + if (apiNode === undefined) { + return contextMenu + } const outputs = apiNode.outputTypes ?? [] for (let j = 0; j < outputs.length; j++) { @@ -237,15 +289,21 @@ export function useFlowNodes(apiNodes: ResolvedNode[] = []) { const edges = source.edges.filter((e) => e.target === ref) for (let i = 0; i < edges.length; i++) { const edge = edges[i] - if (edge.source === '0') continue + if (edge.source === '0') { + continue + } const sourceNode = source.nodes.find((n) => n.id === edge.source) - if (!sourceNode) continue + if (!sourceNode) { + continue + } const currentApiNodes = apiNodesArg || apiOriginRef.current const apiNode = currentApiNodes?.find( (n) => n.id === sourceNode.nodeId, ) - if (apiNode === undefined) continue + if (apiNode === undefined) { + continue + } const sourceContextMenu = sourceNode.data?.contextMenu if (sourceContextMenu && sourceContextMenu.length > 0) { contextMenu = contextMenu.concat(sourceContextMenu) diff --git a/apps/platform/src/features/flow-editor/hooks/use-navigation-guard.ts b/apps/platform/src/features/flow-editor/hooks/use-navigation-guard.ts index ffb1fef..0f28d70 100644 --- a/apps/platform/src/features/flow-editor/hooks/use-navigation-guard.ts +++ b/apps/platform/src/features/flow-editor/hooks/use-navigation-guard.ts @@ -35,8 +35,12 @@ export function useNavigationGuard({ // Link click and popstate interception useEffect(() => { - if (previewMode) return - if (!hasUnsavedChanges) return + if (previewMode) { + return + } + if (!hasUnsavedChanges) { + return + } const handleClick = (e: MouseEvent) => { const link = (e.target as HTMLElement).closest('a[href]') @@ -74,7 +78,9 @@ export function useNavigationGuard({ // beforeunload useEffect(() => { - if (previewMode) return + if (previewMode) { + return + } const handleBeforeUnload = (e: BeforeUnloadEvent) => { if (hasUnsavedChanges) { e.preventDefault() diff --git a/apps/platform/src/features/flow-editor/icons/brand-icons.tsx b/apps/platform/src/features/flow-editor/icons/brand-icons.tsx deleted file mode 100644 index 9fe2bea..0000000 --- a/apps/platform/src/features/flow-editor/icons/brand-icons.tsx +++ /dev/null @@ -1,119 +0,0 @@ -// Brand AI & Media Icons - -const AnthropicIcon = (props) => ( - - - -) - -const ChatGptIcon = (props) => ( - - - -) - -const DeepseekIcon = (props) => ( - - - -) - -const GeminiIcon = (props) => ( - - - - - - - - - - -) - -const SunoIcon = (props) => ( - - - -) - -const ElevenlabsIcon = (props) => ( - - - - -) - -const PiApiIcon = (props) => ( - - - -) - -const CreatoMateIcon = (props) => ( - - - - - -) - -const SoundCloudIcon = (props) => ( - - - -) - -export { - AnthropicIcon, - ChatGptIcon, - DeepseekIcon, - GeminiIcon, - SunoIcon, - ElevenlabsIcon, - PiApiIcon, - CreatoMateIcon, - SoundCloudIcon, -} diff --git a/apps/platform/src/features/flow-editor/icons/index.ts b/apps/platform/src/features/flow-editor/icons/index.ts index db63d0f..e1f37cc 100644 --- a/apps/platform/src/features/flow-editor/icons/index.ts +++ b/apps/platform/src/features/flow-editor/icons/index.ts @@ -1,71 +1,2 @@ -import { Send } from 'lucide-react' - -import { - AnthropicIcon, - ChatGptIcon, - DeepseekIcon, - GeminiIcon, - SunoIcon, - ElevenlabsIcon, - PiApiIcon, - CreatoMateIcon, - SoundCloudIcon, -} from './brand-icons' - -import { - XIcon, - InstagramIcon, - TiktokIcon, - FacebookIcon, - LinkedinIcon, - YouTubeIcon, - DiscordIcon, - SlackIcon, - WhatsAppIcon, - TelegramIcon, -} from './social-icons' - -import { - GmailIcon, - OutlookIcon, - GoogleDriveIcon, - GoogleSheetsIcon, - GoogleDocsIcon, - NotionIcon, - DeepLIcon, - CoinGeckoIcon, -} from './productivity-icons' - export { directionIcons } from './direction-icons' - -export const secretIcons = { - anthropic: AnthropicIcon, - chatgpt: ChatGptIcon, - deepseek: DeepseekIcon, - gemini: GeminiIcon, - gmail: GmailIcon, - outlook: OutlookIcon, - telegram: TelegramIcon, - x: XIcon, - instagram: InstagramIcon, - tiktok: TiktokIcon, - facebook: FacebookIcon, - linkedin: LinkedinIcon, - youtube: YouTubeIcon, - google_drive: GoogleDriveIcon, - google_sheets: GoogleSheetsIcon, - google_docs: GoogleDocsIcon, - sunomusic: SunoIcon, - elevenlabs: ElevenlabsIcon, - smtp: Send, - piapi: PiApiIcon, - creatomate: CreatoMateIcon, - whatsapp: WhatsAppIcon, - deepl: DeepLIcon, - coingecko: CoinGeckoIcon, - discord: DiscordIcon, - slack: SlackIcon, - notion: NotionIcon, - soundcloud: SoundCloudIcon, - veo: GeminiIcon, -} +export { useIconResolver, type ProviderIconComponent } from './provider-icons' diff --git a/apps/platform/src/features/flow-editor/icons/productivity-icons.tsx b/apps/platform/src/features/flow-editor/icons/productivity-icons.tsx deleted file mode 100644 index 61a9074..0000000 --- a/apps/platform/src/features/flow-editor/icons/productivity-icons.tsx +++ /dev/null @@ -1,313 +0,0 @@ -// Productivity & Service Icons - -const GmailIcon = (props) => ( - - - - - - - -) - -const OutlookIcon = (props) => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -) - -const GoogleDriveIcon = (props) => ( - - - - - - - - -) - -const GoogleSheetsIcon = (props) => ( - - - - - -) - -const GoogleDocsIcon = (props) => ( - - - - - -) - -const NotionIcon = (props) => ( - - - - - -) - -const DeepLIcon = (props) => ( - - - - - - - - -) - -const CoinGeckoIcon = (props) => ( - - - - - - - - - - - - - - - - -) - -export { - GmailIcon, - OutlookIcon, - GoogleDriveIcon, - GoogleSheetsIcon, - GoogleDocsIcon, - NotionIcon, - DeepLIcon, - CoinGeckoIcon, -} diff --git a/apps/platform/src/features/flow-editor/icons/provider-icons.tsx b/apps/platform/src/features/flow-editor/icons/provider-icons.tsx new file mode 100644 index 0000000..05f86f8 --- /dev/null +++ b/apps/platform/src/features/flow-editor/icons/provider-icons.tsx @@ -0,0 +1,119 @@ +import { useCallback } from 'react' +import type { ReactNode } from 'react' + +import type { IconSource } from '@/features/flow-editor/types' +import { cn } from '@/lib/utils' +import { useThemeStore } from '@/stores/theme-store' + +const brandSource = (brand: string, mode: 'light' | 'dark') => + `/assets/icons/brands/${brand}/${mode}.svg` +const glyphSource = (glyph: string) => `/assets/icons/glyphs/${glyph}.svg` + +type IconProps = { + className?: string +} + +export type ProviderIconComponent = (props: IconProps) => ReactNode + +const builtIcons = new Map() + +const artwork = (source: string, className?: string) => ( + +) + +const badge = (glyph: string) => ( + + + +) + +const buildIcon = ( + icon: { brand?: string; glyph?: string }, + mode: 'light' | 'dark', +): ProviderIconComponent | undefined => { + if (icon.brand && icon.glyph) { + return ({ className }: IconProps) => ( + + {artwork(brandSource(icon.brand!, mode), 'size-[70%]')} + {badge(icon.glyph!)} + + ) + } + + if (icon.brand) { + return ({ className }: IconProps) => + artwork( + brandSource(icon.brand!, mode), + cn('inline-block shrink-0', className), + ) + } + + if (icon.glyph) { + return ({ className }: IconProps) => ( + + ) + } + + return undefined +} + +export const useIconResolver = () => { + const mode = useThemeStore((state) => state.getMode()) + + return useCallback( + (icon: IconSource) => { + if (!icon) { + return undefined + } + + const key = `${mode}:${icon.brand ?? ''}:${icon.glyph ?? ''}` + const existing = builtIcons.get(key) + if (existing) { + return existing + } + + const built = buildIcon(icon, mode) + if (built) { + builtIcons.set(key, built) + } + + return built + }, + [mode], + ) +} diff --git a/apps/platform/src/features/flow-editor/icons/social-icons.tsx b/apps/platform/src/features/flow-editor/icons/social-icons.tsx deleted file mode 100644 index 4d8a400..0000000 --- a/apps/platform/src/features/flow-editor/icons/social-icons.tsx +++ /dev/null @@ -1,322 +0,0 @@ -// Social Media Icons - -const XIcon = (props) => ( - - - -) - -const InstagramIcon = (props) => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - -) - -const TiktokIcon = (props) => ( - - - - - -) - -const FacebookIcon = (props) => ( - - - - - - - - - - - - - - - - -) - -const LinkedinIcon = (props) => ( - - - - - -) - -const YouTubeIcon = (props) => ( - - - - - - - - - - - -) - -const DiscordIcon = (props) => ( - - - - - - - - - - - - - - - -) - -const SlackIcon = (props) => ( - - - - - - - - - - -) - -const WhatsAppIcon = (props) => ( - - - - - - - -) - -const TelegramIcon = (props) => ( - - - - - - - - - - -) - -export { - XIcon, - InstagramIcon, - TiktokIcon, - FacebookIcon, - LinkedinIcon, - YouTubeIcon, - DiscordIcon, - SlackIcon, - WhatsAppIcon, - TelegramIcon, -} diff --git a/apps/platform/src/features/flow-editor/nodes/annotation.tsx b/apps/platform/src/features/flow-editor/nodes/annotation.tsx index d5393a3..ddc4899 100644 --- a/apps/platform/src/features/flow-editor/nodes/annotation.tsx +++ b/apps/platform/src/features/flow-editor/nodes/annotation.tsx @@ -1,15 +1,18 @@ -import { useState, useRef, useEffect } from 'react' +import { useState, useRef, useEffect, useCallback } from 'react' import { useTranslation } from 'react-i18next' import { AnnotationNode, AnnotationNodeContent, } from '@/features/flow-editor/nodes/annotation-node' +import { useFlowSetNodes } from '@/features/flow-editor/contexts/flow-nodes-context' -const Annotation = () => { +const Annotation = ({ id, data }) => { const { t } = useTranslation() - const [content, setContent] = useState(t('ui.text.annotationPlaceholder')) + const setNodes = useFlowSetNodes() const [isEditing, setIsEditing] = useState(false) - const inputRef = useRef(null) + const inputRef = useRef(null) + + const note = data?.note ?? '' useEffect(() => { if (isEditing && inputRef.current) { @@ -17,20 +20,19 @@ const Annotation = () => { } }, [isEditing]) - const handleContentClick = () => { - setIsEditing(true) - } - - const handleInputChange = (e: React.ChangeEvent) => { - setContent(e.target.value) - } - - const handleInputBlur = () => { - setIsEditing(false) - } + const updateNote = useCallback( + (value: string) => { + setNodes((nodes) => + nodes.map((n) => + n.id === id ? { ...n, data: { ...n.data, note: value } } : n, + ), + ) + }, + [id, setNodes], + ) - const handleInputKeyDown = (e: React.KeyboardEvent) => { - if (e.key === 'Enter') { + const handleInputKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Escape') { setIsEditing(false) } } @@ -38,29 +40,22 @@ const Annotation = () => { return ( setIsEditing(true)} + className="w-full cursor-text" > {isEditing ? (