diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ff91022..0c4aa85 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,14 +1,90 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; +import { Component, ComponentLabel } from './components/component'; +import { ButtonComponent } from './components/button'; +import { socket } from './socket'; -// A simple functional component -const App: React.FC = () => { +type AttributeType = 'str' | 'bool' | 'float' | 'int' | 'method' | 'Subclass'; + +interface Attribute { + type: AttributeType; + value?: any; + readonly: boolean; + doc?: string | null; + parameters?: Record; + async?: boolean; +} + +type MyData = Record; + +const App = () => { + const [data, setData] = useState(null); + const [isConnected, setIsConnected] = useState(socket.connected); + + useEffect(() => { + // Fetch data from the API when the component mounts + fetch('http://localhost:8001/service-properties') + .then((response) => response.json()) + .then(setData); + function onConnect() { + setIsConnected(true); + } + + function onDisconnect() { + setIsConnected(false); + } + + function onNotify(value: Record) { + console.log(value); + } + + socket.on('connect', onConnect); + socket.on('disconnect', onDisconnect); + socket.on('notify', onNotify); + + return () => { + socket.off('connect', onConnect); + socket.off('disconnect', onDisconnect); + socket.off('notify', onNotify); + }; + }, []); + + // While the data is loading + if (!data) { + return

Loading...

; + } return ( -
-

Hello, world!

-

Welcome to my React application. This is some test.

+
+ {Object.entries(data).map(([key, value]) => { + if (value.type === 'bool') { + return ( +
+ +
+ ); + } else if (!value.async) { + return ( +
+ + +
+ ); + } else { + return
; + } + })}
); }; - -export default App; \ No newline at end of file +export default App; diff --git a/frontend/src/components/button.tsx b/frontend/src/components/button.tsx new file mode 100644 index 0000000..ecdf8a1 --- /dev/null +++ b/frontend/src/components/button.tsx @@ -0,0 +1,44 @@ +import React, { MouseEventHandler } from 'react'; +import { OverlayTrigger, Badge, Button, Tooltip } from 'react-bootstrap'; + +interface ButtonComponentProps { + name: string; + fullname?: string; + value: boolean; + readOnly: boolean; + docString: string; + onToggle?: MouseEventHandler; + mapping?: [string, string]; // Enforce a tuple of two strings +} + +const ButtonComponentRef = React.forwardRef( + (props, ref) => { + const { name, fullname, value, readOnly, docString, onToggle, mapping } = props; + + const buttonName = mapping ? (value ? mapping[0] : mapping[1]) : name; + + const tooltip = {docString}; + + return ( +
+ + + {docString && ( + + + ? + + + )} +
+ ); + } +); + +export const ButtonComponent = React.memo(ButtonComponentRef); diff --git a/frontend/src/components/component.tsx b/frontend/src/components/component.tsx new file mode 100644 index 0000000..e6214f1 --- /dev/null +++ b/frontend/src/components/component.tsx @@ -0,0 +1,65 @@ +import React from 'react'; + +interface ComponentProps { + name: string; + value: any; + readOnly: boolean; + type: string; + docString: string; +} + +export const ComponentLabel = ({ + name, + docString +}: { + name: string; + docString: string; +}) => { + return ; +}; + +export const Component = ({ + name, + value, + readOnly, + type, + docString +}: ComponentProps) => { + switch (type) { + case 'int': + case 'float': + return ( + + ); + case 'str': + return ( + + ); + case 'bool': + return ( + + ); + case 'method': + return

Method: {name}

; + default: + return

Unsupported type: {type}

; + } +};