Initial commit

This commit is contained in:
2023-10-29 20:58:28 -03:00
commit 486b77895c
19 changed files with 5187 additions and 0 deletions

3
src/App.css Normal file
View File

@@ -0,0 +1,3 @@
.demo-logo h2 {
color: antiquewhite;
}

74
src/App.jsx Normal file
View File

@@ -0,0 +1,74 @@
import { useEffect, useState } from "react";
import ConnectForm from "./pages/Login";
import { Client } from "paho-mqtt";
import UnauthPage from "./layout/UnauthPage";
import { Spin } from "antd";
import Page from "./layout/Page";
import Spectrum from "./pages/Spectrum";
const App = () => {
const [client, setClient] = useState(null);
const [connected, setConnected] = useState(false);
const [connecting, setConnecting] = useState(false);
const [alert, setAlert] = useState(null);
const onConnect = (url, options) => {
console.log(`Trying to connect to ${url}...`);
const _client = new Client(url, options.clientId);
_client.onConnectionLost = onDisconnect;
_client.connect({
onSuccess: onConnected,
onFailure: onError,
userName: options.username,
password: options.password,
cleanSession: options.clean,
timeout: options.connectTimeout,
});
console.log('Options:', options);
setClient(_client);
setConnecting(true);
};
const onConnected = () => {
console.log("Connected!");
setConnecting(false);
setConnected(true);
};
const onError = (err) => {
console.error("Failed to connect", err);
setConnecting(false);
setAlert({ type: 'error', msg: `Could not connect, error: ${err.errorMessage}` });
};
const onDisconnect = () => {
client.disconnect();
};
useEffect(() => {
if (connecting)
setAlert(null);
}, [connecting]);
if (!connected)
return (
<UnauthPage content={
<ConnectForm
connect={onConnect}
btnContent={connecting ? <Spin /> : 'Connect'}
/>
} alert={alert} />
)
return (
<Page
content={<Spectrum />} />
)
}
export default App

65
src/ConnectedPage.jsx Normal file
View File

@@ -0,0 +1,65 @@
import { useState } from 'react';
import { Client } from 'paho-mqtt';
const ConnectedPage = () => {
const StateMessages = [
"Clique no botão para conectar",
"Conectando...",
"Conectado",
"Erro na conexão",
];
const [connected, setConnected] = useState(false);
const [client, setClient] = useState(null);
const [state, setState] = useState(0)
const handleClick = () => {
const options = {
clientId: 'aaaaa',
username: 'test',
password: '31415926',
clean: true,
reconnectPeriod: 1000,
connectTimeout: 30 * 1000,
host: 'fwmari.net',
port: 8883,
};
const _client = new Client(`ws://${options.host}:${options.port}/mqtt`, options.clientId);
_client.connect({
onSuccess: () => {
console.log("Conectado");
setConnected(true);
setState(2);
},
onFailure: (err) => {
console.log(`Erro ao conectar ${err}`);
setState(3);
},
});
setClient(_client);
setState(1);
}
return (
<div>
<button onClick={handleClick}>
Conectar ao servidor MQTT
</button>
<p>Status: {StateMessages[state]}</p>
{connected && (
<div>
{/* O resto da sua página vai aqui */}
<p>Conectado ao servidor MQTT! Agora você pode ver o resto da página.</p>
</div>
)}
</div>
);
}
export default ConnectedPage;

16
src/layout/Footer.jsx Normal file
View File

@@ -0,0 +1,16 @@
import { Layout } from "antd";
const { Footer } = Layout;
const SFooter = () => {
return (
<Footer
style={{
textAlign: 'center',
}}
>
Marisa © 2023
</Footer>
);
};
export default SFooter;

70
src/layout/Page.jsx Normal file
View File

@@ -0,0 +1,70 @@
import { Alert, Layout, Menu, theme } from 'antd';
import SFooter from './Footer';
import PropTypes from 'prop-types';
const { Header, Content } = Layout;
import '../App.css'
const menus = [
{
key: 'spectrum',
label: 'Espectro',
},
{
key: 'config',
label: 'Configuração',
},
{
key: 'about',
label: 'sobre',
}
];
const Page = ({ content, alert }) => {
const {
token: { colorBgContainer },
} = theme.useToken();
return (
<Layout className="layout">
<Header
style={{
display: 'flex',
alignItems: 'center',
}}
>
<div
className="demo-logo"
style={{ margin: '0 30px' }}
>
<h2>Spectrometer</h2>
</div>
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys={['spectrum']}
items={menus}
/>
</Header>
<Content>
{alert && <Alert type={alert.type} message={alert.msg} banner />}
<div
className="site-layout-content"
style={{
padding: '16px 50px',
background: colorBgContainer,
}}
>
{content}
</div>
</Content>
<SFooter />
</Layout>
);
};
Page.propTypes = {
content: PropTypes.element.isRequired,
alert: PropTypes.object,
};
export default Page;

49
src/layout/UnauthPage.jsx Normal file
View File

@@ -0,0 +1,49 @@
import { Alert, Layout, theme } from "antd";
import PropTypes from 'prop-types';
const { Header, Content } = Layout;
import '../App.css'
import SFooter from "./Footer";
const UnauthPage = ({ content, alert }) => {
const {
token: { colorBgContainer },
} = theme.useToken();
return (
<Layout>
<Header
style={{
display: 'flex',
alignItems: 'center',
}}
>
<div
className="demo-logo"
style={{ margin: '0 30px' }}
>
<h2>Spectrometer</h2>
</div>
</Header>
<Content>
{alert && <Alert type={alert.type} message={alert.msg} banner />}
<div
className="site-layout-content"
style={{
padding: '16px 50px',
background: colorBgContainer,
}}
>
{content}
</div>
</Content>
<SFooter />
</Layout>
);
};
UnauthPage.propTypes = {
content: PropTypes.element.isRequired,
alert: PropTypes.object,
};
export default UnauthPage;

9
src/main.jsx Normal file
View File

@@ -0,0 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)

0
src/pages/Calib.jsx Normal file
View File

48
src/pages/Dashboard.jsx Normal file
View File

@@ -0,0 +1,48 @@
/**
* Main dashboard page
*/
import { useState } from "react";
const Dashboard = ({ messageHandlers, setMessageHandlers, sendMsg }) => {
const [motorStatus, setMotorStatus] = useState({});
const [encoderStatus, setEncoderStatus] = useState({});
const [ccdStatus, setCcdStatus] = useState({});
const onMessageArrived = (msg) => {
};
setMessageHandlers({
...messageHandlers,
dashboard: onMessageArrived,
});
const getMotorStatus = () => {
data = {
"type": "motor",
"command": "get_status",
};
sendMsg("/spectrometer/motor/getStatus", data);
};
const getEncoderStatus = () => {
data = {
"type": "encoder",
"command": "get_status",
};
sendMsg("/spectrometer/encoder/getStatus", data);
};
const getCcdStatus = () => {
data = {
"type": "ccd",
"command": "get_status",
};
sendMsg("/spectrometer/ccd/getStatus", data);
};
};
export default Dashboard;

103
src/pages/Login.jsx Normal file
View File

@@ -0,0 +1,103 @@
import PropTypes from 'prop-types'
import { Card, Button, Form, Input, Row, Col, Space } from 'antd'
const ConnectForm = ({ connect, btnContent }) => {
const [form] = Form.useForm()
const initialConnectionOptions = {
// ws or wss
protocol: 'ws',
host: 'fwmari.net',
clientId: `sp_${Math.random().toString(16).substring(2, 8)}`,
// ws -> 8083; wss -> 8084
port: 8883,
/**
* By default, EMQX allows clients to connect without authentication.
* https://docs.emqx.com/en/enterprise/v4.4/advanced/auth.html#anonymous-login
*/
username: 'test',
password: '31415926',
}
const onFinish = (values) => {
const { host, clientId, port, username, password } = values
const url = `ws://${host}:${port}/mqtt`
const options = {
clientId,
username,
password,
clean: true,
reconnectPeriod: 1000, // ms
connectTimeout: 30 * 1000, // ms
}
connect(url, options)
}
const handleConnect = () => {
form.submit()
}
const ConnectionForm = (
<Form
layout="vertical"
name="basic"
form={form}
initialValues={initialConnectionOptions}
onFinish={onFinish}
>
<Row gutter={20}>
<Col span={8}>
<Form.Item label="Host" name="host">
<Input />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="Port" name="port">
<Input />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="Client ID" name="clientId">
<Input disabled={true} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="Username" name="username">
<Input />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="Password" name="password">
<Input type='password' />
</Form.Item>
</Col>
</Row>
</Form>
)
return (
<Space
align='center'
style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}
>
<Card
title={<h2>Please, connect before using the system</h2>}
actions={[
<Button type="primary" onClick={handleConnect} key={'Connect'} ghost>
{btnContent}
</Button>
]}
>
{ConnectionForm}
</Card>
</Space>
)
}
ConnectForm.propTypes = {
connect: PropTypes.func.isRequired,
btnContent: PropTypes.oneOfType([
PropTypes.element, PropTypes.string,
]).isRequired
};
export default ConnectForm

66
src/pages/Spectrum.jsx Normal file
View File

@@ -0,0 +1,66 @@
import { Button, Card, Form, Input, Layout, Radio, theme } from "antd";
import { useState } from "react";
const { Content, Sider } = Layout;
const Spectrum = () => {
const {
token: { colorBgContainer },
} = theme.useToken();
const [form] = Form.useForm();
const [mode, setMode] = useState('Angle');
const initialValues = {
mode: "Angle",
};
const onFormChange = ({ mode }) => {
setMode(mode);
};
const angleForm = (
<Form
form={form}
onValuesChange={onFormChange}
initialValues={initialValues}
layout="horizontal"
size="small"
>
<Form.Item label="Mode" name="mode">
<Radio.Group value={mode}>
<Radio.Button value="Angle">Angle</Radio.Button>
<Radio.Button value="Wavelength">Wavelength</Radio.Button>
</Radio.Group>
</Form.Item>
<Form.Item label={`Target ${mode} (${mode == "Angle" ? '°' : 'Å'})`}>
<Input placeholder="30.127" />
</Form.Item>
</Form>
);
return (
<Layout style={{ height: 500 }}>
<Content>
<h2>kk eae men</h2>
</Content>
<Sider width={300} style={{ background: colorBgContainer }}>
<Card
title="Motor control"
size="small"
actions={[
<Button type="primary" key='sendAngle' size="small" ghost>
Send
</Button>
]}
>
{angleForm}
</Card>
</Sider>
</Layout>
)
};
export default Spectrum;