mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-04-20 00:10:03 +02:00
updates MethodComponent
Keyword arguments have a default value now which is displayed in the frontend. The following types can be rendered now: - numbers (ints, floats, quantities) - enums (including coloured enums) I still have to fix the `convert_argument_to_hinted_types` method to make Quantity and Enums work.
This commit is contained in:
parent
22fd2d099d
commit
883ec6d6ae
@ -1,11 +1,13 @@
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import { WebSettingsContext } from '../WebSettings';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { runMethod } from '../socket';
|
||||
import { Button, InputGroup, Form, Collapse } from 'react-bootstrap';
|
||||
import { Button, Form, Card } from 'react-bootstrap';
|
||||
import { DocStringComponent } from './DocStringComponent';
|
||||
import { getIdFromFullAccessPath } from '../utils/stringUtils';
|
||||
import { LevelName } from './NotificationsComponent';
|
||||
import { GenericComponent, SerializedValue } from './GenericComponent';
|
||||
import { SerializedValue } from './GenericComponent';
|
||||
import { FloatObject, NumberComponent, QuantityObject } from './NumberComponent';
|
||||
import { StringComponent } from './StringComponent';
|
||||
import { ColouredEnumComponent } from './ColouredEnumComponent';
|
||||
import { EnumComponent } from './EnumComponent';
|
||||
|
||||
type MethodProps = {
|
||||
name: string;
|
||||
@ -14,36 +16,23 @@ type MethodProps = {
|
||||
docString?: string;
|
||||
hideOutput?: boolean;
|
||||
addNotification: (message: string, levelname?: LevelName) => void;
|
||||
displayName: string;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const MethodComponent = React.memo((props: MethodProps) => {
|
||||
const { name, parentPath, docString, addNotification } = props;
|
||||
const { name, parentPath, docString, addNotification, displayName, id } = props;
|
||||
|
||||
const renderCount = useRef(0);
|
||||
const [hideOutput, setHideOutput] = useState(false);
|
||||
// Add a new state variable to hold the list of function calls
|
||||
const [functionCalls, setFunctionCalls] = useState([]);
|
||||
const fullAccessPath = [parentPath, name].filter((element) => element).join('.');
|
||||
const id = getIdFromFullAccessPath(fullAccessPath);
|
||||
const webSettings = useContext(WebSettingsContext);
|
||||
let displayName = name;
|
||||
|
||||
if (webSettings[fullAccessPath] && webSettings[fullAccessPath].displayName) {
|
||||
displayName = webSettings[fullAccessPath].displayName;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
renderCount.current++;
|
||||
if (props.hideOutput !== undefined) {
|
||||
setHideOutput(props.hideOutput);
|
||||
}
|
||||
});
|
||||
|
||||
const triggerNotification = (args: Record<string, string>) => {
|
||||
const argsString = Object.entries(args)
|
||||
.map(([key, value]) => `${key}: "${value}"`)
|
||||
.join(', ');
|
||||
let message = `Method ${parentPath}.${name} was triggered`;
|
||||
let message = `Method ${fullAccessPath} was triggered`;
|
||||
|
||||
if (argsString === '') {
|
||||
message += '.';
|
||||
@ -55,11 +44,10 @@ export const MethodComponent = React.memo((props: MethodProps) => {
|
||||
|
||||
const execute = async (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
const kwargs = {};
|
||||
Object.keys(props.parameters).forEach(
|
||||
(name) => (kwargs[name] = event.target[name].value)
|
||||
);
|
||||
Object.keys(props.parameters).forEach((name) => {
|
||||
kwargs[name] = event.target[name].value;
|
||||
});
|
||||
runMethod(name, parentPath, kwargs, (ack) => {
|
||||
// Update the functionCalls state with the new call if we get an acknowledge msg
|
||||
if (ack !== undefined) {
|
||||
@ -73,14 +61,109 @@ export const MethodComponent = React.memo((props: MethodProps) => {
|
||||
triggerNotification(kwargs);
|
||||
};
|
||||
|
||||
const args = Object.entries(props.parameters).map(([name, type], index) => {
|
||||
const form_name = `${name} (${type})`;
|
||||
return (
|
||||
<InputGroup key={index}>
|
||||
<InputGroup.Text className="component-label">{form_name}</InputGroup.Text>
|
||||
<Form.Control type="text" name={name} />
|
||||
</InputGroup>
|
||||
);
|
||||
const args = Object.entries(props.parameters).map(([name, serializedValue]) => {
|
||||
if (serializedValue.type == 'float' || serializedValue.type == 'int') {
|
||||
return (
|
||||
<NumberComponent
|
||||
name={name}
|
||||
value={(serializedValue as FloatObject).value}
|
||||
displayName={name}
|
||||
type={serializedValue.type}
|
||||
readOnly={false}
|
||||
docString={undefined}
|
||||
isInstantUpdate={false}
|
||||
addNotification={() => {}}
|
||||
id={id + '.' + name}
|
||||
/>
|
||||
);
|
||||
} else if (serializedValue.type == 'Quantity') {
|
||||
return (
|
||||
<NumberComponent
|
||||
name={name}
|
||||
value={(serializedValue as QuantityObject).value.magnitude}
|
||||
displayName={name}
|
||||
unit={(serializedValue as QuantityObject).value.unit}
|
||||
type="float"
|
||||
readOnly={false}
|
||||
docString={undefined}
|
||||
isInstantUpdate={false}
|
||||
addNotification={() => {}}
|
||||
id={id + '.' + name}
|
||||
/>
|
||||
);
|
||||
} else if (serializedValue.type == 'str') {
|
||||
return (
|
||||
<StringComponent
|
||||
name={name}
|
||||
value={serializedValue.value as string}
|
||||
displayName={name}
|
||||
readOnly={false}
|
||||
docString={undefined}
|
||||
isInstantUpdate={false}
|
||||
addNotification={() => {}}
|
||||
id={id + '.' + name}
|
||||
/>
|
||||
);
|
||||
} else if (serializedValue.type == 'Enum') {
|
||||
return (
|
||||
<EnumComponent
|
||||
name={name}
|
||||
parentPath={parentPath}
|
||||
value={serializedValue.value as string}
|
||||
readOnly={false}
|
||||
docString={undefined}
|
||||
addNotification={() => {}}
|
||||
enumDict={serializedValue.enum}
|
||||
displayName={name}
|
||||
id={id + '.' + name}
|
||||
/>
|
||||
);
|
||||
} else if (serializedValue.type == 'ColouredEnum') {
|
||||
return (
|
||||
<ColouredEnumComponent
|
||||
name={name}
|
||||
parentPath={parentPath}
|
||||
value={serializedValue.value as string}
|
||||
readOnly={false}
|
||||
docString={undefined}
|
||||
addNotification={() => {}}
|
||||
enumDict={serializedValue.enum}
|
||||
displayName={name}
|
||||
id={id + '.' + name}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Content conditionally rendered based on args
|
||||
const formContent = (
|
||||
<Form onSubmit={execute}>
|
||||
{args}
|
||||
<Button className="component" variant="primary" type="submit">
|
||||
{`${displayName} `}
|
||||
<DocStringComponent docString={docString} />
|
||||
</Button>
|
||||
</Form>
|
||||
);
|
||||
|
||||
const outputContent = (
|
||||
<div id="function-output">
|
||||
{functionCalls.map((call, index) => (
|
||||
<div key={index}>
|
||||
<div style={{ color: 'grey', fontSize: 'small' }}>
|
||||
{Object.entries(call.args)
|
||||
.map(([key, val]) => `${key}=${JSON.stringify(val)}`)
|
||||
.join(', ') +
|
||||
' => ' +
|
||||
JSON.stringify(call.result)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
renderCount.current++;
|
||||
});
|
||||
|
||||
return (
|
||||
@ -88,32 +171,16 @@ export const MethodComponent = React.memo((props: MethodProps) => {
|
||||
{process.env.NODE_ENV === 'development' && (
|
||||
<div>Render count: {renderCount.current}</div>
|
||||
)}
|
||||
<h5 onClick={() => setHideOutput(!hideOutput)} style={{ cursor: 'pointer' }}>
|
||||
Function: {displayName}
|
||||
</h5>
|
||||
<Form onSubmit={execute}>
|
||||
{args}
|
||||
<Button variant="primary" type="submit">
|
||||
Execute
|
||||
<DocStringComponent docString={docString} />
|
||||
</Button>
|
||||
</Form>
|
||||
|
||||
<Collapse in={!hideOutput}>
|
||||
<div id="function-output">
|
||||
{functionCalls.map((call, index) => (
|
||||
<div key={index}>
|
||||
<div style={{ color: 'grey', fontSize: 'small' }}>
|
||||
{Object.entries(call.args)
|
||||
.map(([key, val]) => `${key}=${JSON.stringify(val)}`)
|
||||
.join(', ') +
|
||||
' => ' +
|
||||
JSON.stringify(call.result)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Collapse>
|
||||
{args.length > 0 ? (
|
||||
<Card>
|
||||
<Card.Body>
|
||||
{formContent}
|
||||
{outputContent}
|
||||
</Card.Body>
|
||||
</Card>
|
||||
) : (
|
||||
<div>{formContent}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user