diff --git a/telemetry/ui/src/components/routes/app/ActionView.tsx b/telemetry/ui/src/components/routes/app/ActionView.tsx index f2912751..7180f6c5 100644 --- a/telemetry/ui/src/components/routes/app/ActionView.tsx +++ b/telemetry/ui/src/components/routes/app/ActionView.tsx @@ -11,13 +11,14 @@ import { base16AteliersulphurpoolLight } from 'react-syntax-highlighter/dist/esm */ export const CodeView = (props: { code: string }) => { return ( -
+
+ style={base16AteliersulphurpoolLight} + > {props.code}
diff --git a/telemetry/ui/src/components/routes/app/DataView.tsx b/telemetry/ui/src/components/routes/app/DataView.tsx index 3ca43c99..0144a6a0 100644 --- a/telemetry/ui/src/components/routes/app/DataView.tsx +++ b/telemetry/ui/src/components/routes/app/DataView.tsx @@ -1,7 +1,11 @@ +import React, { useState } from 'react'; import { Step } from '../../../api'; import JsonView from '@uiw/react-json-view'; import { Button } from '../../common/button'; -import { useState } from 'react'; +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,21 +17,37 @@ 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 && (
- {stateData !== undefined && ( - - )} + {error && ( <>

Error

)} - {resultData && ( + {resultData && Object.keys(resultData).length > 0 && ( <> -

Result

- +

Result

+ + + )} + {inputs && Object.keys(inputs).length > 0 && ( + <> +

Input

+ + + )} +
+ ); +}; + +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' && ( + <> + )} - {Object.keys(inputs || {}).length > 0 && ( + {resultData && viewRawData === 'raw' && ( <> -

Inputs

- + )} + + ); +}; + +export const InputsView = (props: { inputs: object }) => { + const { inputs } = props; + return ; +}; + +type DataType = Record; + +interface FormRendererProps { + data: Record; +} + +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}
+            
+
+ ) : Array.isArray(value) ? ( +
+
+ {value.map((v, i) => { + return ( +
+ +
+ ); + })} +
+
+ ) : typeof value === 'object' ? ( +
+
+ {value === null ? ( + NULL + ) : ( + Object.entries(value).map(([k, v]) => { + return ( +
+ +
+ ); + }) + )} +
+
+ ) : value === null ? ( +
+
NULL
+
+ ) : ( +
+
{value.toString()}
+
+ ))} + + ); +}; + +// 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..25745c23 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' && (