Skip to content

Commit

Permalink
Use eslint in frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
Luligu committed Feb 17, 2025
1 parent 5fea904 commit a3ab409
Show file tree
Hide file tree
Showing 28 changed files with 1,771 additions and 89 deletions.
42 changes: 39 additions & 3 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import tseslint from 'typescript-eslint';
import eslintPluginJest from 'eslint-plugin-jest';
import eslintPluginPrettier from 'eslint-plugin-prettier/recommended';
import eslintPluginN from 'eslint-plugin-n';
import eslintPluginReact from 'eslint-plugin-react';
import eslintPluginReactHooks from 'eslint-plugin-react-hooks';

export default [
{
name: 'global ignores',
ignores: ['dist/', 'build/', 'node_modules/', 'coverage/', 'frontend/', 'rock-s0/'],
ignores: ['dist/', 'build/', 'node_modules/', 'coverage/', 'rock-s0/', 'frontend/public/', 'frontend/build/'],
},
eslint.configs.recommended,
...tseslint.configs.strict,
Expand All @@ -35,11 +37,16 @@ export default [
name: 'javascript',
files: ['**/*.js'],
...tseslint.configs.disableTypeChecked,
rules: {
// Make absolutely sure no TS rules bleed into .js files
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
},
},
{
name: 'typescript',
files: ['**/*.ts'],
ignores: ['**/__test__/*', '**/*.test.ts', '**/*.spec.ts'],
ignores: ['**/__test__/*', '**/*.test.ts', '**/*.spec.ts', 'frontend/**'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
Expand All @@ -55,7 +62,7 @@ export default [
},
{
name: 'jest',
files: ['**/__test__/*', '**/*.test.ts', '**/*.spec.ts'],
files: ['**/__test__/*', '**/*.test.ts', '**/*.spec.ts', 'frontend/**'],
plugins: {
'@typescript-eslint': tseslint.plugin,
jest: eslintPluginJest,
Expand All @@ -73,4 +80,33 @@ export default [
'n/prefer-node-protocol': 'error',
},
},
{
name: 'frontend-react',
files: ['frontend/src/**/*.js'],
plugins: {
react: eslintPluginReact,
'react-hooks': eslintPluginReactHooks,
},
settings: {
react: {
version: 'detect',
},
},
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'react/prop-types': 'off',
'react/react-in-jsx-scope': 'off', // React 17+
'no-unused-vars': [
'error',
{
vars: 'all',
args: 'after-used',
ignoreRestSiblings: true,
argsIgnorePattern: '^_', // Ignore unused variables starting with _
varsIgnorePattern: '^_', // Ignore unused variables starting with _
},
],
},
},
];
6 changes: 3 additions & 3 deletions frontend/build/asset-manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"files": {
"main.css": "./static/css/main.cf25d33e.css",
"main.js": "./static/js/main.be75f5a3.js",
"main.js": "./static/js/main.0b93979e.js",
"static/js/453.abd36b29.chunk.js": "./static/js/453.abd36b29.chunk.js",
"static/media/roboto-latin-700-normal.woff2": "./static/media/roboto-latin-700-normal.4535474e1cf8598695ad.woff2",
"static/media/roboto-latin-500-normal.woff2": "./static/media/roboto-latin-500-normal.7077203b1982951ecf76.woff2",
Expand Down Expand Up @@ -61,11 +61,11 @@
"static/media/roboto-greek-ext-400-normal.woff": "./static/media/roboto-greek-ext-400-normal.16eb83b4a3b1ea994243.woff",
"index.html": "./index.html",
"main.cf25d33e.css.map": "./static/css/main.cf25d33e.css.map",
"main.be75f5a3.js.map": "./static/js/main.be75f5a3.js.map",
"main.0b93979e.js.map": "./static/js/main.0b93979e.js.map",
"453.abd36b29.chunk.js.map": "./static/js/453.abd36b29.chunk.js.map"
},
"entrypoints": [
"static/css/main.cf25d33e.css",
"static/js/main.be75f5a3.js"
"static/js/main.0b93979e.js"
]
}
2 changes: 1 addition & 1 deletion frontend/build/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.be75f5a3.js"></script><link href="./static/css/main.cf25d33e.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.0b93979e.js"></script><link href="./static/css/main.cf25d33e.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions frontend/src/components/ConfirmCancelForm.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
// @mui/material
import Dialog from '@mui/material/Dialog';
import DialogTitle from '@mui/material/DialogTitle';
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/Devices.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
// React
import React, { useContext, useEffect, useState } from 'react';
import { useTable, useSortBy } from 'react-table';
Expand Down
27 changes: 15 additions & 12 deletions frontend/src/components/DevicesIcons.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/* eslint-disable no-unused-vars */
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-console */
// React
import React, { useContext, useEffect, useState } from 'react';

Expand Down Expand Up @@ -154,47 +157,47 @@ function Device({ device, endpoint, id, deviceType, clusters }) {
{deviceType===0x002b && clusters.filter(cluster => cluster.clusterName === 'FanControl' && cluster.attributeName === 'percentCurrent').map(cluster => (
<Render icon={<AirIcon/>} cluster={cluster} value={cluster.attributeValue} unit='%'/>
))}
{/*GenericSwitch*/}
{/* GenericSwitch */}
{deviceType===0x000f && clusters.filter(cluster => cluster.clusterName === 'Switch' && cluster.attributeName === 'currentPosition').map(cluster => (
<Render icon={<RadioButtonCheckedIcon/>} cluster={cluster} value={cluster.attributeValue} unit='pos'/>
))}
{/*ModeSelect*/}
{/* ModeSelect */}
{deviceType===0x0027 && clusters.filter(cluster => cluster.clusterName === 'ModeSelect' && cluster.attributeName === 'currentMode').map(cluster => (
<Render icon={<ChecklistIcon/>} cluster={cluster} value={cluster.attributeValue} unit='mode'/>
))}
{/*Pump*/}
{/* Pump */}
{deviceType===0x0303 && clusters.filter(cluster => cluster.clusterName === 'OnOff' && cluster.attributeName === 'onOff').map(cluster => (
<Render icon={<CycloneIcon/>} cluster={cluster} value={cluster.attributeLocalValue===true ? 'On' : 'Off'}/>
))}
{/*Air purifier*/}
{/* Air purifier */}
{deviceType===0x002d && clusters.filter(cluster => cluster.clusterName === 'FanControl' && cluster.attributeName === 'percentCurrent').map(cluster => (
<Render icon={<HvacIcon/>} cluster={cluster} value={cluster.attributeValue} unit='%'/>
))}
{/*Air conditioner*/}
{/* Air conditioner */}
{deviceType===0x0072 && clusters.filter(cluster => cluster.clusterName === 'Thermostat' && cluster.attributeName === 'localTemperature').map(cluster => (
<Render icon={<HvacIcon/>} cluster={cluster} value={(cluster.attributeLocalValue ?? 0)/100} unit='°C'/>
))}
{/*Water leak detector*/}
{/* Water leak detector */}
{deviceType===0x0043 && clusters.filter(cluster => cluster.clusterName === 'BooleanState' && cluster.attributeName === 'stateValue').map(cluster => (
<Render icon={<WaterIcon/>} cluster={cluster} value={cluster.attributeLocalValue===true ?'No leak':'Leak'}/>
))}
{/*Water freeze detector*/}
{/* Water freeze detector */}
{deviceType===0x0041 && clusters.filter(cluster => cluster.clusterName === 'BooleanState' && cluster.attributeName === 'stateValue').map(cluster => (
<Render icon={<AcUnitIcon/>} cluster={cluster} value={cluster.attributeLocalValue===true ?'No freeze':'Freeze'}/>
))}
{/*Rain sensor*/}
{/* Rain sensor */}
{deviceType===0x0044 && clusters.filter(cluster => cluster.clusterName === 'BooleanState' && cluster.attributeName === 'stateValue').map(cluster => (
<Render icon={<ThunderstormIcon/>} cluster={cluster} value={cluster.attributeLocalValue===true ?'No rain':'Rain'}/>
))}
{/*SmokeCoAlarm*/}
{/* SmokeCoAlarm */}
{deviceType===0x0076 && clusters.filter(cluster => cluster.clusterName === 'SmokeCoAlarm' && cluster.attributeName === 'smokeState').map(cluster => (
<Render icon={<LocalFireDepartmentIcon/>} cluster={cluster} value={cluster.attributeLocalValue===0 ?'No smoke':'Smoke'}/>
))}
{/*WaterValve*/}
{/* WaterValve */}
{deviceType===0x0042 && clusters.filter(cluster => cluster.clusterName === 'ValveConfigurationAndControl' && cluster.attributeName === 'currentState').map(cluster => (
<Render icon={<OpacityIcon/>} cluster={cluster} value={cluster.attributeLocalValue===0 ?'Closed':'Opened'}/>
))}
{/*AirQuality*/}
{/* AirQuality */}
{deviceType===0x002c && clusters.filter(cluster => cluster.clusterName === 'AirQuality' && cluster.attributeName === 'airQuality').map(cluster => (
<Render icon={<MasksIcon/>} cluster={cluster} value={airQualityLookup[cluster.attributeLocalValue ?? 0]}/>
))}
Expand Down Expand Up @@ -360,7 +363,7 @@ export function DevicesIcons({filter}) {
</Dialog>

<div style={{ display: 'flex', flexWrap: 'wrap', paddingBottom: '5px', gap: '20px', width: '100%', overflow: 'auto' }}>
{/*<Typography>Loading... {devices.length} devices, {Object.keys(endpoints).length} endpoints, {Object.keys(deviceTypes).length} deviceTypes</Typography>*/}
{/* <Typography>Loading... {devices.length} devices, {Object.keys(endpoints).length} endpoints, {Object.keys(deviceTypes).length} deviceTypes</Typography> */}
{filteredDevices.map((device) => (
endpoints[device.serial] && endpoints[device.serial].map((endpoint) => (
endpoint.deviceTypes.map((deviceType) => (
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ function Header() {

useEffect(() => {
const handleWebSocketMessage = (msg) => {
/*Header listener*/
/* Header listener */
if (debug) console.log('Header received WebSocket Message:', msg);
if (msg.src === 'Matterbridge' && msg.dst === 'Frontend') {
if (msg.method === 'refresh_required') {
Expand Down
14 changes: 8 additions & 6 deletions frontend/src/components/Home.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable no-unused-vars */
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-console */

// React
Expand Down Expand Up @@ -62,7 +64,7 @@ function Home() {
const { showSnackbarMessage, showConfirmCancelDialog } = useContext(UiContext);
const { logMessage, addListener, removeListener, online, sendMessage } = useContext(WebSocketContext);

const refAddRemove = useRef(null);
// const refAddRemove = useRef(null);
const refRegisteredPlugins = useRef(null);

const primaryColor = useMemo(() => getCssVariable('--primary-color', '#009a00'), []);
Expand Down Expand Up @@ -283,17 +285,17 @@ function Home() {
</Dialog>
</ThemeProvider>

{/*Left column*/}
{/* Left column */}
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', width: '302px', minWidth: '302px', gap: '20px' }}>
{matterbridgeInfo && <QRDiv matterbridgeInfo={matterbridgeInfo} plugin={selectedRow === -1 ? undefined : plugins[selectedRow]} />}
{systemInfo && <SystemInfoTable systemInfo={systemInfo} compact={true} />}
{qrCode === '' && matterbridgeInfo && <MatterbridgeInfoTable matterbridgeInfo={matterbridgeInfo} />}
</div>

{/*Right column*/}
{/* Right column */}
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', width: '100%', gap: '20px' }}>

{/*Install add plugin*/}
{/* Install add plugin */}
{matterbridgeInfo && !matterbridgeInfo.readOnly &&
<div className="MbfWindowDiv" style={{ flex: '0 0 auto', width: '100%', overflow: 'hidden' }}>
<div className="MbfWindowHeader">
Expand All @@ -303,7 +305,7 @@ function Home() {
</div>
}

{/*Registered plugins*/}
{/* Registered plugins */}
<div className="MbfWindowDiv" style={{ flex: '0 0 auto', width: '100%', overflow: 'hidden' }}>
<div className="MbfWindowDivTable" style={{ flex: '0 0 auto', overflow: 'hidden' }}>
<table ref={refRegisteredPlugins}>
Expand Down Expand Up @@ -390,7 +392,7 @@ function Home() {
</div>
</div>

{/*Logs*/}
{/* Logs*/}
<div className="MbfWindowDiv" style={{ flex: '1 1 auto', width: '100%', overflow: 'hidden' }}>
<div className="MbfWindowHeader" style={{ flexShrink: 0 }}>
<div className="MbfWindowHeaderText" style={{ display: 'flex', justifyContent: 'space-between' }}>
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/components/InstallAddPlugins.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
/* eslint-disable no-console */
// React
import React, { useState, useContext } from 'react';

// @mui/material
import TextField from '@mui/material/TextField';
import Alert from '@mui/material/Alert';
import Snackbar from '@mui/material/Snackbar';
import Tooltip from '@mui/material/Tooltip';
import IconButton from '@mui/material/IconButton';
import Button from '@mui/material/Button';
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/Logs.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
// React
import React, { useState, useContext } from 'react';

Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/MatterbridgeInfoTable.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
// Frontend
import { TruncatedText } from './TruncatedText';
// import { debug } from '../App';
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/QRDiv.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
// Frontend
import { debug } from '../App';

Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/SystemInfoTable.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
// React
import React, { useContext, useEffect, useState } from 'react';

Expand Down
8 changes: 5 additions & 3 deletions frontend/src/components/Test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable no-unused-vars */
/* eslint-disable no-console */
// React
import React, { useContext, useEffect, useState, useRef } from 'react';

Expand Down Expand Up @@ -101,7 +103,7 @@ function Test() {
removeListener(handleWebSocketMessage);
if(debug) console.log('Test useEffect WebSocketMessage unmounted');
};
}, [addListener, removeListener, sendMessage]);
}, [addListener, removeListener, sendMessage, showSnackbarMessage]);

useEffect(() => {
if(debug) console.log('Test useEffect online mounting');
Expand All @@ -125,9 +127,9 @@ function Test() {
return (
<div className="MbfPageDiv" style={{ display: 'flex', flexDirection: 'row', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>

{/*<div style={{ display: 'flex', gap: '20px', width: '100%' }}>
{/* <div style={{ display: 'flex', gap: '20px', width: '100%' }}>
{settings && settings.systemInformation && <SystemInfoTable systemInfo={settings.systemInformation} compact={false}/>}
</div>*/}
</div> */}

<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '20px', width: '100%' }}>
<img src="matterbridge.svg" alt="Matterbridge Logo" style={{ height: '64px', width: '64px' }} />
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/UiProvider.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/* eslint-disable no-unused-vars */
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-console */
// React
import React, { useState, useCallback, useMemo, createContext, useRef } from 'react';

Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/WebSocketProvider.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-console */
// React
import React, { useEffect, useRef, useState, useCallback, useMemo, createContext, useContext } from 'react';

Expand Down Expand Up @@ -72,7 +74,7 @@ export function WebSocketProvider({ children }) {
wsRef.current.send(msg);
if (debug) console.log(`WebSocket sent message:`, message);
} catch (error) {
// eslint-disable-next-line no-console

console.error(`WebSocket error sending message: ${error}`);
}
} else {
Expand Down Expand Up @@ -210,7 +212,7 @@ export function WebSocketProvider({ children }) {
return newMessages;
});
} catch (error) {
// eslint-disable-next-line no-console
console.error(`WebSocketUse error parsing message: ${error}`);
}
};
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/configEditor.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/* eslint-disable no-unused-vars */
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-console */
// React
import { useState, useMemo } from 'react';

Expand Down Expand Up @@ -452,7 +455,7 @@ export function ArrayFieldTemplate(props) {
}

export function ObjectFieldTemplate(props) {
const { onAddClick, schema, properties, title, description, formData, registry } = props;
const { onAddClick, schema, properties, title, description } = props;

const [dialogDeviceOpen, setDialogDeviceOpen] = useState(false);
const [filter, setFilter] = useState('');
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/muiTheme.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
// @mui
import { createTheme } from '@mui/material';

Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/sendApiCommand.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable no-unused-vars */
/* eslint-disable no-console */
// Send a POST request to the Matterbridge API
export function sendCommandToMatterbridge(command, param, body) {
const sanitizedParam = param.replace(/\\/g, '*');
Expand All @@ -15,7 +17,7 @@ export function sendCommandToMatterbridge(command, param, body) {
}
return response.json();
})
// eslint-disable-next-line @typescript-eslint/no-unused-vars
.then(json => {
// console.log('Command sent successfully:', json);
})
Expand Down
Loading

0 comments on commit a3ab409

Please sign in to comment.