From 514fc5aae31cbbd908a6d9e26782336e91188827 Mon Sep 17 00:00:00 2001 From: Klaus Borges Date: Tue, 17 Dec 2024 07:34:59 -0300 Subject: [PATCH] fix: clean up ignored exhaustive deps rules, fix setup flow --- biome.jsonc | 10 +- package-lock.json | 72 +++---- package.json | 14 +- packages/console/package.json | 5 +- packages/console/src/App.tsx | 6 +- .../Common/ActionFields/ActionFields.tsx | 7 +- .../ActionTypePicker/ActionTypePicker.tsx | 6 +- .../Edit/ScheduleTrigger/ScheduleTrigger.tsx | 1 - .../ScheduleTrigger/TypeScheduleOptions.tsx | 5 +- .../Components/Analysis/Edit/AnalysisEdit.tsx | 61 +++--- .../src/Components/Bucket/Edit/BucketEdit.tsx | 18 +- .../Common/LiveInspector/LiveInspector.tsx | 75 ++++---- .../Device/Edit/EncoderStack/EncoderStack.tsx | 8 +- .../src/Components/EditPage/EditPage.tsx | 19 +- .../Components/Home/Statistics/Statistics.tsx | 2 +- .../src/Components/InputTime/InputTime.tsx | 35 ++-- packages/console/src/Components/Logs/Logs.tsx | 2 +- .../console/src/Components/Modal/Modal.tsx | 2 +- .../ModalFileSelect/ModalFileSelect.tsx | 5 +- .../PaginatedTable/PaginatedTable.tsx | 55 +----- .../ModalInstallPlugin/ModalInstallPlugin.tsx | 17 +- .../ModalUploadPlugin/ModalUploadPlugin.tsx | 14 +- .../Common/ModuleStatus/ModuleStatus.tsx | 30 +-- .../Plugins/Common/Status/Status.tsx | 9 +- .../Components/Plugins/Edit/PluginEdit.tsx | 41 ++-- .../RowManipulator/RowManipulator.tsx | 19 +- .../console/src/Components/Setup/Setup.tsx | 129 +++++++++---- .../StepDatabaseError/StepDatabaseError.tsx | 83 ++++----- .../StepDatabaseNoStore.tsx | 49 +++-- .../StepDatabaseWithStore.tsx | 176 +++++++++--------- .../StepDatabaseWrapper.tsx | 9 +- .../StepMasterPassword/StepMasterPassword.tsx | 78 ++++---- .../StepPluginConfig/StepPluginConfig.tsx | 80 ++++---- .../Setup/StepSignUp/StepSignUp.tsx | 9 +- .../Setup/StepWelcome/StepWelcome.tsx | 2 +- .../src/Components/Sidebar/Sidebar.tsx | 7 +- .../Store/Details/DataTabs/DataTabs.tsx | 7 +- .../Store/Details/PluginDetails.tsx | 4 +- .../Store/Details/Sidebar/Sidebar.tsx | 3 - packages/console/src/theme.ts | 6 +- packages/console/tsconfig.json | 18 +- 41 files changed, 528 insertions(+), 670 deletions(-) diff --git a/biome.jsonc b/biome.jsonc index f27a29d0..1c4c3468 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -7,7 +7,12 @@ }, "files": { "ignoreUnknown": false, - "ignore": ["build", "build-tsc", "standalone-plugins", "standalone"] + "ignore": [ + "build", + "build-tsc", + "standalone-plugins", + "standalone" + ] }, "formatter": { "enabled": true, @@ -29,8 +34,7 @@ "noCommonJs": "error" }, "correctness": { - "useImportExtensions": "error", - "useExhaustiveDependencies": "off" + "useImportExtensions": "error" }, "suspicious": { "noExplicitAny": "off", diff --git a/package-lock.json b/package-lock.json index b6acaa96..c8f76e73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ "tagocore": "packages/tcore-cli/build/index.js" }, "devDependencies": { - "@biomejs/biome": "1.9.3", + "@biomejs/biome": "1.9.4", "@swc-node/register": "1.10.9", "@tago-io/tcore-sdk": "0.7.2", "@testing-library/dom": "10.4.0", @@ -1300,9 +1300,9 @@ } }, "node_modules/@biomejs/biome": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.3.tgz", - "integrity": "sha512-POjAPz0APAmX33WOQFGQrwLvlu7WLV4CFJMlB12b6ZSg+2q6fYu9kZwLCOA+x83zXfcPd1RpuWOKJW0GbBwLIQ==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz", + "integrity": "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==", "dev": true, "hasInstallScript": true, "license": "MIT OR Apache-2.0", @@ -1317,20 +1317,20 @@ "url": "https://opencollective.com/biome" }, "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "1.9.3", - "@biomejs/cli-darwin-x64": "1.9.3", - "@biomejs/cli-linux-arm64": "1.9.3", - "@biomejs/cli-linux-arm64-musl": "1.9.3", - "@biomejs/cli-linux-x64": "1.9.3", - "@biomejs/cli-linux-x64-musl": "1.9.3", - "@biomejs/cli-win32-arm64": "1.9.3", - "@biomejs/cli-win32-x64": "1.9.3" + "@biomejs/cli-darwin-arm64": "1.9.4", + "@biomejs/cli-darwin-x64": "1.9.4", + "@biomejs/cli-linux-arm64": "1.9.4", + "@biomejs/cli-linux-arm64-musl": "1.9.4", + "@biomejs/cli-linux-x64": "1.9.4", + "@biomejs/cli-linux-x64-musl": "1.9.4", + "@biomejs/cli-win32-arm64": "1.9.4", + "@biomejs/cli-win32-x64": "1.9.4" } }, "node_modules/@biomejs/cli-darwin-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.3.tgz", - "integrity": "sha512-QZzD2XrjJDUyIZK+aR2i5DDxCJfdwiYbUKu9GzkCUJpL78uSelAHAPy7m0GuPMVtF/Uo+OKv97W3P9nuWZangQ==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz", + "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==", "cpu": [ "arm64" ], @@ -1345,9 +1345,9 @@ } }, "node_modules/@biomejs/cli-darwin-x64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.3.tgz", - "integrity": "sha512-vSCoIBJE0BN3SWDFuAY/tRavpUtNoqiceJ5PrU3xDfsLcm/U6N93JSM0M9OAiC/X7mPPfejtr6Yc9vSgWlEgVw==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz", + "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==", "cpu": [ "x64" ], @@ -1362,9 +1362,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.3.tgz", - "integrity": "sha512-vJkAimD2+sVviNTbaWOGqEBy31cW0ZB52KtpVIbkuma7PlfII3tsLhFa+cwbRAcRBkobBBhqZ06hXoZAN8NODQ==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz", + "integrity": "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==", "cpu": [ "arm64" ], @@ -1379,9 +1379,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.3.tgz", - "integrity": "sha512-VBzyhaqqqwP3bAkkBrhVq50i3Uj9+RWuj+pYmXrMDgjS5+SKYGE56BwNw4l8hR3SmYbLSbEo15GcV043CDSk+Q==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz", + "integrity": "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==", "cpu": [ "arm64" ], @@ -1396,9 +1396,9 @@ } }, "node_modules/@biomejs/cli-linux-x64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.3.tgz", - "integrity": "sha512-x220V4c+romd26Mu1ptU+EudMXVS4xmzKxPVb9mgnfYlN4Yx9vD5NZraSx/onJnd3Gh/y8iPUdU5CDZJKg9COA==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz", + "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==", "cpu": [ "x64" ], @@ -1413,9 +1413,9 @@ } }, "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.3.tgz", - "integrity": "sha512-TJmnOG2+NOGM72mlczEsNki9UT+XAsMFAOo8J0me/N47EJ/vkLXxf481evfHLlxMejTY6IN8SdRSiPVLv6AHlA==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz", + "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==", "cpu": [ "x64" ], @@ -1430,9 +1430,9 @@ } }, "node_modules/@biomejs/cli-win32-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.3.tgz", - "integrity": "sha512-lg/yZis2HdQGsycUvHWSzo9kOvnGgvtrYRgoCEwPBwwAL8/6crOp3+f47tPwI/LI1dZrhSji7PNsGKGHbwyAhw==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz", + "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==", "cpu": [ "arm64" ], @@ -1447,9 +1447,9 @@ } }, "node_modules/@biomejs/cli-win32-x64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.3.tgz", - "integrity": "sha512-cQMy2zanBkVLpmmxXdK6YePzmZx0s5Z7KEnwmrW54rcXK3myCNbQa09SwGZ8i/8sLw0H9F3X7K4rxVNGU8/D4Q==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", + "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==", "cpu": [ "x64" ], diff --git a/package.json b/package.json index e4c9c932..5c5d1cd2 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,16 @@ "node": ">=20.0.0" }, "type": "module", - "workspaces": ["packages/*", "plugins/*"], - "keywords": ["platform", "iot", "tagoio", "tcore"], + "workspaces": [ + "packages/*", + "plugins/*" + ], + "keywords": [ + "platform", + "iot", + "tagoio", + "tcore" + ], "bugs": { "url": "https://github.com/tago-io/tcore/issues" }, @@ -44,7 +52,7 @@ "zod": "3.23.8" }, "devDependencies": { - "@biomejs/biome": "1.9.3", + "@biomejs/biome": "1.9.4", "@swc-node/register": "1.10.9", "@tago-io/tcore-sdk": "0.7.2", "@testing-library/dom": "10.4.0", diff --git a/packages/console/package.json b/packages/console/package.json index 0840f885..0adf2381 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -9,7 +9,10 @@ "watch": "vite", "build": "vite build", "build-watch": "vite build --watch", - "test": "vitest" + "test": "vitest", + "lint": "biome check .", + "format": "biome format . --write", + "lint-fix": "biome check . --write" }, "dependencies": { "@antv/g2": "4.1.23", diff --git a/packages/console/src/App.tsx b/packages/console/src/App.tsx index cf11e7a8..7f0c4f48 100644 --- a/packages/console/src/App.tsx +++ b/packages/console/src/App.tsx @@ -103,6 +103,7 @@ const WrappedStoreRoutes = observer(() => { } }, [plugins]); + // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect state machine useEffect(() => { if (status) { if (status.database?.error) { @@ -131,17 +132,16 @@ const WrappedStoreRoutes = observer(() => { store.accountConfigured = status.account; }); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [status]); + }, [status, navigate]); /** * Starts the socket connection. */ + // biome-ignore lint/correctness/useExhaustiveDependencies: mobx observers useEffect(() => { if (store.masterPassword || store.token) { startSocket(); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [store.masterPassword, store.token]); if (!readyToRender) { diff --git a/packages/console/src/Components/Action/Common/ActionFields/ActionFields.tsx b/packages/console/src/Components/Action/Common/ActionFields/ActionFields.tsx index d177bfca..90678e0c 100644 --- a/packages/console/src/Components/Action/Common/ActionFields/ActionFields.tsx +++ b/packages/console/src/Components/Action/Common/ActionFields/ActionFields.tsx @@ -9,9 +9,6 @@ import ActionTypePicker from "../ActionTypePicker/ActionTypePicker.tsx"; import HttpHeaders from "../HttpHeaders/HttpHeaders.tsx"; import MultipleAnalysis from "../MultipleAnalysis/MultipleAnalysis.tsx"; -/** - * Props. - */ interface IActionFields { /** * Error of the fields. @@ -178,10 +175,10 @@ function ActionFields(props: IActionFields) { /** * Sets the type into the action. */ + // biome-ignore lint/correctness/useExhaustiveDependencies(action): useEffect state machine useEffect(() => { onChangeAction({ ...action, type: actionType?.id || actionType }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [actionType]); + }, [actionType, onChangeAction]); return ( <> diff --git a/packages/console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.tsx b/packages/console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.tsx index 5bb7b384..500d4672 100644 --- a/packages/console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.tsx +++ b/packages/console/src/Components/Action/Common/ActionTypePicker/ActionTypePicker.tsx @@ -42,9 +42,6 @@ const defaultOptions: IOption[] = [ }, ]; -/** - * Props. - */ interface IActionTypePicker { /** * Option object. @@ -166,8 +163,7 @@ function ActionTypePicker(props: IActionTypePicker) { if (isSchedule && props.value?.id === "tagoio") { props.onChange(null as any); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.value, isSchedule]); + }, [props.value, isSchedule, props.onChange]); return ( diff --git a/packages/console/src/Components/Action/Edit/ScheduleTrigger/ScheduleTrigger.tsx b/packages/console/src/Components/Action/Edit/ScheduleTrigger/ScheduleTrigger.tsx index 46ae86e5..05a1d138 100644 --- a/packages/console/src/Components/Action/Edit/ScheduleTrigger/ScheduleTrigger.tsx +++ b/packages/console/src/Components/Action/Edit/ScheduleTrigger/ScheduleTrigger.tsx @@ -57,7 +57,6 @@ function ScheduleTrigger(props: IScheduleTrigger) { useEffect(() => { const explanation = getCronExplanation(scheduleData.cron || ""); setCronExplanation(explanation); - // eslint-disable-next-line react-hooks/exhaustive-deps }, [scheduleData.cron]); const showExplanation = diff --git a/packages/console/src/Components/Action/Edit/ScheduleTrigger/TypeScheduleOptions.tsx b/packages/console/src/Components/Action/Edit/ScheduleTrigger/TypeScheduleOptions.tsx index e70f7eb2..45d242e9 100644 --- a/packages/console/src/Components/Action/Edit/ScheduleTrigger/TypeScheduleOptions.tsx +++ b/packages/console/src/Components/Action/Edit/ScheduleTrigger/TypeScheduleOptions.tsx @@ -11,9 +11,6 @@ import type { import MinimumScheduleMessage from "./MinimumScheduleMessage.tsx"; import * as Style from "./TypeScheduleOptions.style"; -/** - * Props. - */ interface ITypeScheduleOptions { /** * Error of the fields. @@ -34,11 +31,11 @@ function TypeScheduleOptions(props: ITypeScheduleOptions) { const inputRef = useRef(null); const { errors, scheduleData, onChangeScheduleData } = props; + // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect auto-trigger useEffect(() => { if (inputRef.current && !scheduleData.interval) { inputRef.current.focus(); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [scheduleData.type]); return ( diff --git a/packages/console/src/Components/Analysis/Edit/AnalysisEdit.tsx b/packages/console/src/Components/Analysis/Edit/AnalysisEdit.tsx index b4234681..4058c3f2 100644 --- a/packages/console/src/Components/Analysis/Edit/AnalysisEdit.tsx +++ b/packages/console/src/Components/Analysis/Edit/AnalysisEdit.tsx @@ -37,9 +37,6 @@ function AnalysisEdit() { const initialData = useRef({} as IAnalysis); const loading = !data.id; - /** - * Should return if the initial data is different from the current data. - */ const checkIfDataChanged = useCallback(() => { const initialDataNorm = { ...initialData.current, @@ -55,28 +52,21 @@ function AnalysisEdit() { return JSON.stringify(initialDataNorm) !== JSON.stringify(currentDataNorm); }, [data]); - /** - * Called when the record was fetched by the edit page. - * We use this to set the data state to manipulate the object. - */ const onFetch = useCallback((analysis: IAnalysis) => { setData(analysis); setLogs(analysis.console?.reverse?.() || []); initialData.current = cloneDeep(analysis); }, []); - /** - * Validates the form data to make sure the object is not faulty. - * This should return a boolean to indicate if the data is correct or not. - */ const validate = useCallback(async () => { return true; }, []); - /** - * Saves the analysis. - */ const save = useCallback(async () => { + if (!id) { + return; + } + setSaveAndRunDisabled(true); try { const formatted = { @@ -98,10 +88,11 @@ function AnalysisEdit() { } }, [id, data]); - /** - * Runs the analysis. - */ const run = useCallback(async () => { + if (!id) { + return; + } + setSaveAndRunDisabled(true); try { await runAnalysis(id); @@ -110,9 +101,6 @@ function AnalysisEdit() { } }, [id]); - /** - * Saves and runs the analysis. - */ const saveAndRun = useCallback(async () => { const dataChanged = checkIfDataChanged(); if (dataChanged) { @@ -123,34 +111,29 @@ function AnalysisEdit() { } }, [checkIfDataChanged, save, run]); - /** - * Deletes the analysis. - */ const deleteData = useCallback(async () => { + if (!id) { + return; + } + await deleteAnalysis(id); }, [id]); - /** - * Clears the logs. - */ const clearLogs = useCallback(() => { setLogs([]); }, []); - /** - * Deletes the logs. - */ const deleteLogs = useCallback(() => { + if (!id) { + return; + } + deleteAnalysisLogs(id); clearLogs(); }, [clearLogs, id]); - /** - * Called when a field from a tab gets modified. - * This will apply the change to the data state. - */ const onChangeData = useCallback( - (field: keyof IAnalysis, value) => { + (field: keyof IAnalysis, value: any) => { setData({ ...data, [field]: value }); }, [data], @@ -243,17 +226,19 @@ function AnalysisEdit() { }; }); - /** - */ + // biome-ignore lint/correctness/useExhaustiveDependencies(store.socketConnected): mobx observer useEffect(() => { + if (!id) { + return; + } + if (store.socketConnected) { getSocket().emit("attach", "analysis", id); return () => { getSocket().emit("unattach", "analysis", id); }; } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [store.socketConnected]); + }, [id, store.socketConnected]); return ( diff --git a/packages/console/src/Components/Bucket/Edit/BucketEdit.tsx b/packages/console/src/Components/Bucket/Edit/BucketEdit.tsx index f661c996..58c98467 100644 --- a/packages/console/src/Components/Bucket/Edit/BucketEdit.tsx +++ b/packages/console/src/Components/Bucket/Edit/BucketEdit.tsx @@ -64,10 +64,11 @@ function BucketEdit() { } }, [data]); - /** - * Saves the bucket. - */ const save = useCallback(async () => { + if (!id) { + return; + } + await editDevice(id, { chunk_retention: data.chunk_retention }); initialData.current = cloneDeep(data); }, [id, data]); @@ -83,9 +84,6 @@ function BucketEdit() { [data], ); - /** - * Empties the bucket. - */ const emptyBucket = useCallback(async () => { await axios.post( `/device/${id}/empty`, @@ -103,6 +101,10 @@ function BucketEdit() { */ const deleteData = useCallback( async (ids: string[]) => { + if (!id) { + return; + } + await deleteDeviceData(id, { ids }); mutateDataAmount(Math.max(dataAmount - ids.length, 0)); }, @@ -177,13 +179,11 @@ function BucketEdit() { return JSON.stringify(initialData.current) !== JSON.stringify(data); }, [data]); - /** - */ + // biome-ignore lint/correctness/useExhaustiveDependencies(dataAmount): useEffect state machine useEffect(() => { if (tabIndex === 1) { mutateDataAmount(dataAmount, true); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [mutateDataAmount, tabIndex]); return ( diff --git a/packages/console/src/Components/Device/Common/LiveInspector/LiveInspector.tsx b/packages/console/src/Components/Device/Common/LiveInspector/LiveInspector.tsx index c901f45e..77233183 100644 --- a/packages/console/src/Components/Device/Common/LiveInspector/LiveInspector.tsx +++ b/packages/console/src/Components/Device/Common/LiveInspector/LiveInspector.tsx @@ -14,9 +14,6 @@ import Tooltip from "../../../Tooltip/Tooltip.tsx"; import * as Style from "./LiveInspector.style"; import LiveInspectorRow from "./LiveInspectorRow.tsx"; -/** - * Props. - */ interface ILiveInspectorProps { /** * Indicates if the live inspector is enabled or not. @@ -44,8 +41,6 @@ interface ILiveInspectorProps { onClear: () => void; } -/** - */ function LiveInspector(props: ILiveInspectorProps) { const [filter, setFilter] = useState(""); const [logsFiltered, setLogsFiltered] = useState( @@ -73,43 +68,44 @@ function LiveInspector(props: ILiveInspectorProps) { downloadFile(mapped.join("\n"), "txt", "console"); }, [logsFiltered]); - /** - */ - const filterLogs = useCallback(() => { - const result: any = {}; - - Object.keys(logs).forEach((key: string) => { - result[key] = logs[key].filter((item: any) => { - const filterLowerCase = filter.toLowerCase(); - const content = (String(item.content) || "").toLowerCase(); - const timestamp = (String(item.timestamp) || "").toLowerCase(); - const title = (String(item.title) || "").toLowerCase(); - return ( - !filter || - content.includes(filterLowerCase) || - timestamp.includes(filterLowerCase) || - title.includes(filterLowerCase) - ); - }); + const filterLogs = useCallback( + (logsToFilter: ILiveInspectorProps["logs"]) => { + const result: any = {}; - if (!result[key].length) { - delete result[key]; - } - }); + Object.keys(logsToFilter).forEach((key: string) => { + result[key] = logsToFilter[key].filter((item: any) => { + const filterLowerCase = filter.toLowerCase(); + const content = (String(item.content) || "").toLowerCase(); + const timestamp = (String(item.timestamp) || "").toLowerCase(); + const title = (String(item.title) || "").toLowerCase(); + return ( + !filter || + content.includes(filterLowerCase) || + timestamp.includes(filterLowerCase) || + title.includes(filterLowerCase) + ); + }); - const array = Object.keys(result).map((key) => result[key]); + if (!result[key].length) { + delete result[key]; + } + }); + + const array = Object.keys(result).map((key) => result[key]); - const sorted = array - .sort((a, b) => { - return ( - new Date(b[0].timestamp).getTime() - - new Date(a[0].timestamp).getTime() - ); - }) - .slice(0, limit); + const sorted = array + .sort((a, b) => { + return ( + new Date(b[0].timestamp).getTime() - + new Date(a[0].timestamp).getTime() + ); + }) + .slice(0, limit); - return sorted; - }, [filter, limit, logs]); + return sorted; + }, + [filter, limit], + ); /** * Renders the header of the live inspector. @@ -224,7 +220,8 @@ function LiveInspector(props: ILiveInspectorProps) { * Resets the filtered array when a new data arrives on when one of the filter changes. */ useEffect(() => { - const filtered = filterLogs(); + const filtered = filterLogs(logs); + setLogsFiltered(filtered); }, [filterLogs, logs]); diff --git a/packages/console/src/Components/Device/Edit/EncoderStack/EncoderStack.tsx b/packages/console/src/Components/Device/Edit/EncoderStack/EncoderStack.tsx index 72879b64..313726fc 100644 --- a/packages/console/src/Components/Device/Edit/EncoderStack/EncoderStack.tsx +++ b/packages/console/src/Components/Device/Edit/EncoderStack/EncoderStack.tsx @@ -9,9 +9,6 @@ import { EIcon } from "../../../Icon/Icon.types"; import * as Style from "./EncoderStack.style"; import ModalAddEncoder from "./ModalAddEncoder.tsx"; -/** - * Props. - */ interface IEncoderStackProps { /** * Stack value. @@ -40,8 +37,6 @@ function EncoderStack(props: IEncoderStackProps) { const [targetIndex, setTargetIndex] = useState(-1); const containerRef = useRef(null); - /** - */ const onItemMouseDown = useCallback((e: React.MouseEvent, item: string) => { setSelectedID(item); // we do these to prevent selecting the text: @@ -163,8 +158,7 @@ function EncoderStack(props: IEncoderStackProps) { value.splice(fromIndex, 0, value.splice(targetIndex, 1)[0]); onChange([...value].filter((x) => x)); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedID, targetIndex]); + }, [value, selectedID, targetIndex, onChange]); /** * This array will contain all of the `unselected` encoders, diff --git a/packages/console/src/Components/EditPage/EditPage.tsx b/packages/console/src/Components/EditPage/EditPage.tsx index 4bb2abd1..e56c7ea5 100644 --- a/packages/console/src/Components/EditPage/EditPage.tsx +++ b/packages/console/src/Components/EditPage/EditPage.tsx @@ -13,9 +13,6 @@ import Tabs from "../Tabs/Tabs.tsx"; import type { ITab } from "../Tabs/Tabs.types"; import * as Style from "./EditPage.style"; -/** - * Props. - */ interface IEditPageProps { /** * ID of the resource if the edit page is for a resource. @@ -133,9 +130,6 @@ function EditPage(props: IEditPageProps) { tabIndex, } = props; - /** - * Saves the record. - */ const save = async () => { const validated = await onValidate?.(); if (!validated) { @@ -150,9 +144,6 @@ function EditPage(props: IEditPageProps) { } }; - /** - * Renders the tabs render. - */ const renderTabs = () => { return ( (props: IEditPageProps) { ); }; - /** - * Renders the footer with the `Back` and `Save` buttons. - */ const renderFooter = () => { let saveDisabled = false; @@ -212,8 +200,7 @@ function EditPage(props: IEditPageProps) { ); }; - /** - */ + // biome-ignore lint/correctness/useExhaustiveDependencies(id): useEffect state machine useEffect(() => { if (loaded.current) { setInternalLoading(true); @@ -225,6 +212,7 @@ function EditPage(props: IEditPageProps) { /** * Used to fetch the record and assign the initial data. */ + // biome-ignore lint/correctness/useExhaustiveDependencies(id): useEffect state machine useEffect(() => { if (data && !loaded.current) { setInternalLoading(false); @@ -233,9 +221,6 @@ function EditPage(props: IEditPageProps) { } }, [onFetch, id, data]); - /** - * Sets the document title. - */ useEffect(() => { if (documentTitle) { setDocumentTitle(documentTitle); diff --git a/packages/console/src/Components/Home/Statistics/Statistics.tsx b/packages/console/src/Components/Home/Statistics/Statistics.tsx index 461b1f57..591f45d3 100644 --- a/packages/console/src/Components/Home/Statistics/Statistics.tsx +++ b/packages/console/src/Components/Home/Statistics/Statistics.tsx @@ -43,6 +43,7 @@ function Statistics() { /** * Attaches and detaches the socket to get the statistic updates in realtime. */ + // biome-ignore lint/correctness/useExhaustiveDependencies(store.socketConnected): mobx observer useEffect(() => { if (store.socketConnected) { getSocket().emit("attach", "statistic"); @@ -50,7 +51,6 @@ function Statistics() { getSocket().emit("unattach", "statistic"); }; } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [store.socketConnected]); /** diff --git a/packages/console/src/Components/InputTime/InputTime.tsx b/packages/console/src/Components/InputTime/InputTime.tsx index aee5fab3..004fe8cf 100644 --- a/packages/console/src/Components/InputTime/InputTime.tsx +++ b/packages/console/src/Components/InputTime/InputTime.tsx @@ -1,5 +1,5 @@ import { DateTime } from "luxon"; -import { useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import Select from "../Select/Select.tsx"; import * as Style from "./InputTime.style"; @@ -11,7 +11,10 @@ interface IInputTime { function InputTime(props: IInputTime) { const firstRender = useRef(true); - const usesAmPmFormat = props.timeFormat === "12"; + const usesAmPmFormat = useMemo( + () => props.timeFormat === "12", + [props.timeFormat], + ); const defaultValue = `2010-01-01 ${props.value || ""}`; const [hour, setHour] = useState(() => DateTime.fromFormat(defaultValue, "yyyy-LL-dd HH:mm").toFormat( @@ -41,13 +44,22 @@ function InputTime(props: IInputTime) { * Triggers change to the input outside. * This function will format the date using the time that we selected and the time format as well. */ - function triggerChange() { - if (usesAmPmFormat) { - props.onChange(`${hour || "00"}:${minute || "00"} ${format}`); - } else { - props.onChange(`${hour || "00"}:${minute || "00"}`); - } - } + const triggerChange = useCallback( + (params: { + hour: string; + minute: string; + format: string; + }) => { + if (usesAmPmFormat) { + props.onChange( + `${params.hour || "00"}:${params.minute || "00"} ${params.format}`, + ); + } else { + props.onChange(`${params.hour || "00"}:${params.minute || "00"}`); + } + }, + [usesAmPmFormat, props.onChange], + ); /** * Uses to trigger a change to the input outside if the hour, minute or time format has changed. @@ -55,11 +67,10 @@ function InputTime(props: IInputTime) { */ useEffect(() => { if (!firstRender.current) { - triggerChange(); + triggerChange({ hour, minute, format }); } firstRender.current = false; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [hour, minute, format]); + }, [hour, minute, format, triggerChange]); return ( diff --git a/packages/console/src/Components/Logs/Logs.tsx b/packages/console/src/Components/Logs/Logs.tsx index 40ab2949..b1622d59 100644 --- a/packages/console/src/Components/Logs/Logs.tsx +++ b/packages/console/src/Components/Logs/Logs.tsx @@ -173,7 +173,7 @@ function Logs() { navigate(`/console/logs?channel=${selectedChannel}&type=${selectedType}`, { replace: true, }); - }, [selectedChannel, selectedType]); + }, [navigate, selectedChannel, selectedType]); return ( diff --git a/packages/console/src/Components/Modal/Modal.tsx b/packages/console/src/Components/Modal/Modal.tsx index 227e964b..63d058d0 100644 --- a/packages/console/src/Components/Modal/Modal.tsx +++ b/packages/console/src/Components/Modal/Modal.tsx @@ -217,11 +217,11 @@ function Modal(props: IModalProps) { ); }; + // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect state machine useEffect(() => { if (shouldClose) { onClose?.(); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [shouldClose]); return createPortal( diff --git a/packages/console/src/Components/ModalFileSelect/ModalFileSelect.tsx b/packages/console/src/Components/ModalFileSelect/ModalFileSelect.tsx index 6b811ef1..a51b8797 100644 --- a/packages/console/src/Components/ModalFileSelect/ModalFileSelect.tsx +++ b/packages/console/src/Components/ModalFileSelect/ModalFileSelect.tsx @@ -292,11 +292,8 @@ function ModalFileSelect(props: IModalFileSelect) { refFilesContainer.current.scrollTop = (max as any)?.ref.offsetTop; } } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [files.length]); + }, [files, value]); - /** - */ useEffect(() => { if (files.length > 0) { setPath(value); diff --git a/packages/console/src/Components/PaginatedTable/PaginatedTable.tsx b/packages/console/src/Components/PaginatedTable/PaginatedTable.tsx index bfc11dc8..262c3729 100644 --- a/packages/console/src/Components/PaginatedTable/PaginatedTable.tsx +++ b/packages/console/src/Components/PaginatedTable/PaginatedTable.tsx @@ -9,9 +9,6 @@ import TooltipText from "../TooltipText/TooltipText.tsx"; import * as Style from "./PaginatedTable.style"; import type { IColumn, IFilter } from "./PaginatedTable.types"; -/** - * Props. - */ interface IPaginatedTableProps { /** * The configuration for the columns. @@ -59,25 +56,13 @@ interface IPaginatedTableProps { * Shows page number or not. */ infinitePages?: boolean; - /** - */ showConfigButton?: boolean; - /** - */ onConfigButtonClick?: () => void; - /** - */ refetchID?: number; - /** - */ showRefreshButton?: boolean; - /** - */ onRefreshButtonClick?: () => void; } -/** - */ function PaginatedTable(props: IPaginatedTableProps) { const [data, setData] = useState([]); const [error, setError] = useState(""); @@ -106,17 +91,11 @@ function PaginatedTable(props: IPaginatedTableProps) { const filterTimeout = useRef>(); const firstRender = useRef(true); - /** - * Called when one of the filter changes values. - */ const onChangeFilter = (column: IColumn, text: any) => { setFilter({ ...filter, [column.id]: text }); column.onFilter?.(text, column); }; - /** - * Renders a header cell. - */ const renderHeaderCell = (column: IColumn) => { const flex = column.flex || "1"; const width = column.width || "auto"; @@ -140,9 +119,6 @@ function PaginatedTable(props: IPaginatedTableProps) { ); }; - /** - * Renders a header cell. - */ const renderFilter = (column: IColumn) => { const filterDisabled = column.filterDisabled || column.type === "date"; return ( @@ -173,9 +149,6 @@ function PaginatedTable(props: IPaginatedTableProps) { ); }; - /** - * Renders a row cell. - */ const renderRowCell = (item: T, column: IColumn, rowIndex: number) => { const flex = column.flex || "1"; const width = column.width || "auto"; @@ -190,9 +163,6 @@ function PaginatedTable(props: IPaginatedTableProps) { ); }; - /** - * Renders a single row. - */ const renderRow = (item: T, rowIndex: number) => { const link = onGetRowLink?.(item) as string; @@ -214,9 +184,6 @@ function PaginatedTable(props: IPaginatedTableProps) { ); }; - /** - * Renders the empty message in the center of the table if there are no records in it. - */ const renderEmptyMessage = () => { if (!emptyMessage) { return null; @@ -226,9 +193,6 @@ function PaginatedTable(props: IPaginatedTableProps) { ); }; - /** - * Gets the ideal amount of rows to be rendered. - */ const getIdealAmountOfRows = () => { const node = rowsNode.current as HTMLDivElement; if (node) { @@ -241,8 +205,7 @@ function PaginatedTable(props: IPaginatedTableProps) { return 0; }; - /** - */ + // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect state machine const fetchPageData = useCallback(async () => { if (!rowsNode.current) { return; @@ -261,30 +224,24 @@ function PaginatedTable(props: IPaginatedTableProps) { } }, [page, filter, onGetData]); - /** - */ + // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect state machine useEffect(() => { fetchPageData(); - // eslint-disable-next-line react-hooks/exhaustive-deps }, [page]); - /** - */ + // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect state machine useEffect(() => { if (!firstRender.current) { filterTimeout.current = setTimeout(fetchPageData, 300); - return () => clearTimeout(filterTimeout.current as unknown as number); + return () => clearTimeout(filterTimeout.current); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [filter]); - /** - */ + // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect state machine useEffect(() => { if (!firstRender.current && refetchID) { fetchPageData(); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [refetchID]); /** @@ -292,6 +249,7 @@ function PaginatedTable(props: IPaginatedTableProps) { * of the table. The amount of pages will be set in a state for future use in * the footer component. */ + // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect state machine useEffect(() => { if (!infinitePages) { const idealAmount = getIdealAmountOfRows(); @@ -299,7 +257,6 @@ function PaginatedTable(props: IPaginatedTableProps) { setPageAmount(total); fetchPageData(); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [amountOfRecords]); /** diff --git a/packages/console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.tsx b/packages/console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.tsx index 655fc0d1..15590ccb 100644 --- a/packages/console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.tsx +++ b/packages/console/src/Components/Plugins/Common/ModalInstallPlugin/ModalInstallPlugin.tsx @@ -11,22 +11,11 @@ import { EIcon } from "../../../Icon/Icon.types"; import Modal from "../../../Modal/Modal.tsx"; import * as Style from "./ModalInstallPlugin.style"; -/** - * Props. - */ interface IModalInstallPlugin { - /** - * Called when the modal is closed. - */ - onClose: (pluginID: string) => void; - /** - * The file path for the plugin that will be installed. - */ + /** The file path for the plugin that will be installed. */ source: string; - /** - * Name of the plugin or the file that is being installed. Purely visual. - */ pluginName?: string; + onClose: (pluginID: string) => void; } /** @@ -94,6 +83,7 @@ function ModalInstallPlugin(props: IModalInstallPlugin) { /** * Attaches and detaches the plugin to get the logs during installation. */ + // biome-ignore lint/correctness/useExhaustiveDependencies(store.socketConnected): mobx observer useEffect(() => { if (store.socketConnected) { getSocket().emit("attach", "install"); @@ -101,7 +91,6 @@ function ModalInstallPlugin(props: IModalInstallPlugin) { getSocket().emit("unattach", "install"); }; } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [store.socketConnected]); /** diff --git a/packages/console/src/Components/Plugins/Common/ModalUploadPlugin/ModalUploadPlugin.tsx b/packages/console/src/Components/Plugins/Common/ModalUploadPlugin/ModalUploadPlugin.tsx index 9430a887..18dd5d66 100644 --- a/packages/console/src/Components/Plugins/Common/ModalUploadPlugin/ModalUploadPlugin.tsx +++ b/packages/console/src/Components/Plugins/Common/ModalUploadPlugin/ModalUploadPlugin.tsx @@ -5,27 +5,18 @@ import store from "../../../../System/Store.ts"; import Modal from "../../../Modal/Modal.tsx"; import * as Style from "./ModalUploadPlugin.style"; -/** - * Props. - */ interface IModalUploadPlugin { onClose: () => void; onUpload: (filepath: string) => void; file: File; } -/** - * Modal to upload a plugin file. - */ function ModalUploadPlugin(props: IModalUploadPlugin) { const [error, setError] = useState(false); const [progress, setProgress] = useState(0); const { file, onClose, onUpload } = props; - /** - * Uploads the file and returns the source as the call from the API. - */ const uploadFile = useCallback(async () => { if (!file) { return; @@ -54,12 +45,9 @@ function ModalUploadPlugin(props: IModalUploadPlugin) { } }, [onClose, onUpload, error, file]); - /** - */ useEffect(() => { uploadFile(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [uploadFile]); return ( Promise; } -/** - */ function ModuleStatus(props: IModuleStatusProps) { const { data, module, onStop, onStart } = props; const [state, setState] = useState(() => module.state); const { error } = module; const theme = useTheme(); - /** - * Starts the service. - */ - const start = useCallback(() => { + const startService = useCallback(() => { setState("starting"); setTimeout(onStart, 200); }, [onStart]); - /** - * Stops the service. - */ - const stop = useCallback(() => { + const stopService = useCallback(() => { setState("stopping"); setTimeout(onStop, 200); }, [onStop]); - /** - */ + // biome-ignore lint/correctness/useExhaustiveDependencies(state): useEffect state machine useEffect(() => { if (module.state !== state) { setState(module.state); - // setState("starting"); - // timeout.current = setTimeout(() => setState(module.state), 200); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [module.state]); const pluginRunning = data.state === "started"; @@ -83,13 +65,13 @@ function ModuleStatus(props: IModuleStatusProps) {