Skip to content

Commit c249bb0

Browse files
authored
feat: add ability to attach source to an environment (#809)
Allows attaching environments to sources for all callers. This introduces the distinction between a System Environment and User Configuration to the system. These names might be stupid but they attempt to get around the idea that Headers are more of an implementation detail and the rules associated with how you merge these things should be derived from their provenance rather than how they were supplied. We make some decisions. First off, we complect the call sites of tool proxies by placing the onus of loading on them. This was more or less in the name of purity of the tools proxy. But might be a mistake because it forces the onus of reading system environments to a bunch of places in our code base. It's possible it's a little bug-prone to do this nonsense in a bunch of places. The other decision, which I feel a little better about is to provide both environments to each tool type and leave the responsibility of merging them at the call site. Even though we aim for consistent behavior (ie. preferring user config over system environment), leaving the flexibility on how to merge each tool type seems healthy. ## UX A dialog attached to source cards. Not good. Affordance to access functionality is currently buried behind: <img width="720" height="391" alt="image" src="https://github.com/user-attachments/assets/fce5cd45-7b45-4485-a26a-346c44e817a5" /> The interface for attaching an environment is implemented in this modal: <img width="779" height="356" alt="image" src="https://github.com/user-attachments/assets/89de283e-d412-44a8-b15b-276002762419" /> * We use a combobox * We try to preview what variables will be set to make more mistakes more obvious * Currently pretty ugly, but banking on the UX moving to a new location shortly before I figure out a good hierarchy for presenting. Happy to knock any quick fixes to make this present better if people feel strongly ## Things to pay Attention To * Moved sources components to new directory, but also changed the modal paradigm (separate content components, used `zustand` for state management) * I ported all of the `Dialog`s and Dropdown Menu's to the moonshine versions of those components. I couldn't visually tell the difference and there were some really nasty interplay issues. Hoping this is a nice stability move ## Considerations * Might consider adding a confirmation button considering this action is a pretty serious one * UX is quite ugly at the moment. Preferring to follow up with a dedicated sources page instead of burying behind a dialog * Blocked on this moonshine PR: speakeasy-api/moonshine#319
1 parent 033e09c commit c249bb0

File tree

100 files changed

+27231
-14161
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+27231
-14161
lines changed

.changeset/mighty-sheep-sip.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"dashboard": minor
3+
"server": minor
4+
---
5+
6+
Adds the ability to attach an environment to a source such that all tool calls originating from that source will have those environment variables apply

.mise-tasks/infra/stop.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44
set -e
55

6-
docker compose --profile "*" down --remove-orphans
6+
docker compose --profile "*" down --remove-orphans

.speakeasy/out.openapi.yaml

Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3002,6 +3002,220 @@ paths:
30023002
x-speakeasy-name-override: deleteBySlug
30033003
x-speakeasy-react-hook:
30043004
name: DeleteEnvironment
3005+
/rpc/environments.deleteSourceLink:
3006+
delete:
3007+
description: Delete a link between a source and an environment
3008+
operationId: deleteSourceEnvironmentLink
3009+
parameters:
3010+
- allowEmptyValue: true
3011+
description: The kind of source (http or function)
3012+
in: query
3013+
name: source_kind
3014+
required: true
3015+
schema:
3016+
description: The kind of source that can be linked to an environment
3017+
enum:
3018+
- http
3019+
- function
3020+
type: string
3021+
- allowEmptyValue: true
3022+
description: The slug of the source
3023+
in: query
3024+
name: source_slug
3025+
required: true
3026+
schema:
3027+
description: The slug of the source
3028+
type: string
3029+
- allowEmptyValue: true
3030+
description: Session header
3031+
in: header
3032+
name: Gram-Session
3033+
schema:
3034+
description: Session header
3035+
type: string
3036+
- allowEmptyValue: true
3037+
description: project header
3038+
in: header
3039+
name: Gram-Project
3040+
schema:
3041+
description: project header
3042+
type: string
3043+
responses:
3044+
"200":
3045+
description: OK response.
3046+
"400":
3047+
content:
3048+
application/json:
3049+
schema:
3050+
$ref: '#/components/schemas/Error'
3051+
description: 'bad_request: request is invalid'
3052+
"401":
3053+
content:
3054+
application/json:
3055+
schema:
3056+
$ref: '#/components/schemas/Error'
3057+
description: 'unauthorized: unauthorized access'
3058+
"403":
3059+
content:
3060+
application/json:
3061+
schema:
3062+
$ref: '#/components/schemas/Error'
3063+
description: 'forbidden: permission denied'
3064+
"404":
3065+
content:
3066+
application/json:
3067+
schema:
3068+
$ref: '#/components/schemas/Error'
3069+
description: 'not_found: resource not found'
3070+
"409":
3071+
content:
3072+
application/json:
3073+
schema:
3074+
$ref: '#/components/schemas/Error'
3075+
description: 'conflict: resource already exists'
3076+
"415":
3077+
content:
3078+
application/json:
3079+
schema:
3080+
$ref: '#/components/schemas/Error'
3081+
description: 'unsupported_media: unsupported media type'
3082+
"422":
3083+
content:
3084+
application/json:
3085+
schema:
3086+
$ref: '#/components/schemas/Error'
3087+
description: 'invalid: request contains one or more invalidation fields'
3088+
"500":
3089+
content:
3090+
application/json:
3091+
schema:
3092+
$ref: '#/components/schemas/Error'
3093+
description: 'unexpected: an unexpected error occurred'
3094+
"502":
3095+
content:
3096+
application/json:
3097+
schema:
3098+
$ref: '#/components/schemas/Error'
3099+
description: 'gateway_error: an unexpected error occurred'
3100+
security:
3101+
- project_slug_header_Gram-Project: []
3102+
session_header_Gram-Session: []
3103+
- {}
3104+
summary: deleteSourceEnvironmentLink environments
3105+
tags:
3106+
- environments
3107+
x-speakeasy-name-override: deleteSourceLink
3108+
x-speakeasy-react-hook:
3109+
name: DeleteSourceEnvironmentLink
3110+
/rpc/environments.getSourceEnvironment:
3111+
get:
3112+
description: Get the environment linked to a source
3113+
operationId: getSourceEnvironment
3114+
parameters:
3115+
- allowEmptyValue: true
3116+
description: The kind of source (http or function)
3117+
in: query
3118+
name: source_kind
3119+
required: true
3120+
schema:
3121+
description: The kind of source that can be linked to an environment
3122+
enum:
3123+
- http
3124+
- function
3125+
type: string
3126+
- allowEmptyValue: true
3127+
description: The slug of the source
3128+
in: query
3129+
name: source_slug
3130+
required: true
3131+
schema:
3132+
description: The slug of the source
3133+
type: string
3134+
- allowEmptyValue: true
3135+
description: Session header
3136+
in: header
3137+
name: Gram-Session
3138+
schema:
3139+
description: Session header
3140+
type: string
3141+
- allowEmptyValue: true
3142+
description: project header
3143+
in: header
3144+
name: Gram-Project
3145+
schema:
3146+
description: project header
3147+
type: string
3148+
responses:
3149+
"200":
3150+
content:
3151+
application/json:
3152+
schema:
3153+
$ref: '#/components/schemas/Environment'
3154+
description: OK response.
3155+
"400":
3156+
content:
3157+
application/json:
3158+
schema:
3159+
$ref: '#/components/schemas/Error'
3160+
description: 'bad_request: request is invalid'
3161+
"401":
3162+
content:
3163+
application/json:
3164+
schema:
3165+
$ref: '#/components/schemas/Error'
3166+
description: 'unauthorized: unauthorized access'
3167+
"403":
3168+
content:
3169+
application/json:
3170+
schema:
3171+
$ref: '#/components/schemas/Error'
3172+
description: 'forbidden: permission denied'
3173+
"404":
3174+
content:
3175+
application/json:
3176+
schema:
3177+
$ref: '#/components/schemas/Error'
3178+
description: 'not_found: resource not found'
3179+
"409":
3180+
content:
3181+
application/json:
3182+
schema:
3183+
$ref: '#/components/schemas/Error'
3184+
description: 'conflict: resource already exists'
3185+
"415":
3186+
content:
3187+
application/json:
3188+
schema:
3189+
$ref: '#/components/schemas/Error'
3190+
description: 'unsupported_media: unsupported media type'
3191+
"422":
3192+
content:
3193+
application/json:
3194+
schema:
3195+
$ref: '#/components/schemas/Error'
3196+
description: 'invalid: request contains one or more invalidation fields'
3197+
"500":
3198+
content:
3199+
application/json:
3200+
schema:
3201+
$ref: '#/components/schemas/Error'
3202+
description: 'unexpected: an unexpected error occurred'
3203+
"502":
3204+
content:
3205+
application/json:
3206+
schema:
3207+
$ref: '#/components/schemas/Error'
3208+
description: 'gateway_error: an unexpected error occurred'
3209+
security:
3210+
- project_slug_header_Gram-Project: []
3211+
session_header_Gram-Session: []
3212+
- {}
3213+
summary: getSourceEnvironment environments
3214+
tags:
3215+
- environments
3216+
x-speakeasy-name-override: getBySource
3217+
x-speakeasy-react-hook:
3218+
name: GetSourceEnvironment
30053219
/rpc/environments.list:
30063220
get:
30073221
description: List all environments for an organization
@@ -3092,6 +3306,102 @@ paths:
30923306
x-speakeasy-name-override: list
30933307
x-speakeasy-react-hook:
30943308
name: ListEnvironments
3309+
/rpc/environments.setSourceLink:
3310+
put:
3311+
description: Set (upsert) a link between a source and an environment
3312+
operationId: setSourceEnvironmentLink
3313+
parameters:
3314+
- allowEmptyValue: true
3315+
description: Session header
3316+
in: header
3317+
name: Gram-Session
3318+
schema:
3319+
description: Session header
3320+
type: string
3321+
- allowEmptyValue: true
3322+
description: project header
3323+
in: header
3324+
name: Gram-Project
3325+
schema:
3326+
description: project header
3327+
type: string
3328+
requestBody:
3329+
content:
3330+
application/json:
3331+
schema:
3332+
$ref: '#/components/schemas/SetSourceEnvironmentLinkRequestBody'
3333+
required: true
3334+
responses:
3335+
"200":
3336+
content:
3337+
application/json:
3338+
schema:
3339+
$ref: '#/components/schemas/SourceEnvironmentLink'
3340+
description: OK response.
3341+
"400":
3342+
content:
3343+
application/json:
3344+
schema:
3345+
$ref: '#/components/schemas/Error'
3346+
description: 'bad_request: request is invalid'
3347+
"401":
3348+
content:
3349+
application/json:
3350+
schema:
3351+
$ref: '#/components/schemas/Error'
3352+
description: 'unauthorized: unauthorized access'
3353+
"403":
3354+
content:
3355+
application/json:
3356+
schema:
3357+
$ref: '#/components/schemas/Error'
3358+
description: 'forbidden: permission denied'
3359+
"404":
3360+
content:
3361+
application/json:
3362+
schema:
3363+
$ref: '#/components/schemas/Error'
3364+
description: 'not_found: resource not found'
3365+
"409":
3366+
content:
3367+
application/json:
3368+
schema:
3369+
$ref: '#/components/schemas/Error'
3370+
description: 'conflict: resource already exists'
3371+
"415":
3372+
content:
3373+
application/json:
3374+
schema:
3375+
$ref: '#/components/schemas/Error'
3376+
description: 'unsupported_media: unsupported media type'
3377+
"422":
3378+
content:
3379+
application/json:
3380+
schema:
3381+
$ref: '#/components/schemas/Error'
3382+
description: 'invalid: request contains one or more invalidation fields'
3383+
"500":
3384+
content:
3385+
application/json:
3386+
schema:
3387+
$ref: '#/components/schemas/Error'
3388+
description: 'unexpected: an unexpected error occurred'
3389+
"502":
3390+
content:
3391+
application/json:
3392+
schema:
3393+
$ref: '#/components/schemas/Error'
3394+
description: 'gateway_error: an unexpected error occurred'
3395+
security:
3396+
- project_slug_header_Gram-Project: []
3397+
session_header_Gram-Session: []
3398+
- {}
3399+
summary: setSourceEnvironmentLink environments
3400+
tags:
3401+
- environments
3402+
x-speakeasy-name-override: setSourceLink
3403+
x-speakeasy-react-hook:
3404+
name: SetSourceEnvironmentLink
30953405
/rpc/environments.update:
30963406
post:
30973407
description: Update an environment
@@ -11115,6 +11425,52 @@ components:
1111511425
$ref: '#/components/schemas/Project'
1111611426
required:
1111711427
- project
11428+
SetSourceEnvironmentLinkRequestBody:
11429+
type: object
11430+
properties:
11431+
environment_id:
11432+
type: string
11433+
description: The ID of the environment to link
11434+
format: uuid
11435+
source_kind:
11436+
type: string
11437+
description: The kind of source (http or function)
11438+
enum:
11439+
- http
11440+
- function
11441+
source_slug:
11442+
type: string
11443+
description: The slug of the source
11444+
required:
11445+
- source_kind
11446+
- source_slug
11447+
- environment_id
11448+
SourceEnvironmentLink:
11449+
type: object
11450+
properties:
11451+
environment_id:
11452+
type: string
11453+
description: The ID of the environment
11454+
format: uuid
11455+
id:
11456+
type: string
11457+
description: The ID of the source environment link
11458+
format: uuid
11459+
source_kind:
11460+
type: string
11461+
description: The kind of source that can be linked to an environment
11462+
enum:
11463+
- http
11464+
- function
11465+
source_slug:
11466+
type: string
11467+
description: The slug of the source
11468+
description: A link between a source and an environment
11469+
required:
11470+
- id
11471+
- source_kind
11472+
- source_slug
11473+
- environment_id
1111811474
TierLimits:
1111911475
type: object
1112011476
properties:

0 commit comments

Comments
 (0)