diff --git a/public/manifest.json b/public/manifest.json index 080d6c7..ec8d29c 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "React App", - "name": "Create React App Sample", + "short_name": "Farm Control", + "name": "Farm Control", "icons": [ { "src": "favicon.ico", diff --git a/src/components/Dashboard/Inventory/FilamentStocks/LoadFilamentStock.jsx b/src/components/Dashboard/Inventory/FilamentStocks/LoadFilamentStock.jsx index d67ca90..e43b17b 100644 --- a/src/components/Dashboard/Inventory/FilamentStocks/LoadFilamentStock.jsx +++ b/src/components/Dashboard/Inventory/FilamentStocks/LoadFilamentStock.jsx @@ -76,7 +76,7 @@ const LoadFilamentStock = ({ if (filamentStockEventUnsubscribe) filamentStockEventUnsubscribe() } } - }, [printer?._id, connected]) + }, [printer?._id, connected, subscribeToObjectEvent]) useEffect(() => { // Validate form fields diff --git a/src/components/Dashboard/Inventory/FilamentStocks/UnloadFilamentStock.jsx b/src/components/Dashboard/Inventory/FilamentStocks/UnloadFilamentStock.jsx index 910769e..ea49d7e 100644 --- a/src/components/Dashboard/Inventory/FilamentStocks/UnloadFilamentStock.jsx +++ b/src/components/Dashboard/Inventory/FilamentStocks/UnloadFilamentStock.jsx @@ -60,7 +60,7 @@ const UnloadFilamentStock = ({ onOk, reset, printer = null }) => { if (filamentStockEventUnsubscribe) filamentStockEventUnsubscribe() } } - }, [printer?._id, connected]) + }, [printer?._id, connected, subscribeToObjectEvent]) useEffect(() => { if (reset) { diff --git a/src/components/Dashboard/Management/Hosts/HostOtp.jsx b/src/components/Dashboard/Management/Hosts/HostOtp.jsx index a5c13d0..2b7f733 100644 --- a/src/components/Dashboard/Management/Hosts/HostOtp.jsx +++ b/src/components/Dashboard/Management/Hosts/HostOtp.jsx @@ -1,5 +1,5 @@ import PropTypes from 'prop-types' -import { useContext, useEffect, useState, useRef } from 'react' +import { useContext, useEffect, useState, useRef, useCallback } from 'react' import { Input, Result, Typography, Flex, Progress } from 'antd' import { LoadingOutlined } from '@ant-design/icons' import { ApiServerContext } from '../../context/ApiServerContext' @@ -17,7 +17,7 @@ const HostOTP = ({ id }) => { const [initialized, setInitialized] = useState(false) const intervalRef = useRef(null) - const fetchNewOTP = () => { + const fetchNewOTP = useCallback(() => { setLoading(true) setHostObject(null) // Reset to show loading fetchHostOTP(id, (hostOTPObject) => { @@ -33,14 +33,14 @@ const HostOTP = ({ id }) => { setTotalTime(remaining) } }) - } + }, [id, fetchHostOTP]) useEffect(() => { if (hostObject === null && initialized == false) { setInitialized(true) fetchNewOTP() } - }, [id]) + }, [id, fetchNewOTP, initialized, hostObject]) useEffect(() => { if (hostObject && timeRemaining > 0) { @@ -62,7 +62,7 @@ const HostOTP = ({ id }) => { } } } - }, [hostObject, timeRemaining]) + }, [hostObject, timeRemaining, fetchNewOTP]) // Clean up interval on unmount useEffect(() => { diff --git a/src/components/Dashboard/Production/Jobs/DeployJob.jsx b/src/components/Dashboard/Production/Jobs/DeployJob.jsx index 2555a63..64a615c 100644 --- a/src/components/Dashboard/Production/Jobs/DeployJob.jsx +++ b/src/components/Dashboard/Production/Jobs/DeployJob.jsx @@ -1,4 +1,4 @@ -import { useState, useContext, useEffect } from 'react' +import { useState, useContext, useEffect, useCallback } from 'react' import PropTypes from 'prop-types' import WizardView from '../../common/WizardView' import { ApiServerContext } from '../../context/ApiServerContext' @@ -15,7 +15,7 @@ const DeployJob = ({ onOk, objectData = undefined }) => { const [subJobsCount, setSubJobsCount] = useState(999) const { sendObjectAction, fetchObjects } = useContext(ApiServerContext) - const handleDeploy = async () => { + const handleDeploy = useCallback(async () => { setDeployLoading(true) var hasMore = true var currentPage = 1 @@ -50,13 +50,13 @@ const DeployJob = ({ onOk, objectData = undefined }) => { } ) }) - } + }, [job._id, sendObjectAction, fetchObjects]) useEffect(() => { if (deployedSubJobsCount == subJobsCount && deployLoading == true) { onOk() } - }, [deployedSubJobsCount, subJobsCount, deployLoading]) + }, [deployedSubJobsCount, subJobsCount, deployLoading, onOk]) const steps = [ { diff --git a/src/components/Dashboard/common/DashboardNavigation.jsx b/src/components/Dashboard/common/DashboardNavigation.jsx index 79799b2..597f7d3 100644 --- a/src/components/Dashboard/common/DashboardNavigation.jsx +++ b/src/components/Dashboard/common/DashboardNavigation.jsx @@ -1,5 +1,5 @@ // DashboardNavigation.js -import { useContext, useEffect, useState } from 'react' +import { useContext, useEffect, useState, useMemo } from 'react' import { Menu, Flex, @@ -59,28 +59,31 @@ const DashboardNavigation = () => { const isMobile = useMediaQuery({ maxWidth: 768 }) const { platform, isElectron, isFullScreen } = useContext(ElectronContext) - const mainMenuItems = [ - { - key: 'production', - label: 'Production', - icon: - }, - { - key: 'inventory', - label: 'Inventory', - icon: - }, - { - key: 'finance', - label: 'Finance', - icon: - }, - { - key: 'management', - label: 'Management', - icon: - } - ] + const mainMenuItems = useMemo( + () => [ + { + key: 'production', + label: 'Production', + icon: + }, + { + key: 'inventory', + label: 'Inventory', + icon: + }, + { + key: 'finance', + label: 'Finance', + icon: + }, + { + key: 'management', + label: 'Management', + icon: + } + ], + [] + ) const userMenuItems = { items: [ @@ -119,7 +122,7 @@ const DashboardNavigation = () => { ) setSelectedKey(pathParts[1]) // Return the section (production/management) } - }, [location.pathname]) + }, [location.pathname, mainMenuItems]) useEffect(() => { if (connecting == true) { diff --git a/src/components/Dashboard/common/DataTree.jsx b/src/components/Dashboard/common/DataTree.jsx index aa47749..fb6981c 100644 --- a/src/components/Dashboard/common/DataTree.jsx +++ b/src/components/Dashboard/common/DataTree.jsx @@ -1,6 +1,6 @@ import PropTypes from 'prop-types' import { Tree, Typography, Space, Tag } from 'antd' -import { useState, useMemo } from 'react' +import { useState, useMemo, useCallback } from 'react' import XMarkIcon from '../../Icons/XMarkIcon' import QuestionCircleIcon from '../../Icons/QuestionCircleIcon' import JsonStringIcon from '../../Icons/JsonStringIcon' @@ -48,7 +48,7 @@ const DataTree = ({ } // Function to format value for display - const formatValue = (value) => { + const formatValue = useCallback((value) => { if (value === null) return 'null' if (value === undefined) return 'undefined' if (typeof value === 'boolean') return value.toString() @@ -63,10 +63,10 @@ const DataTree = ({ return `Object (${keys.length} properties)` } return String(value) - } + }, []) // Function to get raw value for copying - const getCopyValue = (value) => { + const getCopyValue = useCallback((value) => { if (value === null) return 'null' if (value === undefined) return 'undefined' if (typeof value === 'boolean') return value.toString() @@ -75,64 +75,67 @@ const DataTree = ({ if (Array.isArray(value)) return JSON.stringify(value, null, 2) if (typeof value === 'object') return JSON.stringify(value, null, 2) return String(value) - } + }, []) // Recursive function to convert JSON to tree data - const convertToTreeData = (obj, key = 'root', path = '') => { - const currentPath = path ? `${path}.${key}` : key - const dataInfo = getDataTypeInfo(obj) + const convertToTreeData = useCallback( + (obj, key = 'root', path = '') => { + const currentPath = path ? `${path}.${key}` : key + const dataInfo = getDataTypeInfo(obj) - const node = { - title: ( - - - {dataInfo.icon} - - {key} - {showKeyCopy && ( - - )} - ({dataInfo.type}) - {dataInfo.type !== 'object' && dataInfo.type !== 'array' && ( - <> - {formatValue(obj)} - {showValueCopy && ( + const node = { + title: ( + + + {dataInfo.icon} + + {key} + {showKeyCopy && ( + + )} + ({dataInfo.type}) + {dataInfo.type !== 'object' && dataInfo.type !== 'array' && ( + <> + {formatValue(obj)} + {showValueCopy && ( + + )} + + )} + {(dataInfo.type === 'object' || dataInfo.type === 'array') && + showValueCopy && ( )} - - )} - {(dataInfo.type === 'object' || dataInfo.type === 'array') && - showValueCopy && ( - - )} - - ), - key: currentPath, - value: obj, - path: currentPath - } - - // Add children for objects and arrays - if (typeof obj === 'object' && obj !== null) { - if (Array.isArray(obj)) { - node.children = obj.map((item, index) => - convertToTreeData(item, `[${index}]`, currentPath) - ) - } else { - node.children = Object.entries(obj).map(([childKey, childValue]) => - convertToTreeData(childValue, childKey, currentPath) - ) + + ), + key: currentPath, + value: obj, + path: currentPath } - } - return node - } + // Add children for objects and arrays + if (typeof obj === 'object' && obj !== null) { + if (Array.isArray(obj)) { + node.children = obj.map((item, index) => + convertToTreeData(item, `[${index}]`, currentPath) + ) + } else { + node.children = Object.entries(obj).map(([childKey, childValue]) => + convertToTreeData(childValue, childKey, currentPath) + ) + } + } + + return node + }, + [showValueCopy, getCopyValue, formatValue, showKeyCopy] + ) // Convert data to tree structure const treeData = useMemo(() => { @@ -171,7 +174,7 @@ const DataTree = ({ } ] } - }, [data]) + }, [data, showValueCopy, convertToTreeData, getCopyValue, formatValue]) // Handle node selection const handleSelect = (selectedKeys, { selected, selectedNodes }) => { diff --git a/src/components/Dashboard/common/FilePreview.jsx b/src/components/Dashboard/common/FilePreview.jsx index 4aab4e1..0091b66 100644 --- a/src/components/Dashboard/common/FilePreview.jsx +++ b/src/components/Dashboard/common/FilePreview.jsx @@ -18,7 +18,7 @@ const FilePreview = ({ file, style = {} }) => { const objectUrl = await fetchFileContent(file, false) setFileObjectUrl(objectUrl) setLoading(false) - }, [file._id, fetchFileContent]) + }, [file, fetchFileContent]) useEffect(() => { if (file?.type && token != null) { diff --git a/src/components/Dashboard/common/GCodePreview.jsx b/src/components/Dashboard/common/GCodePreview.jsx index 00dfee7..c743881 100644 --- a/src/components/Dashboard/common/GCodePreview.jsx +++ b/src/components/Dashboard/common/GCodePreview.jsx @@ -42,7 +42,14 @@ function GCodePreviewUI(props) { return () => { window.removeEventListener('resize', resizePreview) } - }, [endLayer, lastSegmentColor, lineWidth, startLayer, topLayerColor]) + }, [ + endLayer, + lastSegmentColor, + lineWidth, + startLayer, + topLayerColor, + resizePreview + ]) useEffect(() => { const loadFromSrc = async () => { diff --git a/src/components/Dashboard/common/KeyboardShortcut.jsx b/src/components/Dashboard/common/KeyboardShortcut.jsx index 1c7a54b..515966b 100644 --- a/src/components/Dashboard/common/KeyboardShortcut.jsx +++ b/src/components/Dashboard/common/KeyboardShortcut.jsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, cloneElement } from 'react' +import { useEffect, useRef, cloneElement, useCallback } from 'react' import PropTypes from 'prop-types' import { Popover, Typography } from 'antd' @@ -24,10 +24,9 @@ const { Text } = Typography const KeyboardShortcut = ({ shortcut, children, hint, onTrigger }) => { const childRef = useRef() const shortcutObj = parseShortcut(shortcut) - let pressedKeys = new Set() // Helper to get the set of keys required for the shortcut - function getShortcutKeySet(shortcutObj) { + const getShortcutKeySet = useCallback((shortcutObj) => { const keys = [] if (shortcutObj.meta) keys.push('Meta') if (shortcutObj.ctrl) keys.push('Control') @@ -38,12 +37,12 @@ const KeyboardShortcut = ({ shortcut, children, hint, onTrigger }) => { keys.push('Key' + shortcutObj.key.toUpperCase()) } return new Set(keys) - } + }, []) const shortcutKeySet = getShortcutKeySet(shortcutObj) useEffect(() => { - pressedKeys = new Set() + const pressedKeys = new Set() const handleKeyDown = (event) => { if ( event.key === 'Meta' || @@ -83,7 +82,7 @@ const KeyboardShortcut = ({ shortcut, children, hint, onTrigger }) => { window.removeEventListener('keydown', handleKeyDown) window.removeEventListener('keyup', handleKeyUp) } - }, [shortcut, shortcutObj, onTrigger]) + }, [shortcut, shortcutObj, onTrigger, shortcutKeySet]) // Clone the child to attach a ref const element = cloneElement(children, { ref: childRef }) diff --git a/src/components/Dashboard/common/ObjectChildTable.jsx b/src/components/Dashboard/common/ObjectChildTable.jsx index c9a8d56..f3301ea 100644 --- a/src/components/Dashboard/common/ObjectChildTable.jsx +++ b/src/components/Dashboard/common/ObjectChildTable.jsx @@ -272,7 +272,7 @@ const ObjectChildTable = ({ }) return [summaryRow] - }, [properties, rollups, objectData]) + }, [properties, rollups, objectData, value]) const rollupColumns = useMemo(() => { const propertyColumns = properties.map((property, index) => { diff --git a/src/components/Dashboard/common/ObjectSelect.jsx b/src/components/Dashboard/common/ObjectSelect.jsx index 1602c3c..9fb71b1 100644 --- a/src/components/Dashboard/common/ObjectSelect.jsx +++ b/src/components/Dashboard/common/ObjectSelect.jsx @@ -340,28 +340,31 @@ const ObjectSelect = ({ }) } - const onTreeSelectChange = (value) => { - // Mark this as an internal change - isInternalChangeRef.current = true + const onTreeSelectChange = useCallback( + (value) => { + // Mark this as an internal change + isInternalChangeRef.current = true - // value can be a string (single) or array (multiple) - if (multiple) { - // Multiple selection - let selectedObjects = [] - if (Array.isArray(value)) { - selectedObjects = value - .map((id) => objectList.find((obj) => obj._id === id)) - .filter(Boolean) + // value can be a string (single) or array (multiple) + if (multiple) { + // Multiple selection + let selectedObjects = [] + if (Array.isArray(value)) { + selectedObjects = value + .map((id) => objectList.find((obj) => obj._id === id)) + .filter(Boolean) + } + setTreeSelectValue(value) + if (rest.onChange) rest.onChange(selectedObjects) + } else { + // Single selection + const selectedObject = objectList.find((obj) => obj._id === value) + setTreeSelectValue(value) + if (rest.onChange) rest.onChange(selectedObject) } - setTreeSelectValue(value) - if (rest.onChange) rest.onChange(selectedObjects) - } else { - // Single selection - const selectedObject = objectList.find((obj) => obj._id === value) - setTreeSelectValue(value) - if (rest.onChange) rest.onChange(selectedObject) - } - } + }, + [multiple, objectList, rest] + ) // Update treeData when objectPropertiesTree changes useEffect(() => { @@ -494,7 +497,7 @@ const ObjectSelect = ({ setError(false) prevValuesRef.current = { type, masterFilter } } - }, [type, masterFilter]) + }, [type, masterFilter, onTreeSelectChange]) useEffect(() => { // Check if value has actually changed @@ -519,7 +522,7 @@ const ObjectSelect = ({ prevValueRef.current = value prevValueIdentityRef.current = currentValueIdentity } - }, [value, getValueIdentity]) + }, [value, getValueIdentity, type, masterFilter]) const placeholder = useMemo( () => diff --git a/src/components/Dashboard/common/PrinterMiscPanel.jsx b/src/components/Dashboard/common/PrinterMiscPanel.jsx index eb815a4..807bf7d 100644 --- a/src/components/Dashboard/common/PrinterMiscPanel.jsx +++ b/src/components/Dashboard/common/PrinterMiscPanel.jsx @@ -16,7 +16,6 @@ const PrinterMiscPanel = ({ id, showControls = true }) => { target: 0 }, lcdBacklight: { - // eslint-disable-line camelcase brightness: 0 }, beeper: { diff --git a/src/components/Dashboard/common/PrinterPositionPanel.jsx b/src/components/Dashboard/common/PrinterPositionPanel.jsx index 17a671f..8520c42 100644 --- a/src/components/Dashboard/common/PrinterPositionPanel.jsx +++ b/src/components/Dashboard/common/PrinterPositionPanel.jsx @@ -38,14 +38,14 @@ const PrinterPositionPanel = ({ const { subscribeToObjectEvent, connected, sendObjectAction } = useContext(ApiServerContext) const [positionData, setPositionData] = useState({ - speedFactor: 1.0, // eslint-disable-line + speedFactor: 1.0, speed: 100, - extrudeFactor: 1.0, // eslint-disable-line - absoluteCoordinates: true, // eslint-disable-line - absoluteExtrude: false, // eslint-disable-line - homingOrigin: [0.0, 0.0, 0.0, 0.0], // eslint-disable-line + extrudeFactor: 1.0, + absoluteCoordinates: true, + absoluteExtrude: false, + homingOrigin: [0.0, 0.0, 0.0, 0.0], toolheadPosition: [0.0, 0.0, 0.0, 0.0], - gcodePosition: [0.0, 0.0, 0.0, 0.0], // eslint-disable-line + gcodePosition: [0.0, 0.0, 0.0, 0.0], livePosition: [0.0, 0.0, 0.0, 0.0], maxVelocity: 1000, maxAcceleration: 1000, @@ -70,7 +70,7 @@ const PrinterPositionPanel = ({ if (motionEventUnsubscribe) motionEventUnsubscribe() } } - }, [id, connected]) + }, [id, connected, subscribeToObjectEvent]) const [speedFactor, setSpeedFactor] = useState(positionData.speedFactor) const [extrudeFactor, setExtrudeFactor] = useState(positionData.extrudeFactor) const [maxVelocity, setMaxVelocity] = useState(positionData.maxVelocity) diff --git a/src/components/Dashboard/common/PrinterTemperaturePanel.jsx b/src/components/Dashboard/common/PrinterTemperaturePanel.jsx index b38375a..965c6da 100644 --- a/src/components/Dashboard/common/PrinterTemperaturePanel.jsx +++ b/src/components/Dashboard/common/PrinterTemperaturePanel.jsx @@ -87,7 +87,7 @@ const PrinterTemperaturePanel = ({ if (temperatureEventUnsubscribe) temperatureEventUnsubscribe() } } - }, [id, connected]) + }, [id, connected, subscribeToObjectEvent]) const [extruderTarget, setExtruderTarget] = useState(0) const [bedTarget, setBedTarget] = useState(0) diff --git a/src/components/Dashboard/common/TemplatePreview.jsx b/src/components/Dashboard/common/TemplatePreview.jsx index 4423a29..ee004f8 100644 --- a/src/components/Dashboard/common/TemplatePreview.jsx +++ b/src/components/Dashboard/common/TemplatePreview.jsx @@ -44,22 +44,25 @@ const TemplatePreview = ({ } } - const reloadPreviewPDF = (content, testObject = {}) => { - setReloadLoading(true) - fetchTemplatePDF(documentTemplate._id, content, testObject, (result) => { - setReloadLoading(false) - if (result?.error) { - // Handle error through parent component - onPreviewMessage(result.error, true) - } else { - const pdfBlob = new Blob([result.pdf], { type: 'application/pdf' }) - const pdfUrl = URL.createObjectURL(pdfBlob) + const reloadPreviewPDF = useCallback( + (content, testObject = {}) => { + setReloadLoading(true) + fetchTemplatePDF(documentTemplate._id, content, testObject, (result) => { + setReloadLoading(false) + if (result?.error) { + // Handle error through parent component + onPreviewMessage(result.error, true) + } else { + const pdfBlob = new Blob([result.pdf], { type: 'application/pdf' }) + const pdfUrl = URL.createObjectURL(pdfBlob) - setPDFBlob(pdfUrl) - onPreviewMessage('No issues found.', false) - } - }) - } + setPDFBlob(pdfUrl) + onPreviewMessage('No issues found.', false) + } + }) + }, + [documentTemplate?._id, fetchTemplatePDF, onPreviewMessage] + ) const reloadPreview = useCallback( (content, testObject = {}, scale = 1) => { @@ -81,7 +84,7 @@ const TemplatePreview = ({ } ) }, - [fetchTemplatePreview, objectData?._id, onPreviewMessage] + [fetchTemplatePreview, onPreviewMessage, documentTemplate?._id] ) // Move useEffect to component level and use state to track objectData changes @@ -93,7 +96,14 @@ const TemplatePreview = ({ reloadPreviewPDF(documentTemplate.content, objectData) } } - }, [objectData, documentTemplate, previewScale, previewType]) + }, [ + objectData, + documentTemplate, + previewScale, + previewType, + reloadPreview, + reloadPreviewPDF + ]) return ( diff --git a/src/components/Dashboard/common/ThreeDPreview.jsx b/src/components/Dashboard/common/ThreeDPreview.jsx index 20f19d1..d80ab9e 100644 --- a/src/components/Dashboard/common/ThreeDPreview.jsx +++ b/src/components/Dashboard/common/ThreeDPreview.jsx @@ -10,10 +10,7 @@ function ThreeDPreview(props) { width = 500, height = 500, style = {}, - backgroundColor = '#ffffff', - showGrid = true, - showAxes = true, - enableControls = true + backgroundColor = '#ffffff' } = props const containerRef = useRef(null) const viewer = useRef(null) @@ -34,6 +31,9 @@ function ThreeDPreview(props) { }, [viewer, width, height]) useEffect(() => { + // Variable to track the viewer instance created in this effect + let currentViewer = null + const initializeViewer = async () => { if (!containerRef.current) return @@ -42,7 +42,10 @@ function ThreeDPreview(props) { setError(null) // Clear any existing viewer - if (viewer) { + if (viewer.current) { + if (viewer.current.dispose) { + viewer.current.dispose() + } containerRef.current.innerHTML = '' } @@ -71,6 +74,10 @@ function ThreeDPreview(props) { environmentSettings: new OV.EnvironmentSettings([], false) }) + // Store the viewer instance in the ref and local variable + viewer.current = newViewer + currentViewer = newViewer + try { setIsLoading(true) setError(null) @@ -105,11 +112,11 @@ function ThreeDPreview(props) { return () => { window.removeEventListener('resize', resizeViewer) - if (viewer.current && viewer.current.dispose) { - viewer.current.dispose() + if (currentViewer && currentViewer.dispose) { + currentViewer.dispose() } } - }, [width, height, backgroundColor, showGrid, showAxes, enableControls, src]) + }, [width, height, src, extension, resizeViewer]) const containerStyle = { width: width + 'px', diff --git a/src/components/Dashboard/context/ApiServerContext.jsx b/src/components/Dashboard/context/ApiServerContext.jsx index bf4ea75..2c3c3fa 100644 --- a/src/components/Dashboard/context/ApiServerContext.jsx +++ b/src/components/Dashboard/context/ApiServerContext.jsx @@ -8,7 +8,7 @@ import { useCallback } from 'react' import io from 'socket.io-client' -import { message, notification, Modal, Space, Button } from 'antd' +import { message, Modal, Space, Button } from 'antd' import PropTypes from 'prop-types' import { AuthContext } from './AuthContext' @@ -30,7 +30,6 @@ const ApiServerProvider = ({ children }) => { const [connecting, setConnecting] = useState(false) const [error, setError] = useState(null) const [messageApi, contextHolder] = message.useMessage() - const [notificationApi] = notification.useNotification() const [fetchLoading, setFetchLoading] = useState(false) const [showErrorModal, setShowErrorModal] = useState(false) const [errorModalContent, setErrorModalContent] = useState('') @@ -125,7 +124,7 @@ const ApiServerProvider = ({ children }) => { socketRef.current = newSocket } - }, [token, authenticated, messageApi, notificationApi, handleLockUpdate]) + }, [token, authenticated, messageApi, handleLockUpdate, clearSubscriptions]) useEffect(() => { if (token && authenticated == true) { @@ -539,7 +538,7 @@ const ApiServerProvider = ({ children }) => { return () => offObjectEventEvent(id, objectType, eventType, callback) } }, - [offObjectUpdatesEvent] + [offObjectEventEvent] ) const offModelStats = useCallback((objectType, callback) => { diff --git a/src/components/Dashboard/context/AuthContext.jsx b/src/components/Dashboard/context/AuthContext.jsx index 58b49a4..b65e93c 100644 --- a/src/components/Dashboard/context/AuthContext.jsx +++ b/src/components/Dashboard/context/AuthContext.jsx @@ -338,12 +338,12 @@ const AuthProvider = ({ children }) => { } }, [ - isElectron, navigate, location.search, location.pathname, messageApi, - persistSession + persistSession, + redirectType ] ) diff --git a/src/components/Dashboard/context/ElectronContext.jsx b/src/components/Dashboard/context/ElectronContext.jsx index 3db5329..d8630f5 100644 --- a/src/components/Dashboard/context/ElectronContext.jsx +++ b/src/components/Dashboard/context/ElectronContext.jsx @@ -7,6 +7,7 @@ const electron = window.require ? window.require('electron') : null const ipcRenderer = electron ? electron.ipcRenderer : null // Utility to check if running in Electron +// eslint-disable-next-line react-refresh/only-export-components export function isElectron() { // Renderer process @@ -88,6 +89,7 @@ const ElectronProvider = ({ children }) => { // Listen for navigate const navigateHandler = (event, url) => { console.log('Navigating to:', url) + navigate(url) } ipcRenderer.on('navigate', navigateHandler) @@ -96,7 +98,7 @@ const ElectronProvider = ({ children }) => { ipcRenderer.removeListener('navigate', navigateHandler) ipcRenderer.removeListener('window-state', windowStateHandler) } - }, []) + }, [navigate]) // Window control handler const handleWindowControl = (action) => { diff --git a/src/components/Dashboard/context/MessageContext.jsx b/src/components/Dashboard/context/MessageContext.jsx index 5f0cfd5..cdea2c8 100644 --- a/src/components/Dashboard/context/MessageContext.jsx +++ b/src/components/Dashboard/context/MessageContext.jsx @@ -47,6 +47,7 @@ MessageProvider.propTypes = { children: PropTypes.node.isRequired } +// eslint-disable-next-line react-refresh/only-export-components export const useMessageContext = () => { const context = useContext(MessageContext) if (!context) { diff --git a/src/components/Dashboard/context/SpotlightContext.jsx b/src/components/Dashboard/context/SpotlightContext.jsx index 0c1f87f..9dda2bb 100644 --- a/src/components/Dashboard/context/SpotlightContext.jsx +++ b/src/components/Dashboard/context/SpotlightContext.jsx @@ -17,7 +17,8 @@ import { useState, useRef, createElement, - useContext + useContext, + useCallback } from 'react' import axios from 'axios' import { LoadingOutlined } from '@ant-design/icons' @@ -608,7 +609,7 @@ const ElectronSpotlightContentPage = () => { const { resizeSpotlightWindow, isElectron } = useContext(ElectronContext) // Function to measure and resize window - const updateWindowHeight = () => { + const updateWindowHeight = useCallback(() => { if (!cardRef.current || !isElectron || !resizeSpotlightWindow) return // Clear any pending resize @@ -639,7 +640,7 @@ const ElectronSpotlightContentPage = () => { console.warn('Failed to update spotlight window height:', error) } }, 100) // 100ms debounce - } + }, [isElectron, resizeSpotlightWindow]) // Use ResizeObserver to watch for content changes useEffect(() => { @@ -666,7 +667,7 @@ const ElectronSpotlightContentPage = () => { } clearTimeout(initialTimeout) } - }, [isElectron, resizeSpotlightWindow]) + }, [isElectron, resizeSpotlightWindow, updateWindowHeight]) return (
{ const context = useContext(ThemeContext) if (!context) {