diff --git a/telemetry/ui/src/components/routes/app/DataView.tsx b/telemetry/ui/src/components/routes/app/DataView.tsx index b1f00963..1a957353 100644 --- a/telemetry/ui/src/components/routes/app/DataView.tsx +++ b/telemetry/ui/src/components/routes/app/DataView.tsx @@ -2,6 +2,10 @@ import React, { useState } from 'react'; import { Step } from '../../../api'; import JsonView from '@uiw/react-json-view'; import { Button } from '../../common/button'; +import { Switch, SwitchField } from '../../common/switch'; +import { Label } from '../../common/fieldset'; +import { classNames } from '../../../utils/tailwind'; +import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/20/solid'; const StateButton = (props: { label: string; selected: boolean; setSelected: () => void }) => { const color = props.selected ? 'zinc' : 'light'; @@ -13,46 +17,45 @@ const StateButton = (props: { label: string; selected: boolean; setSelected: () }; export const ErrorView = (props: { error: string }) => { - return
{props.error}
; + return ( + <> +
{props.error}
+ + ); }; export const DataView = (props: { currentStep: Step | undefined; priorStep: Step | undefined }) => { const [whichState, setWhichState] = useState<'after' | 'before'>('after'); const stepToExamine = whichState === 'after' ? props.currentStep : props.priorStep; const stateData = stepToExamine?.step_end_log?.state; - const resultData = stepToExamine?.step_end_log?.result; + const resultData = stepToExamine?.step_end_log?.result || undefined; const inputs = stepToExamine?.step_start_log?.inputs; const error = props.currentStep?.step_end_log?.exception; const [viewRawData, setViewRawData] = useState<'raw' | 'render'>('render'); return ( -
-
-

State

+
+
+

State

+ + { + setViewRawData(checked ? 'raw' : 'render'); + }} + > + + + {stateData !== undefined && ( - <> - { - setViewRawData('raw'); - }} - /> - { - setViewRawData('render'); - }} - /> - { - setWhichState('after'); - }} - /> - + { + setWhichState('after'); + }} + /> )} { @@ -67,136 +70,182 @@ export const DataView = (props: { currentStep: Step | undefined; priorStep: Step
- {stateData !== undefined && viewRawData === 'render' && ( - // - - )} - {stateData !== undefined && viewRawData === 'raw' && ( - - )} + {error && ( <>

Error

)} +

Result

+ + {inputs && } +
+ ); +}; + +export const StateView = (props: { + stateData: DataType | undefined; + viewRawData: 'render' | 'raw'; +}) => { + const { stateData, viewRawData } = props; + return ( + <> + {stateData !== undefined && viewRawData === 'render' && } + {stateData !== undefined && viewRawData === 'raw' && ( + + )} + + ); +}; + +export const ResultView = (props: { + resultData: DataType | undefined; + viewRawData: 'render' | 'raw'; +}) => { + const { resultData, viewRawData } = props; + return ( + <> {resultData && viewRawData === 'render' && ( <> -

Result

)} {resultData && viewRawData === 'raw' && ( <> -

Result

)} + + ); +}; + +export const InputsView = (props: { inputs: object }) => { + const { inputs } = props; + return ( + <> {Object.keys(inputs || {}).length > 0 && ( <>

Inputs

)} -
+ ); }; -interface StringComponentProps { - name: string; - value: string; - level: number; -} -// String component is used to render string data -const StringComponent: React.FC = ({ name, value, level }) => { - const renderField = (name: string, value: string, level: number) => { - return ( -
- -
-
-          {value}
-        
-
- ); - }; - return
{renderField(name, value, level)}
; -}; +type DataType = Record; interface FormRendererProps { data: Record; } -// This component is used to render the form data in a structured way -const FormRenderer: React.FC = ({ data }) => { - const renderField = (value: string | number | boolean | object, key: string, level: number) => { - // TODO: have max level depth. - if (typeof value === 'string') { - return ; - } else if (Array.isArray(value)) { - return ( -
- -
-
- {value.map((v, i) => { - return ( -
- {renderField(v, key + '-' + i.toString(), level + 1)} -
- ); - })} +const Header = (props: { + name: string; + isExpanded: boolean; + setExpanded: (expanded: boolean) => void; +}) => { + const MinimizeMaximizeIcon = props.isExpanded ? ChevronUpIcon : ChevronDownIcon; + + return ( +
+

{props.name}

+
+ ); +}; +const RenderedField = (props: { + value: string | number | boolean | object; + keyName: string; + level: number; +}) => { + const [isExpanded, setExpanded] = useState(true); + // TODO: have max level depth. + const { value, keyName: key, level } = props; + const bodyClassNames = + 'border-gray-100 border-l-[8px] pl-1 hover:bg-gray-100 text-sm text-gray-700'; + if (key.startsWith('__')) { + return null; + } + return ( + <> +
+ {isExpanded && + (typeof value === 'string' ? ( +
+
+              {value}
+            
-
- ); - } else if (typeof value === 'object') { - return ( -
- -
-
- {value === null ? ( - NULL - ) : ( - Object.entries(value).map(([k, v]) => { + ) : Array.isArray(value) ? ( +
+
+ {value.map((v, i) => { return ( -
- {renderField(v, k, level + 1)} +
+
); - }) - )} + })} +
-
- ); - } else if (value === null) { -
- -
- NULL -
; - } else { - return ( -
- -
- {value.toString()} -
- ); - } - }; - - const renderFields = () => { - if (data !== null) { - return Object.entries(data).map(([key, value]) => renderField(value, key, 0)); - } - return null; - }; + ) : typeof value === 'object' ? ( +
+
+ {value === null ? ( + NULL + ) : ( + Object.entries(value).map(([k, v]) => { + return ( +
+ +
+ ); + }) + )} +
+
+ ) : value === null ? ( +
+
NULL
+
+ ) : ( +
+
{value.toString()}
+
+ ))} + + ); +}; - return
{renderFields()}
; +// This component is used to render the form data in a structured way +const FormRenderer: React.FC = ({ data }) => { + if (data !== null) { + return ( + <> + {Object.entries(data).map(([key, value]) => { + return ; + })} + + ); + } + return null; }; export default FormRenderer; diff --git a/telemetry/ui/src/components/routes/app/StateMachine.tsx b/telemetry/ui/src/components/routes/app/StateMachine.tsx index b2b6901e..c9e44472 100644 --- a/telemetry/ui/src/components/routes/app/StateMachine.tsx +++ b/telemetry/ui/src/components/routes/app/StateMachine.tsx @@ -31,7 +31,7 @@ export const AppStateView = (props: { return ( <> -
+
{currentTab === 'graph' && (