@@ -31,10 +31,18 @@ import {
3131 LoaderIcon ,
3232 PlayIcon ,
3333 ScrollTextIcon ,
34+ SearchCodeIcon ,
3435 XIcon ,
3536} from "lucide-react" ;
3637import { AnimatePresence , motion } from "motion/react" ;
37- import { type FC , useCallback , useEffect , useMemo , useState } from "react" ;
38+ import {
39+ type FC ,
40+ type PropsWithChildren ,
41+ useCallback ,
42+ useEffect ,
43+ useMemo ,
44+ useState ,
45+ } from "react" ;
3846import { useSearchParams } from "react-router" ;
3947import {
4048 Select ,
@@ -196,7 +204,7 @@ export const Preview: FC = () => {
196204 ( $errors . show && $errors . diagnostics . length > 0 )
197205 }
198206 className = { cn (
199- "flex h-full w-full flex-col items-start gap-6 p-6 " ,
207+ "flex h-full w-full flex-col items-start gap-4 p-5 " ,
200208 ( $wasmState !== "loaded" ||
201209 ( $errors . show && $errors . diagnostics . length > 0 ) ) &&
202210 "pointer-events-none" ,
@@ -226,16 +234,7 @@ export const Preview: FC = () => {
226234 ) : null }
227235 </ AnimatePresence >
228236 </ div >
229- < div className = "flex w-full items-center justify-end gap-3" >
230- < UserSelect />
231- < Button
232- variant = "destructive"
233- onClick = { $resetForm }
234- className = "w-fit"
235- >
236- Reset form
237- </ Button >
238- </ div >
237+ < UserSelect />
239238 </ div >
240239 }
241240 { $parameters . length === 0 ? (
@@ -247,6 +246,12 @@ export const Preview: FC = () => {
247246 < Form parameters = { $parameters } />
248247 </ div >
249248 ) }
249+ < div className = "flex w-full justify-between gap-3" >
250+ < Button variant = "outline" onClick = { $resetForm } className = "w-fit" >
251+ Reset form
252+ </ Button >
253+ < ViewOutput />
254+ </ div >
250255 </ div >
251256 </ Tabs . Content >
252257
@@ -486,15 +491,17 @@ const LogsEmptyState = () => {
486491
487492type LogProps = { log : ParserLog } ;
488493const Log : FC < LogProps > = ( { log } ) => {
489- const [ showTable , setShowTable ] = useState ( ( ) => false ) ;
494+ const data = Object . entries ( log ) . reduce < Record < string , unknown > > (
495+ ( acc , [ key , value ] ) => {
496+ acc [ key ] = value ;
497+ return acc ;
498+ } ,
499+ { } ,
500+ ) ;
490501
491502 return (
492- < Dialog . Root
493- modal = { true }
494- open = { showTable }
495- onOpenChange = { ( show ) => setShowTable ( ( ) => show ) }
496- >
497- < Dialog . Trigger
503+ < TableDrawer data = { data } >
504+ < button
498505 className = { cn (
499506 "group grid h-fit min-h-10 w-full grid-cols-8 items-center border-b border-l-4 border-l-content-destructive hover:bg-surface-primary" ,
500507 log . level . toLowerCase ( ) === "info" && "border-l-content-link" ,
@@ -509,7 +516,91 @@ const Log: FC<LogProps> = ({ log }) => {
509516 < p className = "col-span-6 break-all p-2 text-left font-mono text-content-primary text-xs" >
510517 { JSON . stringify ( log ) }
511518 </ p >
512- </ Dialog . Trigger >
519+ </ button >
520+ </ TableDrawer >
521+ ) ;
522+ } ;
523+
524+ type FormProps = { parameters : ParameterWithSource [ ] } ;
525+
526+ const Form : FC < FormProps > = ( { parameters } ) => {
527+ return parameters
528+ . sort ( ( a , b ) => a . order - b . order )
529+ . map ( ( p , index ) => < FormElement key = { index } parameter = { p } /> ) ;
530+ } ;
531+
532+ type FormElementProps = { parameter : ParameterWithSource } ;
533+ const FormElement : FC < FormElementProps > = ( { parameter } ) => {
534+ const $form = useStore ( ( state ) => state . form ) ;
535+ const $setForm = useStore ( ( state ) => state . setFormState ) ;
536+
537+ const value = useMemo (
538+ ( ) =>
539+ $form [ parameter . name ] ??
540+ ( parameter . default_value . value === "??"
541+ ? ""
542+ : parameter . default_value . value ) ,
543+ [ $form , parameter ] ,
544+ ) ;
545+
546+ const onValueChange = ( value : string ) => {
547+ $setForm ( parameter . name , value ) ;
548+ } ;
549+
550+ return (
551+ < DynamicParameter
552+ parameter = { parameter }
553+ value = { value }
554+ autofill = { false }
555+ onChange = { onValueChange }
556+ disabled = { parameter . styling . disabled }
557+ />
558+ ) ;
559+ } ;
560+
561+ const UserSelect : FC = ( ) => {
562+ const $setWorkspaceOwner = useStore ( ( state ) => state . setWorkspaceOwner ) ;
563+
564+ return (
565+ < Select
566+ defaultValue = "admin"
567+ onValueChange = { ( value ) => {
568+ const users : Record < string , WorkspaceOwner | undefined > = mockUsers ;
569+ $setWorkspaceOwner ( users [ value ] ?? mockUsers . admin ) ;
570+ } }
571+ >
572+ < SelectTrigger className = "w-fit min-w-40" >
573+ < SelectValue />
574+ </ SelectTrigger >
575+ < SelectContent >
576+ < SelectItem value = "admin" > Administrator</ SelectItem >
577+ < SelectItem value = "developer" > Developer</ SelectItem >
578+ < SelectItem value = "contractor" > Contractor</ SelectItem >
579+ < SelectItem value = "eu-developer" > EU Developer</ SelectItem >
580+ </ SelectContent >
581+ </ Select >
582+ ) ;
583+ } ;
584+
585+ type TableDrawerProps = {
586+ data : Record < string , unknown > ;
587+ headers ?: [ string , string ] ;
588+ } & PropsWithChildren ;
589+
590+ const TableDrawer : FC < TableDrawerProps > = ( {
591+ data,
592+ headers = [ "field" , "value" ] ,
593+ children,
594+ } ) => {
595+ const [ showTable , setShowTable ] = useState ( ( ) => false ) ;
596+
597+ return (
598+ < Dialog . Root
599+ modal = { true }
600+ open = { showTable }
601+ onOpenChange = { ( show ) => setShowTable ( ( ) => show ) }
602+ >
603+ < Dialog . Trigger asChild = { true } > { children } </ Dialog . Trigger >
513604
514605 < Dialog . Portal forceMount = { true } >
515606 < AnimatePresence propagate = { true } >
@@ -528,11 +619,11 @@ const Log: FC<LogProps> = ({ log }) => {
528619 initial = { { opacity : 0 , transform : "translateX(100px)" } }
529620 animate = { { opacity : 1 , transform : "translateX(0px)" } }
530621 exit = { { opacity : 0 , transform : "translateX(100px)" } }
531- className = "fixed top-0 right-0 z-20 flex h-full w-full max-w-md flex-col justify-start gap-6 border-l bg-surface-primary p-4"
622+ className = "fixed top-0 right-0 z-20 flex h-full w-full max-w-lg flex-col justify-start gap-6 border-l bg-surface-primary p-4"
532623 >
533624 < div className = "flex items-center justify-between" >
534625 < Dialog . Title className = "font-semibold text-2xl text-content-primary" >
535- Log
626+ Parameter Values
536627 </ Dialog . Title >
537628 < Dialog . Close asChild = { true } >
538629 < Button
@@ -544,16 +635,16 @@ const Log: FC<LogProps> = ({ log }) => {
544635 </ Button >
545636 </ Dialog . Close >
546637 </ div >
547- < div className = "flex w-full flex-col overflow-clip rounded-lg border font-mono text-content-primary text-xs" >
638+ < div className = "flex w-full flex-col overflow-scroll rounded-lg border font-mono text-content-primary text-xs" >
548639 < div className = "grid grid-cols-8 border-b bg-surface-secondary" >
549640 < div className = "col-span-2 flex min-h-8 items-center border-r px-2 py-1" >
550- < p className = "text-left uppercase" > field </ p >
641+ < p className = "text-left uppercase" > { headers [ 0 ] } </ p >
551642 </ div >
552643 < div className = "col-span-6 flex min-h-8 items-center px-2 py-1" >
553- < p className = "text-left uppercase" > value </ p >
644+ < p className = "text-left uppercase" > { headers [ 1 ] } </ p >
554645 </ div >
555646 </ div >
556- { Object . entries ( log ) . map ( ( [ key , value ] , index ) => {
647+ { Object . entries ( data ) . map ( ( [ key , value ] , index ) => {
557648 const displayValue = JSON . stringify ( value ) ;
558649
559650 return (
@@ -593,63 +684,29 @@ const Log: FC<LogProps> = ({ log }) => {
593684 ) ;
594685} ;
595686
596- type FormProps = { parameters : ParameterWithSource [ ] } ;
597-
598- const Form : FC < FormProps > = ( { parameters } ) => {
599- return parameters
600- . sort ( ( a , b ) => a . order - b . order )
601- . map ( ( p , index ) => < FormElement key = { index } parameter = { p } /> ) ;
602- } ;
603-
604- type FormElementProps = { parameter : ParameterWithSource } ;
605- const FormElement : FC < FormElementProps > = ( { parameter } ) => {
606- const $form = useStore ( ( state ) => state . form ) ;
607- const $setForm = useStore ( ( state ) => state . setFormState ) ;
687+ const ViewOutput : FC = ( ) => {
688+ const $parameters = useStore ( ( state ) => state . parameters ) ;
608689
609- const value = useMemo (
610- ( ) =>
611- $form [ parameter . name ] ??
612- ( parameter . default_value . value === "??"
613- ? ""
614- : parameter . default_value . value ) ,
615- [ $form , parameter ] ,
690+ const isInvalid = useMemo (
691+ ( ) => $parameters . length === 0 || $parameters . some ( ( p ) => ! p . value . valid ) ,
692+ [ $parameters ] ,
616693 ) ;
617694
618- const onValueChange = ( value : string ) => {
619- $setForm ( parameter . name , value ) ;
620- } ;
621-
622- return (
623- < DynamicParameter
624- parameter = { parameter }
625- value = { value }
626- autofill = { false }
627- onChange = { onValueChange }
628- disabled = { parameter . styling . disabled }
629- />
695+ const data = useMemo (
696+ ( ) =>
697+ $parameters . reduce < Record < string , string > > ( ( acc , p ) => {
698+ acc [ p . name ] = p . value . value ;
699+ return acc ;
700+ } , { } ) ,
701+ [ $parameters ] ,
630702 ) ;
631- } ;
632-
633- const UserSelect : FC = ( ) => {
634- const $setWorkspaceOwner = useStore ( ( state ) => state . setWorkspaceOwner ) ;
635703
636704 return (
637- < Select
638- defaultValue = "admin"
639- onValueChange = { ( value ) => {
640- const users : Record < string , WorkspaceOwner | undefined > = mockUsers ;
641- $setWorkspaceOwner ( users [ value ] ?? mockUsers . admin ) ;
642- } }
643- >
644- < SelectTrigger className = "w-fit min-w-40" >
645- < SelectValue />
646- </ SelectTrigger >
647- < SelectContent >
648- < SelectItem value = "admin" > Administrator</ SelectItem >
649- < SelectItem value = "developer" > Developer</ SelectItem >
650- < SelectItem value = "contractor" > Contractor</ SelectItem >
651- < SelectItem value = "eu-developer" > EU Developer</ SelectItem >
652- </ SelectContent >
653- </ Select >
705+ < TableDrawer data = { data } headers = { [ "Parameter" , "Value" ] } >
706+ < Button variant = "default" disabled = { isInvalid } >
707+ < SearchCodeIcon />
708+ View output
709+ </ Button >
710+ </ TableDrawer >
654711 ) ;
655712} ;
0 commit comments