@@ -27,9 +27,11 @@ import {
27
27
ResizablePanelGroup ,
28
28
} from "~/components/primitives/Resizable" ;
29
29
import { Select } from "~/components/primitives/Select" ;
30
+ import { TabButton , TabContainer } from "~/components/primitives/Tabs" ;
30
31
import { TextLink } from "~/components/primitives/TextLink" ;
31
32
import { TaskRunStatusCombo } from "~/components/runs/v3/TaskRunStatus" ;
32
33
import { TimezoneList } from "~/components/scheduled/timezones" ;
34
+ import { useSearchParams } from "~/hooks/useSearchParam" ;
33
35
import { redirectBackWithErrorMessage , redirectWithSuccessMessage } from "~/models/message.server" ;
34
36
import {
35
37
ScheduledRun ,
@@ -39,6 +41,7 @@ import {
39
41
} from "~/presenters/v3/TestTaskPresenter.server" ;
40
42
import { logger } from "~/services/logger.server" ;
41
43
import { requireUserId } from "~/services/session.server" ;
44
+ import { cn } from "~/utils/cn" ;
42
45
import { docsPath , v3RunSpanPath , v3TaskParamsSchema } from "~/utils/pathBuilder" ;
43
46
import { TestTaskService } from "~/v3/services/testTask.server" ;
44
47
import { OutOfEntitlementError } from "~/v3/services/triggerTask.server" ;
@@ -129,27 +132,44 @@ export default function Page() {
129
132
const startingJson = "{\n\n}" ;
130
133
131
134
function StandardTaskForm ( { task, runs } : { task : TestTask [ "task" ] ; runs : StandardRun [ ] } ) {
135
+ const { value, replace } = useSearchParams ( ) ;
136
+ const tab = value ( "tab" ) ;
137
+
132
138
//form submission
133
139
const submit = useSubmit ( ) ;
134
140
const lastSubmission = useActionData ( ) ;
135
141
136
142
//recent runs
137
143
const [ selectedCodeSampleId , setSelectedCodeSampleId ] = useState ( runs . at ( 0 ) ?. id ) ;
138
- const selectedCodeSample = runs . find ( ( r ) => r . id === selectedCodeSampleId ) ?. payload ;
144
+ const selectedCodeSample = runs . find ( ( r ) => r . id === selectedCodeSampleId ) ;
145
+ const selectedCodeSamplePayload = selectedCodeSample ?. payload ;
146
+ const selectedCodeSampleMetadata = selectedCodeSample ?. metadata ;
139
147
140
- const [ defaultJson , setDefaultJson ] = useState < string > ( selectedCodeSample ?? startingJson ) ;
141
- const setCode = useCallback ( ( code : string ) => {
142
- setDefaultJson ( code ) ;
148
+ const [ defaultPayloadJson , setDefaultPayloadJson ] = useState < string > (
149
+ selectedCodeSamplePayload ?? startingJson
150
+ ) ;
151
+ const setPayload = useCallback ( ( code : string ) => {
152
+ setDefaultPayloadJson ( code ) ;
143
153
} , [ ] ) ;
144
154
145
- const currentJson = useRef < string > ( defaultJson ) ;
155
+ const currentPayloadJson = useRef < string > ( defaultPayloadJson ) ;
156
+
157
+ const [ defaultMetadataJson , setDefaultMetadataJson ] = useState < string > (
158
+ selectedCodeSampleMetadata ?? "{}"
159
+ ) ;
160
+ const setMetadata = useCallback ( ( code : string ) => {
161
+ setDefaultMetadataJson ( code ) ;
162
+ } , [ ] ) ;
163
+
164
+ const currentMetadataJson = useRef < string > ( defaultMetadataJson ) ;
146
165
147
166
const submitForm = useCallback (
148
167
( e : React . FormEvent < HTMLFormElement > ) => {
149
168
submit (
150
169
{
151
170
triggerSource : "STANDARD" ,
152
- payload : currentJson . current ,
171
+ payload : currentPayloadJson . current ,
172
+ metadata : currentMetadataJson . current ,
153
173
taskIdentifier : task . taskIdentifier ,
154
174
environmentId : task . environment . id ,
155
175
} ,
@@ -160,7 +180,7 @@ function StandardTaskForm({ task, runs }: { task: TestTask["task"]; runs: Standa
160
180
) ;
161
181
e . preventDefault ( ) ;
162
182
} ,
163
- [ currentJson ]
183
+ [ currentPayloadJson , currentMetadataJson ]
164
184
) ;
165
185
166
186
const [ form , { environmentId, payload } ] = useForm ( {
@@ -183,28 +203,73 @@ function StandardTaskForm({ task, runs }: { task: TestTask["task"]; runs: Standa
183
203
< ResizablePanelGroup orientation = "horizontal" >
184
204
< ResizablePanel id = "test-task-main" min = "100px" default = "60%" >
185
205
< div className = "h-full bg-charcoal-900" >
186
- < JSONEditor
187
- defaultValue = { defaultJson }
188
- readOnly = { false }
189
- basicSetup
190
- onChange = { ( v ) => {
191
- currentJson . current = v ;
192
-
193
- //deselect the example if it's been edited
194
- if ( selectedCodeSampleId ) {
195
- if ( v !== selectedCodeSample ) {
196
- setDefaultJson ( v ) ;
197
- setSelectedCodeSampleId ( undefined ) ;
206
+ < TabContainer className = "px-3 pt-2" >
207
+ < TabButton
208
+ isActive = { ! tab || tab === "payload" }
209
+ layoutId = "test-editor"
210
+ onClick = { ( ) => {
211
+ replace ( { tab : "payload" } ) ;
212
+ } }
213
+ >
214
+ Payload
215
+ </ TabButton >
216
+
217
+ < TabButton
218
+ isActive = { tab === "metadata" }
219
+ layoutId = "test-editor"
220
+ onClick = { ( ) => {
221
+ replace ( { tab : "metadata" } ) ;
222
+ } }
223
+ >
224
+ Metadata
225
+ </ TabButton >
226
+ </ TabContainer >
227
+ < div >
228
+ < JSONEditor
229
+ defaultValue = { defaultPayloadJson }
230
+ readOnly = { false }
231
+ basicSetup
232
+ onChange = { ( v ) => {
233
+ currentPayloadJson . current = v ;
234
+
235
+ //deselect the example if it's been edited
236
+ if ( selectedCodeSampleId ) {
237
+ if ( v !== selectedCodeSamplePayload ) {
238
+ setDefaultPayloadJson ( v ) ;
239
+ setSelectedCodeSampleId ( undefined ) ;
240
+ }
198
241
}
199
- }
200
- } }
201
- height = "100%"
202
- min-height = "100%"
203
- max-height = "100%"
204
- autoFocus
205
- placeholder = "Use your schema to enter valid JSON or add one of the recent payloads then click 'Run test'"
206
- className = "h-full"
207
- />
242
+ } }
243
+ height = "100%"
244
+ min-height = "100%"
245
+ max-height = "100%"
246
+ autoFocus = { ! tab || tab === "payload" }
247
+ placeholder = "{ }"
248
+ className = { cn ( "h-full" , tab === "metadata" && "hidden" ) }
249
+ />
250
+ < JSONEditor
251
+ defaultValue = { defaultMetadataJson }
252
+ readOnly = { false }
253
+ basicSetup
254
+ onChange = { ( v ) => {
255
+ currentMetadataJson . current = v ;
256
+
257
+ //deselect the example if it's been edited
258
+ if ( selectedCodeSampleId ) {
259
+ if ( v !== selectedCodeSampleMetadata ) {
260
+ setDefaultMetadataJson ( v ) ;
261
+ setSelectedCodeSampleId ( undefined ) ;
262
+ }
263
+ }
264
+ } }
265
+ height = "100%"
266
+ min-height = "100%"
267
+ max-height = "100%"
268
+ autoFocus = { tab === "metadata" }
269
+ placeholder = ""
270
+ className = { cn ( "h-full" , tab !== "metadata" && "hidden" ) }
271
+ />
272
+ </ div >
208
273
</ div >
209
274
</ ResizablePanel >
210
275
< ResizableHandle id = "test-task-handle" />
@@ -213,9 +278,10 @@ function StandardTaskForm({ task, runs }: { task: TestTask["task"]; runs: Standa
213
278
runs = { runs }
214
279
selectedId = { selectedCodeSampleId }
215
280
onSelected = { ( id ) => {
216
- const payload = runs . find ( ( r ) => r . id === id ) ?. payload ;
217
- if ( ! payload ) return ;
218
- setCode ( payload ) ;
281
+ const run = runs . find ( ( r ) => r . id === id ) ;
282
+ if ( ! run ) return ;
283
+ setPayload ( run . payload ) ;
284
+ run . metadata && setMetadata ( run . metadata ) ;
219
285
setSelectedCodeSampleId ( id ) ;
220
286
} }
221
287
/>
0 commit comments