mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-04-20 00:10:03 +02:00
only methods without arguments can be rendered
This commit is contained in:
parent
b6f6b3058e
commit
2337aa9d6d
@ -1,19 +1,19 @@
|
|||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { runMethod } from '../socket';
|
import { runMethod } from '../socket';
|
||||||
import { InputGroup, Form, Button } from 'react-bootstrap';
|
import { Form, Button, InputGroup } from 'react-bootstrap';
|
||||||
import { DocStringComponent } from './DocStringComponent';
|
import { DocStringComponent } from './DocStringComponent';
|
||||||
import { LevelName } from './NotificationsComponent';
|
import { LevelName } from './NotificationsComponent';
|
||||||
|
|
||||||
type AsyncMethodProps = {
|
type AsyncMethodProps = {
|
||||||
name: string;
|
name: string;
|
||||||
parentPath: string;
|
parentPath: string;
|
||||||
parameters: Record<string, string>;
|
|
||||||
value: Record<string, string>;
|
value: Record<string, string>;
|
||||||
docString?: string;
|
docString?: string;
|
||||||
hideOutput?: boolean;
|
hideOutput?: boolean;
|
||||||
addNotification: (message: string, levelname?: LevelName) => void;
|
addNotification: (message: string, levelname?: LevelName) => void;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
render: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AsyncMethodComponent = React.memo((props: AsyncMethodProps) => {
|
export const AsyncMethodComponent = React.memo((props: AsyncMethodProps) => {
|
||||||
@ -26,6 +26,12 @@ export const AsyncMethodComponent = React.memo((props: AsyncMethodProps) => {
|
|||||||
displayName,
|
displayName,
|
||||||
id
|
id
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
// Conditional rendering based on the 'render' prop.
|
||||||
|
if (!props.render) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const renderCount = useRef(0);
|
const renderCount = useRef(0);
|
||||||
const formRef = useRef(null);
|
const formRef = useRef(null);
|
||||||
const fullAccessPath = [parentPath, name].filter((element) => element).join('.');
|
const fullAccessPath = [parentPath, name].filter((element) => element).join('.');
|
||||||
@ -66,50 +72,31 @@ export const AsyncMethodComponent = React.memo((props: AsyncMethodProps) => {
|
|||||||
const execute = async (event: React.FormEvent) => {
|
const execute = async (event: React.FormEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let method_name: string;
|
let method_name: string;
|
||||||
const kwargs: Record<string, unknown> = {};
|
|
||||||
|
|
||||||
if (runningTask !== undefined && runningTask !== null) {
|
if (runningTask !== undefined && runningTask !== null) {
|
||||||
method_name = `stop_${name}`;
|
method_name = `stop_${name}`;
|
||||||
} else {
|
} else {
|
||||||
Object.keys(props.parameters).forEach(
|
|
||||||
(name) => (kwargs[name] = event.target[name].value)
|
|
||||||
);
|
|
||||||
method_name = `start_${name}`;
|
method_name = `start_${name}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
runMethod(method_name, parentPath, kwargs);
|
runMethod(method_name, parentPath, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
const args = Object.entries(props.parameters).map(([name, type], index) => {
|
|
||||||
const form_name = `${name} (${type})`;
|
|
||||||
const value = runningTask && runningTask[name];
|
|
||||||
const isRunning = value !== undefined && value !== null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<InputGroup key={index}>
|
|
||||||
<InputGroup.Text className="component-label">{form_name}</InputGroup.Text>
|
|
||||||
<Form.Control
|
|
||||||
type="text"
|
|
||||||
name={name}
|
|
||||||
defaultValue={isRunning ? value : ''}
|
|
||||||
disabled={isRunning}
|
|
||||||
/>
|
|
||||||
</InputGroup>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="component asyncMethodComponent" id={id}>
|
<div className="component asyncMethodComponent" id={id}>
|
||||||
{process.env.NODE_ENV === 'development' && (
|
{process.env.NODE_ENV === 'development' && (
|
||||||
<div>Render count: {renderCount.current}</div>
|
<div>Render count: {renderCount.current}</div>
|
||||||
)}
|
)}
|
||||||
<h5>Function: {displayName}</h5>
|
|
||||||
<Form onSubmit={execute} ref={formRef}>
|
<Form onSubmit={execute} ref={formRef}>
|
||||||
{args}
|
<InputGroup>
|
||||||
<Button id={`button-${id}`} type="submit">
|
<InputGroup.Text>
|
||||||
{runningTask ? 'Stop ' : 'Start '}
|
{displayName}
|
||||||
<DocStringComponent docString={docString} />
|
<DocStringComponent docString={docString} />
|
||||||
</Button>
|
</InputGroup.Text>
|
||||||
|
<Button id={`button-${id}`} type="submit">
|
||||||
|
{runningTask ? 'Stop ' : 'Start '}
|
||||||
|
</Button>
|
||||||
|
</InputGroup>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,144 +1,46 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { runMethod } from '../socket';
|
import { runMethod } from '../socket';
|
||||||
import { Button, Form, Card } from 'react-bootstrap';
|
import { Button, Form } from 'react-bootstrap';
|
||||||
import { DocStringComponent } from './DocStringComponent';
|
import { DocStringComponent } from './DocStringComponent';
|
||||||
import { LevelName } from './NotificationsComponent';
|
import { LevelName } from './NotificationsComponent';
|
||||||
import { SerializedValue } from './GenericComponent';
|
|
||||||
import { FloatObject, NumberComponent, QuantityObject } from './NumberComponent';
|
|
||||||
import { StringComponent } from './StringComponent';
|
|
||||||
import { ColouredEnumComponent } from './ColouredEnumComponent';
|
|
||||||
import { EnumComponent } from './EnumComponent';
|
|
||||||
|
|
||||||
type MethodProps = {
|
type MethodProps = {
|
||||||
name: string;
|
name: string;
|
||||||
parentPath: string;
|
parentPath: string;
|
||||||
parameters: Record<string, SerializedValue>;
|
|
||||||
docString?: string;
|
docString?: string;
|
||||||
hideOutput?: boolean;
|
|
||||||
addNotification: (message: string, levelname?: LevelName) => void;
|
addNotification: (message: string, levelname?: LevelName) => void;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
render: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MethodComponent = React.memo((props: MethodProps) => {
|
export const MethodComponent = React.memo((props: MethodProps) => {
|
||||||
const { name, parentPath, docString, addNotification, displayName, id } = props;
|
const { name, parentPath, docString, addNotification, displayName, id } = props;
|
||||||
|
|
||||||
|
// Conditional rendering based on the 'render' prop.
|
||||||
|
if (!props.render) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const renderCount = useRef(0);
|
const renderCount = useRef(0);
|
||||||
// Add a new state variable to hold the list of function calls
|
const formRef = useRef(null);
|
||||||
const [functionCalls, setFunctionCalls] = useState([]);
|
|
||||||
const fullAccessPath = [parentPath, name].filter((element) => element).join('.');
|
const fullAccessPath = [parentPath, name].filter((element) => element).join('.');
|
||||||
|
|
||||||
const triggerNotification = (args: Record<string, string>) => {
|
const triggerNotification = () => {
|
||||||
const argsString = Object.entries(args)
|
const message = `Method ${fullAccessPath} was triggered.`;
|
||||||
.map(([key, value]) => `${key}: "${value}"`)
|
|
||||||
.join(', ');
|
|
||||||
let message = `Method ${fullAccessPath} was triggered`;
|
|
||||||
|
|
||||||
if (argsString === '') {
|
|
||||||
message += '.';
|
|
||||||
} else {
|
|
||||||
message += ` with arguments {${argsString}}.`;
|
|
||||||
}
|
|
||||||
addNotification(message);
|
addNotification(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
const execute = async (event: React.FormEvent) => {
|
const execute = async (event: React.FormEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const kwargs = {};
|
runMethod(name, parentPath, {});
|
||||||
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) {
|
|
||||||
setFunctionCalls((prevCalls) => [
|
|
||||||
...prevCalls,
|
|
||||||
{ name, args: kwargs, result: ack }
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
triggerNotification(kwargs);
|
triggerNotification();
|
||||||
};
|
};
|
||||||
|
|
||||||
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 = (
|
const formContent = (
|
||||||
<Form onSubmit={execute}>
|
<Form onSubmit={execute} ref={formRef}>
|
||||||
{args}
|
|
||||||
<Button className="component" variant="primary" type="submit">
|
<Button className="component" variant="primary" type="submit">
|
||||||
{`${displayName} `}
|
{`${displayName} `}
|
||||||
<DocStringComponent docString={docString} />
|
<DocStringComponent docString={docString} />
|
||||||
@ -146,22 +48,6 @@ export const MethodComponent = React.memo((props: MethodProps) => {
|
|||||||
</Form>
|
</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(() => {
|
useEffect(() => {
|
||||||
renderCount.current++;
|
renderCount.current++;
|
||||||
});
|
});
|
||||||
@ -171,16 +57,7 @@ export const MethodComponent = React.memo((props: MethodProps) => {
|
|||||||
{process.env.NODE_ENV === 'development' && (
|
{process.env.NODE_ENV === 'development' && (
|
||||||
<div>Render count: {renderCount.current}</div>
|
<div>Render count: {renderCount.current}</div>
|
||||||
)}
|
)}
|
||||||
{args.length > 0 ? (
|
<div>{formContent}</div>
|
||||||
<Card>
|
|
||||||
<Card.Body>
|
|
||||||
{formContent}
|
|
||||||
{outputContent}
|
|
||||||
</Card.Body>
|
|
||||||
</Card>
|
|
||||||
) : (
|
|
||||||
<div>{formContent}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user