mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-04-20 00:10:03 +02:00
116 lines
3.7 KiB
TypeScript
116 lines
3.7 KiB
TypeScript
import React, { useContext, useEffect, useRef } from 'react';
|
|
import { runMethod } from '../socket';
|
|
import { InputGroup, Form, Button } from 'react-bootstrap';
|
|
import { DocStringComponent } from './DocStringComponent';
|
|
import { getIdFromFullAccessPath } from '../utils/stringUtils';
|
|
import { LevelName } from './NotificationsComponent';
|
|
import { WebSettingsContext } from '../WebSettings';
|
|
|
|
type AsyncMethodProps = {
|
|
name: string;
|
|
parentPath: string;
|
|
parameters: Record<string, string>;
|
|
value: Record<string, string>;
|
|
docString?: string;
|
|
hideOutput?: boolean;
|
|
addNotification: (message: string, levelname?: LevelName) => void;
|
|
};
|
|
|
|
export const AsyncMethodComponent = React.memo((props: AsyncMethodProps) => {
|
|
const { name, parentPath, docString, value: runningTask, addNotification } = props;
|
|
const renderCount = useRef(0);
|
|
const formRef = useRef(null);
|
|
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++;
|
|
|
|
// updates the value of each form control that has a matching name in the
|
|
// runningTask object
|
|
if (runningTask) {
|
|
const formElement = formRef.current;
|
|
if (formElement) {
|
|
Object.entries(runningTask).forEach(([name, value]) => {
|
|
const inputElement = formElement.elements.namedItem(name);
|
|
if (inputElement) {
|
|
inputElement.value = value;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}, [runningTask]);
|
|
|
|
useEffect(() => {
|
|
let message: string;
|
|
|
|
if (runningTask === null) {
|
|
message = `${parentPath}.${name} task was stopped.`;
|
|
} else {
|
|
const runningTaskEntries = Object.entries(runningTask)
|
|
.map(([key, value]) => `${key}: "${value}"`)
|
|
.join(', ');
|
|
|
|
message = `${parentPath}.${name} was started with parameters { ${runningTaskEntries} }.`;
|
|
}
|
|
addNotification(message);
|
|
}, [props.value]);
|
|
|
|
const execute = async (event: React.FormEvent) => {
|
|
event.preventDefault();
|
|
let method_name: string;
|
|
const kwargs: Record<string, unknown> = {};
|
|
|
|
if (runningTask !== undefined && runningTask !== null) {
|
|
method_name = `stop_${name}`;
|
|
} else {
|
|
Object.keys(props.parameters).forEach(
|
|
(name) => (kwargs[name] = event.target[name].value)
|
|
);
|
|
method_name = `start_${name}`;
|
|
}
|
|
|
|
runMethod(method_name, parentPath, kwargs);
|
|
};
|
|
|
|
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 (
|
|
<div className="component asyncMethodComponent" id={id}>
|
|
{process.env.NODE_ENV === 'development' && (
|
|
<div>Render count: {renderCount.current}</div>
|
|
)}
|
|
<h5>Function: {displayName}</h5>
|
|
<Form onSubmit={execute} ref={formRef}>
|
|
{args}
|
|
<Button id={`button-${id}`} name={name} value={parentPath} type="submit">
|
|
{runningTask ? 'Stop ' : 'Start '}
|
|
<DocStringComponent docString={docString} />
|
|
</Button>
|
|
</Form>
|
|
</div>
|
|
);
|
|
});
|