mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-06-05 13:10:41 +02:00
frontend: adding DataServiceComponent. Rendering nested classes is now possible.
This commit is contained in:
parent
ca794948d0
commit
3116d98f1c
@ -1,37 +1,15 @@
|
|||||||
import { useEffect, useReducer } from 'react';
|
import { useEffect, useReducer } from 'react';
|
||||||
import { ButtonComponent } from './components/ButtonComponent';
|
|
||||||
import { NumberComponent } from './components/NumberComponent';
|
|
||||||
import { SliderComponent } from './components/SliderComponent';
|
|
||||||
import { EnumComponent } from './components/EnumComponent';
|
|
||||||
import { socket } from './socket';
|
import { socket } from './socket';
|
||||||
import { MethodComponent } from './components/MethodComponent';
|
import {
|
||||||
import { AsyncMethodComponent } from './components/AsyncMethodComponent';
|
DataServiceComponent,
|
||||||
|
DataServiceJSON
|
||||||
type AttributeType =
|
} from './components/DataServiceComponent';
|
||||||
| 'str'
|
|
||||||
| 'bool'
|
|
||||||
| 'float'
|
|
||||||
| 'int'
|
|
||||||
| 'method'
|
|
||||||
| 'DataService'
|
|
||||||
| 'Enum'
|
|
||||||
| 'NumberSlider';
|
|
||||||
|
|
||||||
type ValueType = boolean | string | number | object;
|
type ValueType = boolean | string | number | object;
|
||||||
interface Attribute {
|
|
||||||
type: AttributeType;
|
|
||||||
value?: ValueType;
|
|
||||||
readonly: boolean;
|
|
||||||
doc?: string | null;
|
|
||||||
parameters?: Record<string, string>;
|
|
||||||
async?: boolean;
|
|
||||||
enum?: Record<string, string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
type MyData = Record<string, Attribute>;
|
type State = DataServiceJSON | null;
|
||||||
type State = MyData | null;
|
|
||||||
type Action =
|
type Action =
|
||||||
| { type: 'SET_DATA'; data: MyData }
|
| { type: 'SET_DATA'; data: DataServiceJSON }
|
||||||
| { type: 'UPDATE_ATTRIBUTE'; parent_path: string; name: string; value: ValueType };
|
| { type: 'UPDATE_ATTRIBUTE'; parent_path: string; name: string; value: ValueType };
|
||||||
type NotificationElement = {
|
type NotificationElement = {
|
||||||
data: { parent_path: string; name: string; value: object };
|
data: { parent_path: string; name: string; value: object };
|
||||||
@ -96,7 +74,7 @@ const App = () => {
|
|||||||
// Fetch data from the API when the component mounts
|
// Fetch data from the API when the component mounts
|
||||||
fetch('http://localhost:8001/service-properties')
|
fetch('http://localhost:8001/service-properties')
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data: MyData) => dispatch({ type: 'SET_DATA', data }));
|
.then((data: DataServiceJSON) => dispatch({ type: 'SET_DATA', data }));
|
||||||
|
|
||||||
function onNotify(value: NotificationElement) {
|
function onNotify(value: NotificationElement) {
|
||||||
dispatch({
|
dispatch({
|
||||||
@ -120,88 +98,7 @@ const App = () => {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
{Object.entries(state).map(([key, value]) => {
|
<DataServiceComponent props={state as DataServiceJSON} />
|
||||||
if (value.type === 'bool') {
|
|
||||||
return (
|
|
||||||
<div key={key}>
|
|
||||||
<ButtonComponent
|
|
||||||
name={key}
|
|
||||||
parent_path="DataService"
|
|
||||||
docString={value.doc}
|
|
||||||
readOnly={value.readonly}
|
|
||||||
value={Boolean(value.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (value.type === 'float' || value.type === 'int') {
|
|
||||||
return (
|
|
||||||
<div key={key}>
|
|
||||||
<NumberComponent
|
|
||||||
name={key}
|
|
||||||
type={value.type}
|
|
||||||
parent_path="DataService"
|
|
||||||
docString={value.doc}
|
|
||||||
readOnly={value.readonly}
|
|
||||||
value={Number(value.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (value.type === 'NumberSlider') {
|
|
||||||
return (
|
|
||||||
<div key={key}>
|
|
||||||
<SliderComponent
|
|
||||||
name={key}
|
|
||||||
parent_path="DataService"
|
|
||||||
docString={value.doc}
|
|
||||||
readOnly={value.readonly}
|
|
||||||
value={value.value['value']['value']}
|
|
||||||
min={value.value['min']['value']}
|
|
||||||
max={value.value['max']['value']}
|
|
||||||
stepSize={value.value['step_size']['value']}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (value.type === 'Enum') {
|
|
||||||
return (
|
|
||||||
<div key={key}>
|
|
||||||
<EnumComponent
|
|
||||||
name={key}
|
|
||||||
parent_path="DataService"
|
|
||||||
docString={value.doc}
|
|
||||||
value={String(value.value)}
|
|
||||||
enumDict={value.enum}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (value.type === 'method') {
|
|
||||||
if (!value.async) {
|
|
||||||
return (
|
|
||||||
<div key={key}>
|
|
||||||
<MethodComponent
|
|
||||||
name={key}
|
|
||||||
parent_path="DataService"
|
|
||||||
docString={value.doc}
|
|
||||||
parameters={value.parameters}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<div key={key}>
|
|
||||||
<AsyncMethodComponent
|
|
||||||
name={key}
|
|
||||||
parent_path="DataService"
|
|
||||||
docString={value.doc}
|
|
||||||
parameters={value.parameters}
|
|
||||||
value={value.value as Record<string, string>}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return <div key={key}></div>;
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
153
frontend/src/components/DataServiceComponent.tsx
Normal file
153
frontend/src/components/DataServiceComponent.tsx
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { ButtonComponent } from './ButtonComponent';
|
||||||
|
import { NumberComponent } from './NumberComponent';
|
||||||
|
import { SliderComponent } from './SliderComponent';
|
||||||
|
import { EnumComponent } from './EnumComponent';
|
||||||
|
import { MethodComponent } from './MethodComponent';
|
||||||
|
import { AsyncMethodComponent } from './AsyncMethodComponent';
|
||||||
|
import React from 'react';
|
||||||
|
import { Card, Collapse } from 'react-bootstrap';
|
||||||
|
import { ChevronDown, ChevronRight } from 'react-bootstrap-icons';
|
||||||
|
|
||||||
|
type AttributeType =
|
||||||
|
| 'str'
|
||||||
|
| 'bool'
|
||||||
|
| 'float'
|
||||||
|
| 'int'
|
||||||
|
| 'method'
|
||||||
|
| 'DataService'
|
||||||
|
| 'Enum'
|
||||||
|
| 'NumberSlider';
|
||||||
|
|
||||||
|
type ValueType = boolean | string | number | object;
|
||||||
|
interface Attribute {
|
||||||
|
type: AttributeType;
|
||||||
|
value?: ValueType;
|
||||||
|
readonly: boolean;
|
||||||
|
doc?: string | null;
|
||||||
|
parameters?: Record<string, string>;
|
||||||
|
async?: boolean;
|
||||||
|
enum?: Record<string, string>;
|
||||||
|
}
|
||||||
|
type DataServiceProps = {
|
||||||
|
props: DataServiceJSON;
|
||||||
|
parentPath?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DataServiceJSON = Record<string, Attribute>;
|
||||||
|
|
||||||
|
export const DataServiceComponent = React.memo(
|
||||||
|
({ props, parentPath = 'DataService' }: DataServiceProps) => {
|
||||||
|
const [open, setOpen] = useState(true);
|
||||||
|
// useEffect(() => {}, []);
|
||||||
|
|
||||||
|
// While the data is loading
|
||||||
|
return (
|
||||||
|
<div className="App">
|
||||||
|
<Card className="mb-3">
|
||||||
|
<Card.Header
|
||||||
|
onClick={() => setOpen(!open)}
|
||||||
|
style={{ cursor: 'pointer' }} // Change cursor style on hover
|
||||||
|
>
|
||||||
|
{parentPath} {open ? <ChevronDown /> : <ChevronRight />}
|
||||||
|
</Card.Header>
|
||||||
|
<Collapse in={open}>
|
||||||
|
<Card.Body>
|
||||||
|
{Object.entries(props).map(([key, value]) => {
|
||||||
|
if (value.type === 'bool') {
|
||||||
|
return (
|
||||||
|
<div key={key}>
|
||||||
|
<ButtonComponent
|
||||||
|
name={key}
|
||||||
|
parent_path={parentPath}
|
||||||
|
docString={value.doc}
|
||||||
|
readOnly={value.readonly}
|
||||||
|
value={Boolean(value.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (value.type === 'float' || value.type === 'int') {
|
||||||
|
return (
|
||||||
|
<div key={key}>
|
||||||
|
<NumberComponent
|
||||||
|
name={key}
|
||||||
|
type={value.type}
|
||||||
|
parent_path={parentPath}
|
||||||
|
docString={value.doc}
|
||||||
|
readOnly={value.readonly}
|
||||||
|
value={Number(value.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (value.type === 'NumberSlider') {
|
||||||
|
return (
|
||||||
|
<div key={key}>
|
||||||
|
<SliderComponent
|
||||||
|
name={key}
|
||||||
|
parent_path={parentPath}
|
||||||
|
docString={value.doc}
|
||||||
|
readOnly={value.readonly}
|
||||||
|
value={value.value['value']['value']}
|
||||||
|
min={value.value['min']['value']}
|
||||||
|
max={value.value['max']['value']}
|
||||||
|
stepSize={value.value['step_size']['value']}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (value.type === 'Enum') {
|
||||||
|
return (
|
||||||
|
<div key={key}>
|
||||||
|
<EnumComponent
|
||||||
|
name={key}
|
||||||
|
parent_path={parentPath}
|
||||||
|
docString={value.doc}
|
||||||
|
value={String(value.value)}
|
||||||
|
enumDict={value.enum}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (value.type === 'method') {
|
||||||
|
if (!value.async) {
|
||||||
|
return (
|
||||||
|
<div key={key}>
|
||||||
|
<MethodComponent
|
||||||
|
name={key}
|
||||||
|
parent_path={parentPath}
|
||||||
|
docString={value.doc}
|
||||||
|
parameters={value.parameters}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div key={key}>
|
||||||
|
<AsyncMethodComponent
|
||||||
|
name={key}
|
||||||
|
parent_path={parentPath}
|
||||||
|
docString={value.doc}
|
||||||
|
parameters={value.parameters}
|
||||||
|
value={value.value as Record<string, string>}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (value.type === 'DataService') {
|
||||||
|
return (
|
||||||
|
<div key={key}>
|
||||||
|
<DataServiceComponent
|
||||||
|
props={value.value as DataServiceJSON}
|
||||||
|
parentPath={parentPath.concat('.', key)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <div key={key}></div>;
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</Card.Body>
|
||||||
|
</Collapse>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
Loading…
x
Reference in New Issue
Block a user