Refactored application to replace SocketContext with PrintServerContext for WebSocket communication. Updated related components to utilize print server events for real-time updates. Removed unused SocketContext and NotificationContext files. Updated package dependencies to use loglevel instead of log4js for improved logging capabilities.
This commit is contained in:
parent
8caad73f0b
commit
0634919bb6
80
package-lock.json
generated
80
package-lock.json
generated
@ -26,7 +26,7 @@
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"gcode-preview": "^2.18.0",
|
||||
"keycloak-js": "^26.2.0",
|
||||
"log4js": "^6.9.1",
|
||||
"loglevel": "^1.9.2",
|
||||
"moment": "*",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-eslint": "^16.4.2",
|
||||
@ -9986,15 +9986,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/date-format": {
|
||||
"version": "4.0.14",
|
||||
"resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
|
||||
"integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||
@ -16008,27 +15999,10 @@
|
||||
"integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/log4js": {
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz",
|
||||
"integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"date-format": "^4.0.14",
|
||||
"debug": "^4.3.4",
|
||||
"flatted": "^3.2.7",
|
||||
"rfdc": "^1.3.0",
|
||||
"streamroller": "^3.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/loglevel": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz",
|
||||
"integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
@ -21486,12 +21460,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rfdc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
||||
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rimraf": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
@ -22819,52 +22787,6 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/streamroller": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz",
|
||||
"integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"date-format": "^4.0.14",
|
||||
"debug": "^4.3.4",
|
||||
"fs-extra": "^8.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/streamroller/node_modules/fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6 <7 || >=8"
|
||||
}
|
||||
},
|
||||
"node_modules/streamroller/node_modules/jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/streamroller/node_modules/universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"gcode-preview": "^2.18.0",
|
||||
"keycloak-js": "^26.2.0",
|
||||
"log4js": "^6.9.1",
|
||||
"loglevel": "^1.9.2",
|
||||
"moment": "*",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-eslint": "^16.4.2",
|
||||
|
||||
11
src/App.css
11
src/App.css
@ -22,11 +22,14 @@
|
||||
.ant-input,
|
||||
.ant-input-number .ant-input-number-input,
|
||||
.ant-segmented-item-label,
|
||||
.ant-badge-status-text {
|
||||
.ant-badge-status-text,
|
||||
.ant-tree-title,
|
||||
.ant-select {
|
||||
font-family: 'DM Sans';
|
||||
}
|
||||
|
||||
.ant-typography code {
|
||||
.ant-typography code,
|
||||
.ant-typography pre {
|
||||
font-family: 'DM Mono';
|
||||
}
|
||||
|
||||
@ -115,6 +118,10 @@ code {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.ant-popover-inner:has(.keyboard-shortcut-tooltip) {
|
||||
padding: 8px !important;
|
||||
}
|
||||
|
||||
/* --- Start of src/index.css --- */
|
||||
body {
|
||||
margin: 0;
|
||||
|
||||
18
src/App.jsx
18
src/App.jsx
@ -44,7 +44,7 @@ import StockAuditInfo from './components/Dashboard/Inventory/StockAudits/StockAu
|
||||
import Dashboard from './components/Dashboard/Dashboard.jsx'
|
||||
import PrivateRoute from './components/PrivateRoute'
|
||||
import './App.css'
|
||||
import { SocketProvider } from './components/Dashboard/context/SocketContext.js'
|
||||
import { PrintServerProvider } from './components/Dashboard/context/PrintServerContext.js'
|
||||
import { AuthProvider } from './components/Dashboard/context/AuthContext.js'
|
||||
import { SpotlightProvider } from './components/Dashboard/context/SpotlightContext.js'
|
||||
import StockEvents from './components/Dashboard/Inventory/StockEvents.jsx'
|
||||
@ -61,8 +61,8 @@ import NoteTypes from './components/Dashboard/Management/NoteTypes.jsx'
|
||||
import NoteTypeInfo from './components/Dashboard/Management/NoteTypes/NoteTypeInfo.jsx'
|
||||
import SessionStorage from './components/Dashboard/Developer/SessionStorage.jsx'
|
||||
import AuthContextDebug from './components/Dashboard/Developer/AuthContextDebug.jsx'
|
||||
import SocketContextDebug from './components/Dashboard/Developer/SocketContextDebug.jsx'
|
||||
import { NotificationProvider } from './components/Dashboard/context/NotificationContext.js'
|
||||
import PrintServerContextDebug from './components/Dashboard/Developer/PrintServerContextDebug.jsx'
|
||||
import { ApiServerProvider } from './components/Dashboard/context/ApiServerContext.js'
|
||||
import Users from './components/Dashboard/Management/Users.jsx'
|
||||
import UserInfo from './components/Dashboard/Management/Users/UserInfo.jsx'
|
||||
|
||||
@ -74,8 +74,8 @@ const AppContent = () => {
|
||||
<App>
|
||||
<AuthProvider>
|
||||
<Router>
|
||||
<SocketProvider>
|
||||
<NotificationProvider>
|
||||
<PrintServerProvider>
|
||||
<ApiServerProvider>
|
||||
<SpotlightProvider>
|
||||
<Routes>
|
||||
<Route
|
||||
@ -213,8 +213,8 @@ const AppContent = () => {
|
||||
element={<AuthContextDebug />}
|
||||
/>
|
||||
<Route
|
||||
path='developer/socketcontextdebug'
|
||||
element={<SocketContextDebug />}
|
||||
path='developer/printservercontextdebug'
|
||||
element={<PrintServerContextDebug />}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
@ -228,8 +228,8 @@ const AppContent = () => {
|
||||
/>
|
||||
</Routes>
|
||||
</SpotlightProvider>
|
||||
</NotificationProvider>
|
||||
</SocketProvider>
|
||||
</ApiServerProvider>
|
||||
</PrintServerProvider>
|
||||
</Router>
|
||||
</AuthProvider>
|
||||
</App>
|
||||
|
||||
BIN
src/assets/icons/lockicon.afdesign
Normal file
BIN
src/assets/icons/lockicon.afdesign
Normal file
Binary file not shown.
1
src/assets/icons/lockicon.min.svg
Normal file
1
src/assets/icons/lockicon.min.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2" viewBox="0 0 64 64"><path d="M7.234 62.237h29.263c4.746 0 7.234-2.544 7.234-7.668V32.436c0-5.08-2.488-7.625-7.234-7.625H7.234C2.483 24.811 0 27.356 0 32.436v22.133c0 5.124 2.483 7.668 7.234 7.668m.887-5.601c-1.299 0-2.04-.793-2.04-2.268V32.649c0-1.48.741-2.236 2.04-2.236h27.494c1.324 0 2.029.756 2.029 2.236v21.719c0 1.475-.705 2.268-2.029 2.268zm-2.405-29.2h5.852V16.922c0-7.338 4.694-11.326 10.285-11.326 5.579 0 10.341 3.988 10.341 11.326v10.514h5.826v-9.959C38.02 5.946 30.389 0 21.853 0 13.342 0 5.716 5.946 5.716 17.477z" style="fill-rule:nonzero" transform="translate(11.623 3)scale(.93191)"/></svg>
|
||||
|
After Width: | Height: | Size: 754 B |
7
src/assets/icons/lockicon.svg
Normal file
7
src/assets/icons/lockicon.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(0.931914,0,0,0.931914,11.6234,3)">
|
||||
<path d="M7.234,62.237L36.497,62.237C41.243,62.237 43.731,59.693 43.731,54.569L43.731,32.436C43.731,27.356 41.243,24.811 36.497,24.811L7.234,24.811C2.483,24.811 0,27.356 0,32.436L0,54.569C0,59.693 2.483,62.237 7.234,62.237ZM8.121,56.636C6.822,56.636 6.081,55.843 6.081,54.368L6.081,32.649C6.081,31.169 6.822,30.413 8.121,30.413L35.615,30.413C36.939,30.413 37.644,31.169 37.644,32.649L37.644,54.368C37.644,55.843 36.939,56.636 35.615,56.636L8.121,56.636ZM5.716,27.436L11.568,27.436L11.568,16.922C11.568,9.584 16.262,5.596 21.853,5.596C27.432,5.596 32.194,9.584 32.194,16.922L32.194,27.436L38.02,27.436L38.02,17.477C38.02,5.946 30.389,0 21.853,0C13.342,0 5.716,5.946 5.716,17.477L5.716,27.436Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -1,29 +1,35 @@
|
||||
import React from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import DashboardSidebar from '../common/DashboardSidebar'
|
||||
import { Typography } from 'antd'
|
||||
|
||||
const { Text } = Typography
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: 'sessionstorage',
|
||||
label: 'Session Storage',
|
||||
icon: <Text>🗃️</Text>,
|
||||
path: '/dashboard/developer/sessionstorage'
|
||||
},
|
||||
{
|
||||
key: 'authcontextdebug',
|
||||
label: 'Auth Context Debug',
|
||||
label: 'Auth Debug',
|
||||
icon: <Text>🔐</Text>,
|
||||
path: '/dashboard/developer/authcontextdebug'
|
||||
},
|
||||
{
|
||||
key: 'socketcontextdebug',
|
||||
label: 'Socket Context Debug',
|
||||
path: '/dashboard/developer/socketcontextdebug'
|
||||
key: 'printservercontextdebug',
|
||||
label: 'Print Server Debug',
|
||||
icon: <Text>🖨️</Text>,
|
||||
path: '/dashboard/developer/printservercontextdebug'
|
||||
}
|
||||
]
|
||||
|
||||
const routeKeyMap = {
|
||||
'/dashboard/developer/sessionstorage': 'sessionstorage',
|
||||
'/dashboard/developer/authcontext': 'authcontextdebug',
|
||||
'/dashboard/developer/socketcontext': 'socketcontextdebug'
|
||||
'/dashboard/developer/printservercontext': 'printservercontextdebug'
|
||||
}
|
||||
|
||||
const DeveloperSidebar = (props) => {
|
||||
|
||||
@ -9,13 +9,13 @@ import {
|
||||
message
|
||||
} from 'antd'
|
||||
import ReloadIcon from '../../Icons/ReloadIcon.jsx'
|
||||
import { SocketContext } from '../context/SocketContext.js'
|
||||
import { PrintServerContext } from '../context/PrintServerContext.js'
|
||||
import BoolDisplay from '../common/BoolDisplay.jsx'
|
||||
|
||||
const { Text, Paragraph } = Typography
|
||||
|
||||
const SocketContextDebug = () => {
|
||||
const { socket, error, connecting } = useContext(SocketContext)
|
||||
const PrintServerContextDebug = () => {
|
||||
const { printServer, error, connecting } = useContext(PrintServerContext)
|
||||
const [msgApi, contextHolder] = message.useMessage()
|
||||
|
||||
const actionItems = {
|
||||
@ -36,9 +36,9 @@ const SocketContextDebug = () => {
|
||||
|
||||
// Helper to display socket info safely
|
||||
const getSocketInfo = () => {
|
||||
if (!socket) return 'n/a'
|
||||
if (!printServer) return 'n/a'
|
||||
// Only show safe properties
|
||||
const { id, connected, disconnected, nsp } = socket
|
||||
const { id, connected, disconnected, nsp } = printServer
|
||||
return JSON.stringify({ id, connected, disconnected, nsp }, null, 2)
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ const SocketContextDebug = () => {
|
||||
<div style={{ height: '100%', overflow: 'auto' }}>
|
||||
<Descriptions bordered column={1}>
|
||||
<Descriptions.Item label='Connected'>
|
||||
<BoolDisplay value={socket?.connected || false} />
|
||||
<BoolDisplay value={printServer?.connected || false} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Connecting'>
|
||||
<BoolDisplay value={connecting} />
|
||||
@ -74,4 +74,4 @@ const SocketContextDebug = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default SocketContextDebug
|
||||
export default PrintServerContextDebug
|
||||
@ -16,7 +16,7 @@ import {
|
||||
} from 'antd'
|
||||
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
|
||||
import NewFilamentStock from './FilamentStocks/NewFilamentStock'
|
||||
import IdText from '../common/IdText'
|
||||
@ -41,7 +41,7 @@ const { Text } = Typography
|
||||
const FilamentStocks = () => {
|
||||
const [messageApi, contextHolder] = message.useMessage()
|
||||
const navigate = useNavigate()
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
const tableRef = useRef()
|
||||
|
||||
@ -213,9 +213,9 @@ const FilamentStocks = () => {
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (socket && !initialized) {
|
||||
if (printServer && !initialized) {
|
||||
setInitialized(true)
|
||||
socket.on('notify_filamentstock_update', (updateData) => {
|
||||
printServer.on('notify_filamentstock_update', (updateData) => {
|
||||
console.log('Received filament stock update:', updateData)
|
||||
if (tableRef.current) {
|
||||
tableRef.current.updateData(updateData._id, updateData)
|
||||
@ -224,12 +224,12 @@ const FilamentStocks = () => {
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
if (printServer && initialized) {
|
||||
console.log('Deregistering filament stock update listener')
|
||||
socket.off('notify_filamentstock_update')
|
||||
printServer.off('notify_filamentstock_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized])
|
||||
}, [printServer, initialized])
|
||||
|
||||
const getFilamentStockActionItems = (id) => {
|
||||
return {
|
||||
|
||||
@ -19,7 +19,7 @@ import {
|
||||
} from 'antd'
|
||||
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
||||
import IdText from '../../common/IdText'
|
||||
import { SocketContext } from '../../context/SocketContext'
|
||||
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||
import FilamentStockState from '../../common/FilamentStockState'
|
||||
import StockEventTable from '../../common/StockEventTable'
|
||||
import useCollapseState from '../../hooks/useCollapseState'
|
||||
@ -48,7 +48,7 @@ const FilamentStockInfo = () => {
|
||||
'filamentStockId'
|
||||
)
|
||||
const [form] = Form.useForm()
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [collapseState, updateCollapseState] = useCollapseState(
|
||||
'FilamentStockInfo',
|
||||
{
|
||||
@ -75,9 +75,9 @@ const FilamentStockInfo = () => {
|
||||
|
||||
// Add WebSocket event listener for real-time updates
|
||||
useEffect(() => {
|
||||
if (socket && !initialized && filamentStockId) {
|
||||
if (printServer && !initialized && filamentStockId) {
|
||||
setInitialized(true)
|
||||
socket.on('notify_filamentstock_update', (statusUpdate) => {
|
||||
printServer.on('notify_filamentstock_update', (statusUpdate) => {
|
||||
console.log('GOT FILAMENT STOCK UPDATE', statusUpdate)
|
||||
setFilamentStockData((prevData) => {
|
||||
if (statusUpdate?._id === filamentStockId) {
|
||||
@ -91,12 +91,12 @@ const FilamentStockInfo = () => {
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
if (printServer && initialized) {
|
||||
console.log('Deregistering filament stock update listener')
|
||||
socket.off('notify_filamentstock_update')
|
||||
printServer.off('notify_filamentstock_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized, filamentStockId])
|
||||
}, [printServer, initialized, filamentStockId])
|
||||
|
||||
const fetchFilamentStockDetails = async () => {
|
||||
try {
|
||||
|
||||
@ -11,7 +11,7 @@ import {
|
||||
} from 'antd'
|
||||
import { useMediaQuery } from 'react-responsive'
|
||||
import PropTypes from 'prop-types'
|
||||
import { SocketContext } from '../../context/SocketContext'
|
||||
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||
|
||||
import FilamentStockSelect from '../../common/FilamentStockSelect'
|
||||
import PrinterSelect from '../../common/PrinterSelect'
|
||||
@ -38,7 +38,7 @@ const LoadFilamentStock = ({
|
||||
filamentStockLoaded: PropTypes.bool
|
||||
}
|
||||
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
|
||||
const initialLoadFilamentStockForm = {
|
||||
printer: printer,
|
||||
@ -93,16 +93,16 @@ const LoadFilamentStock = ({
|
||||
console.log(statusUpdate)
|
||||
}
|
||||
|
||||
socket.emit('printer.objects.subscribe', params)
|
||||
socket.emit('printer.objects.query', params)
|
||||
socket.on('notify_status_update', notifyStatusUpdate)
|
||||
printServer.emit('printer.objects.subscribe', params)
|
||||
printServer.emit('printer.objects.query', params)
|
||||
printServer.on('notify_status_update', notifyStatusUpdate)
|
||||
|
||||
return () => {
|
||||
socket.off('notify_status_update', notifyStatusUpdate)
|
||||
socket.emit('printer.objects.unsubscribe', params)
|
||||
printServer.off('notify_status_update', notifyStatusUpdate)
|
||||
printServer.emit('printer.objects.unsubscribe', params)
|
||||
}
|
||||
}
|
||||
}, [socket, loadFilamentStockFormValues.printer])
|
||||
}, [printServer, loadFilamentStockFormValues.printer])
|
||||
|
||||
React.useEffect(() => {
|
||||
loadFilamentStockForm
|
||||
@ -170,7 +170,7 @@ const LoadFilamentStock = ({
|
||||
|
||||
try {
|
||||
// Set the extruder temperature
|
||||
await socket.emit('printer.filamentstock.load', {
|
||||
await printServer.emit('printer.filamentstock.load', {
|
||||
printerId: loadFilamentStockFormValues.printer._id,
|
||||
filamentStockId: loadFilamentStockFormValues.filamentStock._id
|
||||
})
|
||||
|
||||
@ -2,7 +2,7 @@ import React, { useState, useContext, useEffect } from 'react'
|
||||
import { Form, Button, Typography, Flex, Steps, Divider, Alert } from 'antd'
|
||||
import { useMediaQuery } from 'react-responsive'
|
||||
import PropTypes from 'prop-types'
|
||||
import { SocketContext } from '../../context/SocketContext'
|
||||
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||
|
||||
import PrinterSelect from '../../common/PrinterSelect'
|
||||
import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'
|
||||
@ -18,7 +18,7 @@ const UnloadFilamentStock = ({ onOk, reset, printer = null }) => {
|
||||
printer: PropTypes.object
|
||||
}
|
||||
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||
|
||||
const initialUnloadFilamentStockForm = {
|
||||
@ -66,16 +66,16 @@ const UnloadFilamentStock = ({ onOk, reset, printer = null }) => {
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('printer.objects.subscribe', params)
|
||||
socket.emit('printer.objects.query', params)
|
||||
socket.on('notify_status_update', notifyStatusUpdate)
|
||||
printServer.emit('printer.objects.subscribe', params)
|
||||
printServer.emit('printer.objects.query', params)
|
||||
printServer.on('notify_status_update', notifyStatusUpdate)
|
||||
|
||||
return () => {
|
||||
socket.off('notify_status_update', notifyStatusUpdate)
|
||||
socket.emit('printer.objects.unsubscribe', params)
|
||||
printServer.off('notify_status_update', notifyStatusUpdate)
|
||||
printServer.emit('printer.objects.unsubscribe', params)
|
||||
}
|
||||
}
|
||||
}, [socket, unloadFilamentStockFormValues.printer])
|
||||
}, [printServer, unloadFilamentStockFormValues.printer])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (reset) {
|
||||
@ -109,7 +109,7 @@ const UnloadFilamentStock = ({ onOk, reset, printer = null }) => {
|
||||
const handleUnloadFilamentStock = async () => {
|
||||
setUnloadFilamentStockLoading(true)
|
||||
// Send G-code to retract the filament
|
||||
await socket.emit('printer.gcode.script', {
|
||||
await printServer.emit('printer.gcode.script', {
|
||||
printerId: unloadFilamentStockFormValues.printer._id,
|
||||
script: `_CLIENT_LINEAR_MOVE E=-200 F=1000`
|
||||
})
|
||||
|
||||
@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom'
|
||||
import { Button, Flex, Space, message, Dropdown, Typography } from 'antd'
|
||||
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
|
||||
import IdText from '../common/IdText'
|
||||
import StockAuditIcon from '../../Icons/StockAuditIcon'
|
||||
@ -20,16 +20,16 @@ const { Text } = Typography
|
||||
const StockAudits = () => {
|
||||
const [messageApi, contextHolder] = message.useMessage()
|
||||
const navigate = useNavigate()
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
const tableRef = useRef()
|
||||
|
||||
const { authenticated } = useContext(AuthContext)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (socket && !initialized) {
|
||||
if (printServer && !initialized) {
|
||||
setInitialized(true)
|
||||
socket.on('notify_stockaudit_update', (updateData) => {
|
||||
printServer.on('notify_stockaudit_update', (updateData) => {
|
||||
console.log('Received stock audit update:', updateData)
|
||||
if (tableRef.current) {
|
||||
tableRef.current.updateData(updateData._id, updateData)
|
||||
@ -38,12 +38,12 @@ const StockAudits = () => {
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
if (printServer && initialized) {
|
||||
console.log('Deregistering stock audit update listener')
|
||||
socket.off('notify_stockaudit_update')
|
||||
printServer.off('notify_stockaudit_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized])
|
||||
}, [printServer, initialized])
|
||||
|
||||
const getStockAuditActionItems = (id) => {
|
||||
return {
|
||||
|
||||
@ -11,7 +11,7 @@ import {
|
||||
} from 'antd'
|
||||
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import IdText from '../common/IdText'
|
||||
import TimeDisplay from '../common/TimeDisplay'
|
||||
import ReloadIcon from '../../Icons/ReloadIcon'
|
||||
@ -31,7 +31,7 @@ import StockEventIcon from '../../Icons/StockEventIcon'
|
||||
const { Text } = Typography
|
||||
|
||||
const StockEvents = () => {
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
const tableRef = useRef()
|
||||
const [viewMode, setViewMode] = useViewMode('StockEvents')
|
||||
@ -225,9 +225,9 @@ const StockEvents = () => {
|
||||
|
||||
React.useEffect(() => {
|
||||
// Add WebSocket event listener for real-time updates
|
||||
if (socket && !initialized) {
|
||||
if (printServer && !initialized) {
|
||||
setInitialized(true)
|
||||
socket.on('notify_stockevent_update', (updateData) => {
|
||||
printServer.on('notify_stockevent_update', (updateData) => {
|
||||
console.log('Received stock event update:', updateData)
|
||||
if (tableRef.current) {
|
||||
tableRef.current.updateData(updateData._id, updateData)
|
||||
@ -236,12 +236,12 @@ const StockEvents = () => {
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
if (printServer && initialized) {
|
||||
console.log('Deregistering stock event update listener')
|
||||
socket.off('notify_stockevent_update')
|
||||
printServer.off('notify_stockevent_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized])
|
||||
}, [printServer, initialized])
|
||||
|
||||
const actionItems = {
|
||||
items: [
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -72,7 +72,7 @@ const NewGCodeFile = ({ onOk, reset }) => {
|
||||
|
||||
const { token, authenticated } = useContext(AuthContext)
|
||||
// eslint-disable-next-line
|
||||
const fetchFilamentDetails = async () => {
|
||||
const fetchFilamentInfo = async () => {
|
||||
if (!authenticated) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ import {
|
||||
} from 'antd'
|
||||
|
||||
import { AuthContext } from '../context/AuthContext.js'
|
||||
import { SocketContext } from '../context/SocketContext.js'
|
||||
import { PrintServerContext } from '../context/PrintServerContext.js'
|
||||
import NewJob from './Jobs/NewJob.jsx'
|
||||
import JobState from '../common/JobState.jsx'
|
||||
import SubJobCounter from '../common/SubJobCounter.jsx'
|
||||
@ -257,7 +257,7 @@ const Jobs = () => {
|
||||
]
|
||||
|
||||
const { authenticated } = useContext(AuthContext)
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
|
||||
const [columnVisibility, updateColumnVisibility] = useColumnVisibility(
|
||||
'Jobs',
|
||||
@ -265,9 +265,9 @@ const Jobs = () => {
|
||||
)
|
||||
|
||||
const handleDeployJob = (jobId) => {
|
||||
if (socket) {
|
||||
if (printServer) {
|
||||
messageApi.info(`Print job ${jobId} deployment initiated`)
|
||||
socket.emit('server.job_queue.deploy', { jobId }, (response) => {
|
||||
printServer.emit('server.job_queue.deploy', { jobId }, (response) => {
|
||||
if (response == false) {
|
||||
notificationApi.error({
|
||||
message: 'Print job deployment failed',
|
||||
|
||||
@ -21,7 +21,7 @@ import TimeDisplay from '../../common/TimeDisplay'
|
||||
import JobState from '../../common/JobState'
|
||||
import IdText from '../../common/IdText'
|
||||
import SubJobsTree from '../../common/SubJobsTree'
|
||||
import { SocketContext } from '../../context/SocketContext'
|
||||
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||
import GCodeFileIcon from '../../../Icons/GCodeFileIcon'
|
||||
import ReloadIcon from '../../../Icons/ReloadIcon'
|
||||
import useCollapseState from '../../hooks/useCollapseState'
|
||||
@ -42,7 +42,7 @@ const JobInfo = () => {
|
||||
const location = useLocation()
|
||||
const [messageApi] = message.useMessage()
|
||||
const jobId = new URLSearchParams(location.search).get('jobId')
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [collapseState, updateCollapseState] = useCollapseState('JobInfo', {
|
||||
info: true,
|
||||
subJobs: true,
|
||||
@ -57,8 +57,8 @@ const JobInfo = () => {
|
||||
}, [jobId])
|
||||
|
||||
useEffect(() => {
|
||||
if (socket && jobId) {
|
||||
socket.on('notify_job_update', (updateData) => {
|
||||
if (printServer && jobId) {
|
||||
printServer.on('notify_job_update', (updateData) => {
|
||||
if (updateData._id === jobId) {
|
||||
setJobData((prevData) => {
|
||||
if (!prevData) return prevData
|
||||
@ -73,11 +73,11 @@ const JobInfo = () => {
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (socket) {
|
||||
socket.off('notify_job_update')
|
||||
if (printServer) {
|
||||
printServer.off('notify_job_update')
|
||||
}
|
||||
}
|
||||
}, [socket, jobId])
|
||||
}, [printServer, jobId])
|
||||
|
||||
const fetchJobDetails = async () => {
|
||||
try {
|
||||
|
||||
@ -22,7 +22,7 @@ import {
|
||||
} from 'antd'
|
||||
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
||||
|
||||
import { SocketContext } from '../../context/SocketContext'
|
||||
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||
|
||||
import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'
|
||||
import PrinterPositionPanel from '../../common/PrinterPositionPanel'
|
||||
@ -106,7 +106,7 @@ const ControlPrinter = () => {
|
||||
)
|
||||
}, [componentVisibility])
|
||||
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const { authenticated } = useContext(AuthContext)
|
||||
|
||||
// Fetch printer details when the component mounts
|
||||
@ -143,9 +143,9 @@ const ControlPrinter = () => {
|
||||
|
||||
// Add WebSocket event listener for real-time updates
|
||||
useEffect(() => {
|
||||
if (socket && !initialized && printerId) {
|
||||
if (printServer && !initialized && printerId) {
|
||||
setInitialized(true)
|
||||
socket.on('notify_printer_update', (statusUpdate) => {
|
||||
printServer.on('notify_printer_update', (statusUpdate) => {
|
||||
setPrinterData((prevData) => {
|
||||
if (statusUpdate?._id === printerId) {
|
||||
return {
|
||||
@ -158,7 +158,7 @@ const ControlPrinter = () => {
|
||||
})
|
||||
|
||||
// Add WebSocket event listener for filament stock updates
|
||||
socket.on('notify_filamentstock_update', (filamentStockUpdate) => {
|
||||
printServer.on('notify_filamentstock_update', (filamentStockUpdate) => {
|
||||
setPrinterData((prevData) => {
|
||||
if (prevData?.currentFilamentStock) {
|
||||
if (
|
||||
@ -178,17 +178,17 @@ const ControlPrinter = () => {
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
if (printServer && initialized) {
|
||||
console.log('Deregistering')
|
||||
socket.off('notify_printer_update')
|
||||
socket.off('notify_filamentstock_update')
|
||||
printServer.off('notify_printer_update')
|
||||
printServer.off('notify_filamentstock_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized, printerId])
|
||||
}, [printServer, initialized, printerId])
|
||||
|
||||
function handleEmergencyStop() {
|
||||
console.log('Emergency stop button clicked')
|
||||
socket.emit('printer.emergency_stop', { printerId })
|
||||
printServer.emit('printer.emergency_stop', { printerId })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@ -328,19 +328,19 @@ const ControlPrinter = () => {
|
||||
],
|
||||
onClick: ({ key }) => {
|
||||
if (key === 'restartHost') {
|
||||
socket.emit('printer.restart', { printerId })
|
||||
printServer.emit('printer.restart', { printerId })
|
||||
} else if (key === 'restartFirmware') {
|
||||
socket.emit('printer.firmware_restart', { printerId })
|
||||
printServer.emit('printer.firmware_restart', { printerId })
|
||||
} else if (key === 'resumePrint') {
|
||||
socket.emit('printer.print.resume', { printerId })
|
||||
printServer.emit('printer.print.resume', { printerId })
|
||||
} else if (key === 'pausePrint') {
|
||||
socket.emit('printer.print.pause', { printerId })
|
||||
printServer.emit('printer.print.pause', { printerId })
|
||||
} else if (key === 'cancelPrint') {
|
||||
socket.emit('printer.print.cancel', { printerId })
|
||||
printServer.emit('printer.print.cancel', { printerId })
|
||||
} else if (key === 'startQueue') {
|
||||
socket.emit('server.job_queue.start', { printerId })
|
||||
printServer.emit('server.job_queue.start', { printerId })
|
||||
} else if (key === 'pauseQueue') {
|
||||
socket.emit('server.job_queue.pause', { printerId })
|
||||
printServer.emit('server.job_queue.pause', { printerId })
|
||||
} else if (key === 'loadFilamentStock') {
|
||||
setLoadFilamentStockModalOpen(true)
|
||||
} else if (key === 'unloadFilamentStock') {
|
||||
@ -467,9 +467,9 @@ const ControlPrinter = () => {
|
||||
}
|
||||
onClick={() => {
|
||||
if (printerData?.state?.type === 'paused') {
|
||||
socket.emit('printer.print.resume', { printerId })
|
||||
printServer.emit('printer.print.resume', { printerId })
|
||||
} else {
|
||||
socket.emit('printer.print.pause', { printerId })
|
||||
printServer.emit('printer.print.pause', { printerId })
|
||||
}
|
||||
}}
|
||||
></Button>
|
||||
@ -482,7 +482,7 @@ const ControlPrinter = () => {
|
||||
printerData?.state?.type === 'error'
|
||||
}
|
||||
onClick={() => {
|
||||
socket.emit('server.job_queue.start', { printerId })
|
||||
printServer.emit('server.job_queue.start', { printerId })
|
||||
}}
|
||||
></Button>
|
||||
</Space>
|
||||
@ -933,7 +933,7 @@ const ControlPrinter = () => {
|
||||
key='firmwareRestart'
|
||||
icon={<ReloadIcon />}
|
||||
onClick={() => {
|
||||
socket.emit('printer.firmware_restart', { printerId })
|
||||
printServer.emit('printer.firmware_restart', { printerId })
|
||||
setKlippyErrorModalOpen(false)
|
||||
}}
|
||||
>
|
||||
|
||||
@ -21,7 +21,7 @@ import {
|
||||
} from 'antd'
|
||||
import { SearchOutlined, SettingOutlined } from '@ant-design/icons'
|
||||
import PropTypes from 'prop-types'
|
||||
import { SocketContext } from '../../context/SocketContext'
|
||||
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||
import EditIcon from '../../../Icons/EditIcon.jsx'
|
||||
|
||||
import config from '../../../../config.js'
|
||||
@ -43,7 +43,7 @@ const NewPrinter = ({ onOk, reset }) => {
|
||||
reset: PropTypes.bool.isRequired
|
||||
}
|
||||
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [messageApi, contextHolder] = message.useMessage()
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification()
|
||||
@ -243,22 +243,22 @@ const NewPrinter = ({ onOk, reset }) => {
|
||||
setDiscovering(true)
|
||||
setDiscoveredPrinters([])
|
||||
messageApi.info('Discovering printers...')
|
||||
socket.off('notify_scan_network_found')
|
||||
socket.off('notify_scan_network_progress')
|
||||
socket.off('notify_scan_network_complete')
|
||||
printServer.off('notify_scan_network_found')
|
||||
printServer.off('notify_scan_network_progress')
|
||||
printServer.off('notify_scan_network_complete')
|
||||
|
||||
socket.on('notify_scan_network_found', notifyScanNetworkFound)
|
||||
socket.on('notify_scan_network_progress', notifyScanNetworkProgress)
|
||||
socket.on('notify_scan_network_complete', notifyScanNetworkComplete)
|
||||
printServer.on('notify_scan_network_found', notifyScanNetworkFound)
|
||||
printServer.on('notify_scan_network_progress', notifyScanNetworkProgress)
|
||||
printServer.on('notify_scan_network_complete', notifyScanNetworkComplete)
|
||||
|
||||
socket.emit('bridge.scan_network.start', {
|
||||
printServer.emit('bridge.scan_network.start', {
|
||||
port: scanPort,
|
||||
protocol: scanProtocol
|
||||
})
|
||||
}
|
||||
}, [
|
||||
discovering,
|
||||
socket,
|
||||
printServer,
|
||||
scanPort,
|
||||
scanProtocol,
|
||||
messageApi,
|
||||
@ -279,10 +279,10 @@ const NewPrinter = ({ onOk, reset }) => {
|
||||
setDiscovering(false)
|
||||
notificationApi.destroy('network-scan')
|
||||
messageApi.info('Stopping discovery...')
|
||||
socket.off('notify_scan_network_found')
|
||||
socket.off('notify_scan_network_progress')
|
||||
socket.off('notify_scan_network_complete')
|
||||
socket.emit('bridge.scan_network.stop', (response) => {
|
||||
printServer.off('notify_scan_network_found')
|
||||
printServer.off('notify_scan_network_progress')
|
||||
printServer.off('notify_scan_network_complete')
|
||||
printServer.emit('bridge.scan_network.stop', (response) => {
|
||||
if (response == false) {
|
||||
messageApi.error('Error stopping discovery!')
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ const breadcrumbNameMap = {
|
||||
'/dashboard/inventory/stockaudits/info': 'Info',
|
||||
'/dashboard/developer/sessionstorage': 'Session Storage',
|
||||
'/dashboard/developer/authcontextdebug': 'Auth Context Debug',
|
||||
'/dashboard/developer/socketcontextdebug': 'Socket Context Debug'
|
||||
'/dashboard/developer/printservercontextdebug': 'Print Server Context Debug'
|
||||
}
|
||||
|
||||
const DashboardBreadcrumb = () => {
|
||||
|
||||
@ -8,9 +8,8 @@ import {
|
||||
Dropdown,
|
||||
Button,
|
||||
Tooltip,
|
||||
Typography,
|
||||
Divider,
|
||||
Badge
|
||||
Badge,
|
||||
Divider
|
||||
} from 'antd'
|
||||
import {
|
||||
LogoutOutlined,
|
||||
@ -19,12 +18,13 @@ import {
|
||||
LoadingOutlined
|
||||
} from '@ant-design/icons'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import { SpotlightContext } from '../context/SpotlightContext'
|
||||
import { NotificationContext } from '../context/NotificationContext'
|
||||
import { ApiServerContext } from '../context/ApiServerContext'
|
||||
import { useNavigate, useLocation } from 'react-router-dom'
|
||||
import { Header } from 'antd/es/layout/layout'
|
||||
import { useMediaQuery } from 'react-responsive'
|
||||
import KeyboardShortcut from './KeyboardShortcut'
|
||||
|
||||
import FarmControlLogo from '../../Logos/FarmControlLogo'
|
||||
import FarmControlLogoSmall from '../../Logos/FarmControlLogoSmall'
|
||||
@ -36,16 +36,16 @@ import BellIcon from '../../Icons/BellIcon'
|
||||
import SearchIcon from '../../Icons/SearchIcon'
|
||||
import SettingsIcon from '../../Icons/SettingsIcon'
|
||||
import DeveloperIcon from '../../Icons/DeveloperIcon'
|
||||
|
||||
const { Text } = Typography
|
||||
import PrinterIcon from '../../Icons/PrinterIcon'
|
||||
|
||||
const DashboardNavigation = () => {
|
||||
const { logout, userProfile } = useContext(AuthContext)
|
||||
const { showSpotlight } = useContext(SpotlightContext)
|
||||
const { toggleNotificationCenter, unreadCount } =
|
||||
useContext(NotificationContext)
|
||||
const { socket } = useContext(SocketContext)
|
||||
const [socketState, setSocketState] = useState('disconnected')
|
||||
const { toggleNotificationCenter, unreadCount } = useContext(ApiServerContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const { apiServer } = useContext(ApiServerContext)
|
||||
const [printServerState, setPrintServerState] = useState('disconnected')
|
||||
const [apiServerState, setApiServerState] = useState('disconnected')
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
const [selectedKey, setSelectedKey] = useState('production')
|
||||
@ -59,14 +59,24 @@ const DashboardNavigation = () => {
|
||||
}, [location.pathname])
|
||||
|
||||
useEffect(() => {
|
||||
if (socket?.connecting) {
|
||||
setSocketState('connecting')
|
||||
} else if (socket?.connected) {
|
||||
setSocketState('connected')
|
||||
if (printServer?.connecting) {
|
||||
setPrintServerState('connecting')
|
||||
} else if (printServer?.connected) {
|
||||
setPrintServerState('connected')
|
||||
} else {
|
||||
setSocketState('disconnected')
|
||||
setPrintServerState('disconnected')
|
||||
}
|
||||
}, [socket?.connecting, socket?.connected])
|
||||
}, [printServer?.connecting, printServer?.connected])
|
||||
|
||||
useEffect(() => {
|
||||
if (apiServer?.connecting) {
|
||||
setApiServerState('connecting')
|
||||
} else if (apiServer?.connected) {
|
||||
setApiServerState('connected')
|
||||
} else {
|
||||
setApiServerState('disconnected')
|
||||
}
|
||||
}, [apiServer?.connecting, apiServer?.connected])
|
||||
|
||||
const mainMenuItems = [
|
||||
{
|
||||
@ -165,54 +175,90 @@ const DashboardNavigation = () => {
|
||||
/>
|
||||
<Flex gap={'middle'} align='center'>
|
||||
<Space>
|
||||
<Tooltip title={<Text keyboard>⌘ ⇧ P</Text>} arrow={false}>
|
||||
<KeyboardShortcut
|
||||
shortcut='alt+shift+q'
|
||||
hint='⌘ ⇧ P'
|
||||
onTrigger={() => showSpotlight()}
|
||||
>
|
||||
<Button
|
||||
icon={<SearchIcon />}
|
||||
type='text'
|
||||
style={{ marginTop: '2px' }}
|
||||
onClick={() => showSpotlight()}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
/>
|
||||
</KeyboardShortcut>
|
||||
<Badge count={unreadCount} size='small'>
|
||||
<Button
|
||||
icon={<BellIcon />}
|
||||
type='text'
|
||||
style={{ marginTop: '2px' }}
|
||||
onClick={toggleNotificationCenter}
|
||||
></Button>
|
||||
<KeyboardShortcut
|
||||
shortcut='alt+n'
|
||||
hint='ALT N'
|
||||
onTrigger={() => toggleNotificationCenter()}
|
||||
>
|
||||
<Button
|
||||
icon={<BellIcon />}
|
||||
type='text'
|
||||
style={{ marginTop: '2px' }}
|
||||
onClick={() => toggleNotificationCenter()}
|
||||
/>
|
||||
</KeyboardShortcut>
|
||||
</Badge>
|
||||
</Space>
|
||||
<Space>
|
||||
{socketState === 'connected' ? (
|
||||
<Tooltip title='Connected to server' arrow={false}>
|
||||
<Tag
|
||||
color='success'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<CloudIcon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{socketState === 'connecting' ? (
|
||||
<Tooltip title='Connecting to server...' arrow={false}>
|
||||
<Tag
|
||||
color='default'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<LoadingOutlined />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{socketState === 'disconnected' ? (
|
||||
<Tooltip title='Disconnected from server' arrow={false}>
|
||||
<Tag
|
||||
color='error'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<CloudIcon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</Space>
|
||||
|
||||
{process.env.NODE_ENV === 'development' && (
|
||||
<Space>
|
||||
{printServerState === 'connected' ? (
|
||||
<Tooltip title='Connected to print server' arrow={false}>
|
||||
<Tag
|
||||
color='success'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<PrinterIcon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{printServerState === 'connecting' ? (
|
||||
<Tooltip title='Connecting to print erver...' arrow={false}>
|
||||
<Tag
|
||||
color='default'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<LoadingOutlined />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{printServerState === 'disconnected' ? (
|
||||
<Tooltip title='Disconnected from print server' arrow={false}>
|
||||
<Tag
|
||||
color='error'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<PrinterIcon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{apiServerState === 'connected' ? (
|
||||
<Tooltip title='Connected to api server' arrow={false}>
|
||||
<Tag
|
||||
color='success'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<CloudIcon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{apiServerState === 'connecting' ? (
|
||||
<Tooltip title='Connecting to api erver...' arrow={false}>
|
||||
<Tag
|
||||
color='default'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<LoadingOutlined />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{apiServerState === 'disconnected' ? (
|
||||
<Tooltip title='Disconnected from api server' arrow={false}>
|
||||
<Tag
|
||||
color='error'
|
||||
style={{ marginRight: 0 }}
|
||||
icon={<CloudIcon />}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
<Tooltip title='Developer' arrow={false}>
|
||||
<Tag
|
||||
color='yellow'
|
||||
|
||||
@ -2,7 +2,7 @@ import PropTypes from 'prop-types'
|
||||
import { Badge, Progress, Flex, Space, Tag, Typography } from 'antd'
|
||||
import { green } from '@ant-design/colors'
|
||||
import React, { useState, useContext, useEffect } from 'react'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
|
||||
const { Text } = Typography
|
||||
|
||||
@ -25,7 +25,7 @@ const FilamentStockState = ({
|
||||
showProgress = true,
|
||||
showStatus = true
|
||||
}) => {
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [badgeStatus, setBadgeStatus] = useState('unknown')
|
||||
const [badgeText, setBadgeText] = useState('Unknown')
|
||||
const [currentState, setCurrentState] = useState(
|
||||
@ -37,20 +37,20 @@ const FilamentStockState = ({
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (socket && !initialized && filamentStock?._id) {
|
||||
if (printServer && !initialized && filamentStock?._id) {
|
||||
setInitialized(true)
|
||||
socket.on('notify_filamentstock_update', (statusUpdate) => {
|
||||
printServer.on('notify_filamentstock_update', (statusUpdate) => {
|
||||
if (statusUpdate?._id === filamentStock?._id && statusUpdate?.state) {
|
||||
setCurrentState(statusUpdate.state)
|
||||
}
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
socket.off('notify_filamentstock_update')
|
||||
if (printServer && initialized) {
|
||||
printServer.off('notify_filamentstock_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized, filamentStock?._id])
|
||||
}, [printServer, initialized, filamentStock?._id])
|
||||
|
||||
useEffect(() => {
|
||||
switch (currentState.type) {
|
||||
|
||||
55
src/components/Dashboard/common/InfoCollapse.jsx
Normal file
55
src/components/Dashboard/common/InfoCollapse.jsx
Normal file
@ -0,0 +1,55 @@
|
||||
import React from 'react'
|
||||
import { Collapse, Flex, Typography } from 'antd'
|
||||
import { CaretLeftOutlined } from '@ant-design/icons'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const { Title } = Typography
|
||||
|
||||
const InfoCollapse = ({
|
||||
title,
|
||||
icon,
|
||||
children,
|
||||
active,
|
||||
onToggle,
|
||||
className = '',
|
||||
key = 'default'
|
||||
}) => {
|
||||
return (
|
||||
<Collapse
|
||||
ghost
|
||||
expandIconPosition='end'
|
||||
activeKey={active ? [key] : []}
|
||||
onChange={(keys) => onToggle(keys.length > 0)}
|
||||
expandIcon={({ isActive }) => (
|
||||
<CaretLeftOutlined rotate={isActive ? -90 : 0} />
|
||||
)}
|
||||
className={`no-h-padding-collapse ${className}`}
|
||||
>
|
||||
<Collapse.Panel
|
||||
header={
|
||||
<Flex align='center' gap={'middle'}>
|
||||
{icon}
|
||||
<Title level={5} style={{ margin: 0 }}>
|
||||
{title}
|
||||
</Title>
|
||||
</Flex>
|
||||
}
|
||||
key={key}
|
||||
>
|
||||
{children}
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
)
|
||||
}
|
||||
|
||||
InfoCollapse.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
icon: PropTypes.node.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
active: PropTypes.bool.isRequired,
|
||||
onToggle: PropTypes.func.isRequired,
|
||||
className: PropTypes.string,
|
||||
key: PropTypes.string
|
||||
}
|
||||
|
||||
export default InfoCollapse
|
||||
@ -1,7 +1,7 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { Progress, Flex, Typography, Space } from 'antd'
|
||||
import React, { useState, useContext, useEffect } from 'react'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import IdText from './IdText'
|
||||
import StateTag from './StateTag'
|
||||
|
||||
@ -12,7 +12,7 @@ const JobState = ({
|
||||
showId = true,
|
||||
showQuantity = true
|
||||
}) => {
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [currentState, setCurrentState] = useState(
|
||||
job?.state || { type: 'unknown', progress: 0 }
|
||||
)
|
||||
@ -20,20 +20,20 @@ const JobState = ({
|
||||
const { Text } = Typography
|
||||
|
||||
useEffect(() => {
|
||||
if (socket && !initialized && job?._id) {
|
||||
if (printServer && !initialized && job?._id) {
|
||||
setInitialized(true)
|
||||
socket.on('notify_job_update', (statusUpdate) => {
|
||||
printServer.on('notify_job_update', (statusUpdate) => {
|
||||
if (statusUpdate?._id === job._id && statusUpdate?.state) {
|
||||
setCurrentState(statusUpdate.state)
|
||||
}
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
socket.off('notify_job_update')
|
||||
if (printServer && initialized) {
|
||||
printServer.off('notify_job_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized, job?._id])
|
||||
}, [printServer, initialized, job?._id])
|
||||
|
||||
return (
|
||||
<Flex gap='small' align={'center'}>
|
||||
|
||||
115
src/components/Dashboard/common/KeyboardShortcut.jsx
Normal file
115
src/components/Dashboard/common/KeyboardShortcut.jsx
Normal file
@ -0,0 +1,115 @@
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Popover, Typography } from 'antd'
|
||||
|
||||
// Utility to parse shortcut string like 'cmd+shift+p' or 'ctrl+s'
|
||||
function parseShortcut(shortcut) {
|
||||
const parts = shortcut.toLowerCase().split('+')
|
||||
return {
|
||||
meta: parts.includes('cmd') || parts.includes('meta') || false,
|
||||
ctrl: parts.includes('ctrl') || parts.includes('control') || false,
|
||||
alt: parts.includes('alt') || parts.includes('option') || false,
|
||||
shift: parts.includes('shift') || false,
|
||||
key: parts.find(
|
||||
(p) =>
|
||||
!['cmd', 'meta', 'ctrl', 'control', 'alt', 'option', 'shift'].includes(
|
||||
p
|
||||
)
|
||||
)[0]
|
||||
}
|
||||
}
|
||||
|
||||
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 keys = []
|
||||
if (shortcutObj.meta) keys.push('Meta')
|
||||
if (shortcutObj.ctrl) keys.push('Control')
|
||||
if (shortcutObj.alt) keys.push('Alt')
|
||||
if (shortcutObj.shift) keys.push('Shift')
|
||||
// shortcutObj.code is like 'keyp', so extract the last char
|
||||
if (shortcutObj.key) {
|
||||
keys.push('Key' + shortcutObj.key.toUpperCase())
|
||||
}
|
||||
return new Set(keys)
|
||||
}
|
||||
|
||||
const shortcutKeySet = getShortcutKeySet(shortcutObj)
|
||||
|
||||
useEffect(() => {
|
||||
pressedKeys = new Set()
|
||||
const handleKeyDown = (event) => {
|
||||
if (
|
||||
event.key === 'Meta' ||
|
||||
event.key === 'Control' ||
|
||||
event.key === 'Alt' ||
|
||||
event.key === 'Shift'
|
||||
) {
|
||||
pressedKeys.add(event.key)
|
||||
} else if (event.code && event.code.startsWith('Key')) {
|
||||
pressedKeys.add(event.code)
|
||||
}
|
||||
if (
|
||||
shortcutKeySet.size &&
|
||||
[...shortcutKeySet].every((k) => pressedKeys.has(k))
|
||||
) {
|
||||
if (typeof onTrigger === 'function') {
|
||||
onTrigger(event)
|
||||
}
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
const handleKeyUp = (event) => {
|
||||
if (
|
||||
event.key === 'Meta' ||
|
||||
event.key === 'Control' ||
|
||||
event.key === 'Alt' ||
|
||||
event.key === 'Shift'
|
||||
) {
|
||||
pressedKeys.delete(event.key)
|
||||
} else if (event.code && event.code.startsWith('Key')) {
|
||||
pressedKeys.delete(event.key.toUpperCase())
|
||||
}
|
||||
}
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
window.addEventListener('keyup', handleKeyUp)
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown)
|
||||
window.removeEventListener('keyup', handleKeyUp)
|
||||
}
|
||||
}, [shortcut, shortcutObj, onTrigger])
|
||||
|
||||
// Clone the child to attach a ref
|
||||
const element = React.cloneElement(children, { ref: childRef })
|
||||
|
||||
if (hint) {
|
||||
return (
|
||||
<Popover
|
||||
content={
|
||||
<Text keyboard className='keyboard-shortcut-tooltip'>
|
||||
{hint}
|
||||
</Text>
|
||||
}
|
||||
arrow={false}
|
||||
>
|
||||
{element}
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
return element
|
||||
}
|
||||
|
||||
KeyboardShortcut.propTypes = {
|
||||
shortcut: PropTypes.string.isRequired, // e.g. 'cmd+shift+p'
|
||||
onTrigger: PropTypes.func.isRequired,
|
||||
children: PropTypes.element.isRequired,
|
||||
hint: PropTypes.string // Optional, e.g. '⌘ ⇧ P'
|
||||
}
|
||||
|
||||
export default KeyboardShortcut
|
||||
@ -4,7 +4,7 @@ import { LoadingOutlined } from '@ant-design/icons'
|
||||
import React, { useState, useEffect, useContext } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import SubJobState from './SubJobState'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import axios from 'axios'
|
||||
import JobState from './JobState'
|
||||
import JobIcon from '../../Icons/JobIcon'
|
||||
@ -20,7 +20,7 @@ const PrinterJobsTree = ({
|
||||
const [subJobs, setSubJobs] = useState(initialSubJobs || [])
|
||||
const [treeLoading, setTreeLoading] = useState(initialLoading)
|
||||
const [error, setError] = useState(null)
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [messageApi] = message.useMessage()
|
||||
const [expandedKeys, setExpandedKeys] = useState([])
|
||||
const [treeData, setTreeData] = useState([])
|
||||
@ -116,9 +116,9 @@ const PrinterJobsTree = ({
|
||||
|
||||
initializeData()
|
||||
|
||||
// Add socket.io event listener for subjob updates
|
||||
if (socket) {
|
||||
socket.on('notify_subjob_update', (updateData) => {
|
||||
// Add printServer.io event listener for subjob updates
|
||||
if (printServer) {
|
||||
printServer.on('notify_subjob_update', (updateData) => {
|
||||
if (updateData.subJobId) {
|
||||
setSubJobs((prevSubJobs) =>
|
||||
prevSubJobs.map((subJob) => {
|
||||
@ -137,11 +137,11 @@ const PrinterJobsTree = ({
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (socket) {
|
||||
socket.off('notify_subjob_update')
|
||||
if (printServer) {
|
||||
printServer.off('notify_subjob_update')
|
||||
}
|
||||
}
|
||||
}, [initialSubJobs, socket])
|
||||
}, [initialSubJobs, printServer])
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import React, { useContext, useState, useEffect } from 'react'
|
||||
import { Typography, Spin, Flex, Space, Slider, Descriptions, Tag } from 'antd'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const { Text } = Typography
|
||||
@ -33,7 +33,7 @@ const PrinterMiscPanel = ({
|
||||
})
|
||||
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [fanSpeed, setFanSpeed] = useState(0)
|
||||
const [ledBrightness, setLedBrightness] = useState(0)
|
||||
const [beeperValue, setBeeperValue] = useState(0)
|
||||
@ -89,30 +89,30 @@ const PrinterMiscPanel = ({
|
||||
}
|
||||
}
|
||||
|
||||
if (!initialized && socket.connected) {
|
||||
if (!initialized && printServer.connected) {
|
||||
setInitialized(true)
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket.emit('printer.objects.subscribe', params)
|
||||
socket.emit('printer.objects.query', params)
|
||||
printServer.on('connect', () => {
|
||||
printServer.emit('printer.objects.subscribe', params)
|
||||
printServer.emit('printer.objects.query', params)
|
||||
})
|
||||
|
||||
socket.emit('printer.objects.subscribe', params)
|
||||
socket.emit('printer.objects.query', params)
|
||||
socket.on('notify_status_update', notifyMiscStatusUpdate)
|
||||
printServer.emit('printer.objects.subscribe', params)
|
||||
printServer.emit('printer.objects.query', params)
|
||||
printServer.on('notify_status_update', notifyMiscStatusUpdate)
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (socket.connected && initialized && shouldUnsubscribe) {
|
||||
socket.off('notify_status_update', notifyMiscStatusUpdate)
|
||||
socket.emit('printer.objects.unsubscribe', params)
|
||||
if (printServer.connected && initialized && shouldUnsubscribe) {
|
||||
printServer.off('notify_status_update', notifyMiscStatusUpdate)
|
||||
printServer.emit('printer.objects.unsubscribe', params)
|
||||
}
|
||||
}
|
||||
}, [socket, initialized, printerId, shouldUnsubscribe])
|
||||
}, [printServer, initialized, printerId, shouldUnsubscribe])
|
||||
|
||||
const handleSetFanSpeed = (value) => {
|
||||
if (socket) {
|
||||
socket.emit('printer.gcode.script', {
|
||||
if (printServer) {
|
||||
printServer.emit('printer.gcode.script', {
|
||||
printerId,
|
||||
script: `M106 S${Math.round(value * 255)}`
|
||||
})
|
||||
@ -120,8 +120,8 @@ const PrinterMiscPanel = ({
|
||||
}
|
||||
|
||||
const handleSetLedBrightness = (value) => {
|
||||
if (socket) {
|
||||
socket.emit('printer.gcode.script', {
|
||||
if (printServer) {
|
||||
printServer.emit('printer.gcode.script', {
|
||||
printerId,
|
||||
script: `SET_LED LED=led_backlight BRIGHTNESS=${value}`
|
||||
})
|
||||
@ -129,8 +129,8 @@ const PrinterMiscPanel = ({
|
||||
}
|
||||
|
||||
const handleSetBeeperValue = (value) => {
|
||||
if (socket) {
|
||||
socket.emit('printer.gcode.script', {
|
||||
if (printServer) {
|
||||
printServer.emit('printer.gcode.script', {
|
||||
printerId,
|
||||
script: `M300 S440 P200 V${Math.round(value * 100)}`
|
||||
})
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
Card,
|
||||
message // eslint-disable-line
|
||||
} from 'antd'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import PropTypes from 'prop-types'
|
||||
import LevelBedIcon from '../../Icons/LevelBedIcon'
|
||||
import ArrowLeftIcon from '../../Icons/ArrowLeftIcon'
|
||||
@ -22,7 +22,7 @@ import HomeIcon from '../../Icons/HomeIcon'
|
||||
const PrinterMovementPanel = ({ printerId }) => {
|
||||
const [posValue, setPosValue] = useState(10)
|
||||
const [rateValue, setRateValue] = useState(1000)
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
|
||||
//const messageApi = message.useMessage()
|
||||
|
||||
@ -40,9 +40,9 @@ const PrinterMovementPanel = ({ printerId }) => {
|
||||
}
|
||||
|
||||
const handleHomeAxisClick = (axis) => {
|
||||
if (socket) {
|
||||
if (printServer) {
|
||||
console.log('Homeing Axis:', axis)
|
||||
socket.emit('printer.gcode.script', {
|
||||
printServer.emit('printer.gcode.script', {
|
||||
printerId,
|
||||
script: `G28 ${axis}`
|
||||
})
|
||||
@ -51,9 +51,9 @@ const PrinterMovementPanel = ({ printerId }) => {
|
||||
|
||||
const handleMoveAxisClick = (axis, minus) => {
|
||||
const distanceValue = !minus ? posValue * -1 : posValue
|
||||
if (socket) {
|
||||
if (printServer) {
|
||||
console.log('Moving Axis:', axis, distanceValue)
|
||||
socket.emit('printer.gcode.script', {
|
||||
printServer.emit('printer.gcode.script', {
|
||||
printerId,
|
||||
script: `_CLIENT_LINEAR_MOVE ${axis}=${distanceValue} F=${rateValue}`
|
||||
})
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
Button
|
||||
} from 'antd'
|
||||
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import styled from 'styled-components'
|
||||
import PropTypes from 'prop-types'
|
||||
import BoolDisplay from './BoolDisplay'
|
||||
@ -46,7 +46,7 @@ const PrinterPositionPanel = ({
|
||||
})
|
||||
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [speedFactor, setSpeedFactor] = useState(positionData.speed_factor)
|
||||
const [extrudeFactor, setExtrudeFactor] = useState(
|
||||
positionData.extrude_factor
|
||||
@ -76,33 +76,33 @@ const PrinterPositionPanel = ({
|
||||
}
|
||||
}
|
||||
|
||||
if (!initialized && socket?.connected) {
|
||||
if (!initialized && printServer?.connected) {
|
||||
setInitialized(true)
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket.emit('printer.objects.subscribe', params)
|
||||
socket.emit('printer.objects.query', params)
|
||||
printServer.on('connect', () => {
|
||||
printServer.emit('printer.objects.subscribe', params)
|
||||
printServer.emit('printer.objects.query', params)
|
||||
})
|
||||
|
||||
socket.emit('printer.objects.subscribe', params)
|
||||
socket.emit('printer.objects.query', params)
|
||||
socket.on('notify_status_update', notifyPositionStatusUpdate)
|
||||
printServer.emit('printer.objects.subscribe', params)
|
||||
printServer.emit('printer.objects.query', params)
|
||||
printServer.on('notify_status_update', notifyPositionStatusUpdate)
|
||||
}
|
||||
|
||||
setSpeedFactor(positionData.speed_factor)
|
||||
setExtrudeFactor(positionData.extrude_factor)
|
||||
|
||||
return () => {
|
||||
if (socket?.connected && initialized && shouldUnsubscribe) {
|
||||
socket.off('notify_status_update', notifyPositionStatusUpdate)
|
||||
socket.emit('printer.objects.unsubscribe', params)
|
||||
if (printServer?.connected && initialized && shouldUnsubscribe) {
|
||||
printServer.off('notify_status_update', notifyPositionStatusUpdate)
|
||||
printServer.emit('printer.objects.unsubscribe', params)
|
||||
}
|
||||
}
|
||||
}, [socket, initialized, printerId, shouldUnsubscribe])
|
||||
}, [printServer, initialized, printerId, shouldUnsubscribe])
|
||||
|
||||
const handleSetSpeedFactor = () => {
|
||||
if (socket) {
|
||||
socket.emit('printer.gcode.script', {
|
||||
if (printServer) {
|
||||
printServer.emit('printer.gcode.script', {
|
||||
printerId,
|
||||
script: `M220 S${speedFactor * 100}`
|
||||
})
|
||||
@ -110,8 +110,8 @@ const PrinterPositionPanel = ({
|
||||
}
|
||||
|
||||
const handleSetExtrudeFactor = () => {
|
||||
if (socket) {
|
||||
socket.emit('printer.gcode.script', {
|
||||
if (printServer) {
|
||||
printServer.emit('printer.gcode.script', {
|
||||
printerId,
|
||||
script: `M221 S${extrudeFactor * 100}`
|
||||
})
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { Progress, Flex, Space, Typography, Button, Tooltip } from 'antd'
|
||||
import React, { useState, useContext, useEffect } from 'react'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import { CaretLeftOutlined } from '@ant-design/icons'
|
||||
import XMarkIcon from '../../Icons/XMarkIcon'
|
||||
import PauseIcon from '../../Icons/PauseIcon'
|
||||
@ -15,7 +15,7 @@ const PrinterState = ({
|
||||
showPrinterName = true,
|
||||
showControls = true
|
||||
}) => {
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [currentState, setCurrentState] = useState(
|
||||
printer?.state || {
|
||||
type: 'unknown',
|
||||
@ -26,20 +26,20 @@ const PrinterState = ({
|
||||
const { Text } = Typography
|
||||
|
||||
useEffect(() => {
|
||||
if (socket && !initialized && printer?.id) {
|
||||
if (printServer && !initialized && printer?.id) {
|
||||
setInitialized(true)
|
||||
socket.on('notify_printer_update', (statusUpdate) => {
|
||||
printServer.on('notify_printer_update', (statusUpdate) => {
|
||||
if (statusUpdate?._id === printer.id && statusUpdate?.state) {
|
||||
setCurrentState(statusUpdate.state)
|
||||
}
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
socket.off('notify_printer_update')
|
||||
if (printServer && initialized) {
|
||||
printServer.off('notify_printer_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized, printer?.id])
|
||||
}, [printServer, initialized, printer?.id])
|
||||
|
||||
return (
|
||||
<Flex gap='small' align={'center'}>
|
||||
@ -67,11 +67,11 @@ const PrinterState = ({
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (currentState.type === 'printing') {
|
||||
socket.emit('printer.print.pause', {
|
||||
printServer.emit('printer.print.pause', {
|
||||
printerId: printer.id
|
||||
})
|
||||
} else {
|
||||
socket.emit('printer.print.resume', {
|
||||
printServer.emit('printer.print.resume', {
|
||||
printerId: printer.id
|
||||
})
|
||||
}
|
||||
@ -94,7 +94,7 @@ const PrinterState = ({
|
||||
<Tooltip title='Cancel' arrow={false}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
socket.emit('printer.print.cancel', {
|
||||
printServer.emit('printer.print.cancel', {
|
||||
printerId: printer.id
|
||||
})
|
||||
}}
|
||||
|
||||
@ -11,7 +11,7 @@ import {
|
||||
Button
|
||||
} from 'antd'
|
||||
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import styled from 'styled-components'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
@ -50,7 +50,7 @@ const PrinterTemperaturePanel = ({
|
||||
const [heatedBedTemperature, setHeatedBedTemperature] = useState(
|
||||
temperatureData?.heatedBed?.target || 0
|
||||
)
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
|
||||
const notifyTemperatureStatusUpdate = useCallback((statusUpdate) => {
|
||||
setTemperatureData((prev) => {
|
||||
@ -96,25 +96,25 @@ const PrinterTemperaturePanel = ({
|
||||
heater_bed: null // eslint-disable-line
|
||||
}
|
||||
}
|
||||
if (socket?.connected == true) {
|
||||
if (printServer?.connected == true) {
|
||||
console.log('Printer Temperature Panel is subscribing...')
|
||||
socket.emit('printer.objects.subscribe', params)
|
||||
socket.emit('printer.objects.query', params)
|
||||
socket.on('notify_status_update', notifyTemperatureStatusUpdate)
|
||||
printServer.emit('printer.objects.subscribe', params)
|
||||
printServer.emit('printer.objects.query', params)
|
||||
printServer.on('notify_status_update', notifyTemperatureStatusUpdate)
|
||||
}
|
||||
return () => {
|
||||
if (socket && shouldUnsubscribe == true) {
|
||||
if (printServer && shouldUnsubscribe == true) {
|
||||
console.log('Printer Temperature Panel is unsubscribing...')
|
||||
socket.off('notify_status_update', notifyTemperatureStatusUpdate)
|
||||
socket.emit('printer.objects.unsubscribe', params)
|
||||
printServer.off('notify_status_update', notifyTemperatureStatusUpdate)
|
||||
printServer.emit('printer.objects.unsubscribe', params)
|
||||
}
|
||||
}
|
||||
}, [socket, printerId, notifyTemperatureStatusUpdate, shouldUnsubscribe])
|
||||
}, [printServer, printerId, notifyTemperatureStatusUpdate, shouldUnsubscribe])
|
||||
|
||||
const handleSetTemperatureClick = (target, value) => {
|
||||
if (socket) {
|
||||
if (printServer) {
|
||||
console.log('printer.gcode.script', target, value)
|
||||
socket.emit('printer.gcode.script', {
|
||||
printServer.emit('printer.gcode.script', {
|
||||
printerId,
|
||||
script: `SET_HEATER_TEMPERATURE HEATER=${target} TARGET=${value}`
|
||||
})
|
||||
|
||||
@ -3,7 +3,7 @@ import { Table, Typography } from 'antd'
|
||||
import PropTypes from 'prop-types'
|
||||
import IdText from './IdText'
|
||||
import { AuditOutlined } from '@ant-design/icons'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import moment from 'moment'
|
||||
import TimeDisplay from '../common/TimeDisplay'
|
||||
import PlusMinusIcon from '../../Icons/PlusMinusIcon'
|
||||
@ -13,15 +13,15 @@ import PlayCircleIcon from '../../Icons/PlayCircleIcon'
|
||||
const { Text } = Typography
|
||||
|
||||
const StockEventTable = ({ stockEvents }) => {
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
const [stockEventsData, setStockEventsData] = useState(stockEvents)
|
||||
|
||||
useEffect(() => {
|
||||
// Add WebSocket event listener for real-time updates
|
||||
if (socket && !initialized) {
|
||||
if (printServer && !initialized) {
|
||||
setInitialized(true)
|
||||
socket.on('notify_stockevent_update', (updateData) => {
|
||||
printServer.on('notify_stockevent_update', (updateData) => {
|
||||
console.log('Received stock event update:', updateData)
|
||||
setStockEventsData((prevData) => {
|
||||
return prevData.map((stockEvent) => {
|
||||
@ -41,12 +41,12 @@ const StockEventTable = ({ stockEvents }) => {
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
if (printServer && initialized) {
|
||||
console.log('Deregistering stock event update listener')
|
||||
socket.off('notify_stockevent_update')
|
||||
printServer.off('notify_stockevent_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized])
|
||||
}, [printServer, initialized])
|
||||
|
||||
useEffect(() => {
|
||||
setStockEventsData(stockEvents)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Tag } from 'antd' // eslint-disable-line
|
||||
import React, { useState, useContext, useEffect } from 'react'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
|
||||
import PauseCircleIcon from '../../Icons/PauseCircleIcon'
|
||||
import XMarkCircleIcon from '../../Icons/XMarkCircleIcon'
|
||||
@ -12,7 +12,7 @@ const SubJobCounter = ({
|
||||
showIcon = true,
|
||||
state = { type: 'complete' }
|
||||
}) => {
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
var badgeStatus = 'unknown'
|
||||
var badgeIcon = <QuestionCircleIcon />
|
||||
@ -21,10 +21,10 @@ const SubJobCounter = ({
|
||||
const [count, setCount] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
if (socket && !initialized && job?.id) {
|
||||
if (printServer && !initialized && job?.id) {
|
||||
setInitialized(true)
|
||||
console.log('on notify_subjob_update')
|
||||
socket.on('notify_subjob_update', (statusUpdate) => {
|
||||
printServer.on('notify_subjob_update', (statusUpdate) => {
|
||||
for (const subJob of job.subJobs) {
|
||||
if (statusUpdate?._id === subJob.id && statusUpdate?.state) {
|
||||
console.log('statusUpdate', statusUpdate)
|
||||
@ -34,12 +34,12 @@ const SubJobCounter = ({
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
if (printServer && initialized) {
|
||||
console.log('off notify_subjob_update')
|
||||
socket.off('notify_subjob_update')
|
||||
printServer.off('notify_subjob_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized, job?.subJobs, job?.id])
|
||||
}, [printServer, initialized, job?.subJobs, job?.id])
|
||||
|
||||
switch (state.type) {
|
||||
case 'draft':
|
||||
|
||||
@ -2,7 +2,7 @@ import PropTypes from 'prop-types'
|
||||
import { Progress, Flex, Button, Space, Tooltip } from 'antd' // eslint-disable-line
|
||||
import { CaretLeftOutlined } from '@ant-design/icons' // eslint-disable-line
|
||||
import React, { useState, useContext, useEffect } from 'react'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import IdText from './IdText'
|
||||
import StateTag from './StateTag'
|
||||
import XMarkIcon from '../../Icons/XMarkIcon'
|
||||
@ -16,7 +16,7 @@ const SubJobState = ({
|
||||
showProgress = true,
|
||||
showControls = true //eslint-disable-line
|
||||
}) => {
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [currentState, setCurrentState] = useState(
|
||||
subJob?.state || {
|
||||
type: 'unknown',
|
||||
@ -26,10 +26,10 @@ const SubJobState = ({
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (socket && !initialized && subJob?._id) {
|
||||
if (printServer && !initialized && subJob?._id) {
|
||||
setInitialized(true)
|
||||
console.log('on notify_subjob_update')
|
||||
socket.on('notify_subjob_update', (statusUpdate) => {
|
||||
printServer.on('notify_subjob_update', (statusUpdate) => {
|
||||
if (statusUpdate?._id === subJob._id && statusUpdate?.state) {
|
||||
console.log('statusUpdate', statusUpdate)
|
||||
setCurrentState(statusUpdate.state)
|
||||
@ -37,12 +37,12 @@ const SubJobState = ({
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
if (socket && initialized) {
|
||||
if (printServer && initialized) {
|
||||
console.log('off notify_subjob_update')
|
||||
socket.off('notify_subjob_update')
|
||||
printServer.off('notify_subjob_update')
|
||||
}
|
||||
}
|
||||
}, [socket, initialized, subJob?._id])
|
||||
}, [printServer, initialized, subJob?._id])
|
||||
|
||||
return (
|
||||
<Flex gap='small' align={'center'}>
|
||||
@ -73,11 +73,11 @@ const SubJobState = ({
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (currentState.type === 'printing') {
|
||||
socket.emit('printer.print.pause', {
|
||||
printServer.emit('printer.print.pause', {
|
||||
printerId: subJob.printer
|
||||
})
|
||||
} else {
|
||||
socket.emit('printer.print.resume', {
|
||||
printServer.emit('printer.print.resume', {
|
||||
printerId: subJob.printer
|
||||
})
|
||||
}
|
||||
@ -100,7 +100,7 @@ const SubJobState = ({
|
||||
<Tooltip title='Cancel' arrow={false}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
socket.emit('printer.print.cancel', {
|
||||
printServer.emit('printer.print.cancel', {
|
||||
printerId: subJob.printer
|
||||
})
|
||||
}}
|
||||
@ -117,7 +117,7 @@ const SubJobState = ({
|
||||
<Tooltip title='Cancel' arrow={false}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
socket.emit('server.job_queue.cancel', {
|
||||
printServer.emit('server.job_queue.cancel', {
|
||||
subJobId: subJob._id
|
||||
})
|
||||
}}
|
||||
|
||||
@ -6,7 +6,7 @@ import React, { useState, useEffect, useContext, useCallback } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import PrinterState from './PrinterState'
|
||||
import axios from 'axios'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { PrintServerContext } from '../context/PrintServerContext'
|
||||
import PrinterIcon from '../../Icons/PrinterIcon'
|
||||
import SubJobState from './SubJobState'
|
||||
import SubJobIcon from '../../Icons/SubJobIcon'
|
||||
@ -18,7 +18,7 @@ const SubJobsTree = ({ jobData, loading }) => {
|
||||
const [treeData, setTreeData] = useState([])
|
||||
const [treeLoading, setTreeLoading] = useState(loading)
|
||||
const [error, setError] = useState(null)
|
||||
const { socket } = useContext(SocketContext)
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [messageApi] = message.useMessage()
|
||||
const [expandedKeys, setExpandedKeys] = useState([])
|
||||
const [currentJobData, setCurrentJobData] = useState(null)
|
||||
@ -111,9 +111,9 @@ const SubJobsTree = ({ jobData, loading }) => {
|
||||
|
||||
initializeData()
|
||||
|
||||
// Add socket.io event listener for deployment updates
|
||||
if (socket) {
|
||||
socket.on('notify_deployment_update', (updateData) => {
|
||||
// Add printServer.io event listener for deployment updates
|
||||
if (printServer) {
|
||||
printServer.on('notify_deployment_update', (updateData) => {
|
||||
console.log('Received deployment update:', updateData)
|
||||
setCurrentJobData((prevData) => {
|
||||
if (!prevData) return prevData
|
||||
@ -148,7 +148,7 @@ const SubJobsTree = ({ jobData, loading }) => {
|
||||
return prevData
|
||||
})
|
||||
})
|
||||
socket.on('notify_subjob_update', (updateData) => {
|
||||
printServer.on('notify_subjob_update', (updateData) => {
|
||||
// Handle sub-job updates
|
||||
if (updateData.subJobId) {
|
||||
console.log('Received subjob update:', updateData)
|
||||
@ -174,11 +174,11 @@ const SubJobsTree = ({ jobData, loading }) => {
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (socket) {
|
||||
socket.off('notify_deployment_update')
|
||||
if (printServer) {
|
||||
printServer.off('notify_deployment_update')
|
||||
}
|
||||
}
|
||||
}, [jobData, socket])
|
||||
}, [jobData, printServer])
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
|
||||
300
src/components/Dashboard/context/ApiServerContext.js
Normal file
300
src/components/Dashboard/context/ApiServerContext.js
Normal file
@ -0,0 +1,300 @@
|
||||
// src/contexts/ApiServerContext.js
|
||||
import React, {
|
||||
createContext,
|
||||
useEffect,
|
||||
useState,
|
||||
useContext,
|
||||
useRef
|
||||
} from 'react'
|
||||
import io from 'socket.io-client'
|
||||
import { message, notification, Modal, Space, Button } from 'antd'
|
||||
import PropTypes from 'prop-types'
|
||||
import { AuthContext } from './AuthContext'
|
||||
import config from '../../../config'
|
||||
import loglevel from 'loglevel'
|
||||
import axios from 'axios'
|
||||
import ExclamationOctagonIcon from '../../Icons/ExclamationOctagonIcon'
|
||||
import ReloadIcon from '../../Icons/ReloadIcon'
|
||||
const log = loglevel.getLogger('Api Server')
|
||||
log.setLevel(config.logLevel)
|
||||
|
||||
const ApiServerContext = createContext()
|
||||
|
||||
const ApiServerProvider = ({ children }) => {
|
||||
const { token, userProfile } = useContext(AuthContext)
|
||||
const socketRef = useRef(null)
|
||||
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('')
|
||||
const [retryCallback, setRetryCallback] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
log.debug('Token is available, connecting to api server...')
|
||||
|
||||
const newSocket = io(config.apiServerUrl, {
|
||||
reconnectionAttempts: 3,
|
||||
timeout: 3000,
|
||||
auth: { token: token }
|
||||
})
|
||||
|
||||
setConnecting(true)
|
||||
|
||||
newSocket.on('connect', () => {
|
||||
log.debug('Api Server connected')
|
||||
setConnecting(false)
|
||||
setError(null)
|
||||
})
|
||||
|
||||
newSocket.on('disconnect', () => {
|
||||
log.debug('Api Server disconnected')
|
||||
setError('Api Server disconnected')
|
||||
})
|
||||
|
||||
newSocket.on('connect_error', (err) => {
|
||||
log.error('Api Server connection error:', err)
|
||||
messageApi.error('Api Server connection error: ' + err.message)
|
||||
setError('Api Server connection error')
|
||||
})
|
||||
|
||||
newSocket.on('bridge.notification', (data) => {
|
||||
notificationApi[data.type]({
|
||||
title: data.title,
|
||||
message: data.message
|
||||
})
|
||||
})
|
||||
|
||||
newSocket.on('error', (err) => {
|
||||
log.error('Api Server error:', err)
|
||||
setError('Api Server error')
|
||||
})
|
||||
|
||||
socketRef.current = newSocket
|
||||
|
||||
// Clean up function
|
||||
return () => {
|
||||
if (socketRef.current) {
|
||||
log.debug('Cleaning up api server connection...')
|
||||
socketRef.current.disconnect()
|
||||
socketRef.current = null
|
||||
}
|
||||
}
|
||||
} else if (!token && socketRef.current) {
|
||||
log.debug('Token not available, disconnecting api server...')
|
||||
socketRef.current.disconnect()
|
||||
socketRef.current = null
|
||||
}
|
||||
}, [token, messageApi])
|
||||
|
||||
const lockObject = (id, type) => {
|
||||
log.debug('Locking ' + id)
|
||||
if (socketRef.current && socketRef.current.connected) {
|
||||
socketRef.current.emit('lock', { _id: id, type: type })
|
||||
log.debug('Sent lock command for object:', id)
|
||||
}
|
||||
}
|
||||
|
||||
const unlockObject = (id, type) => {
|
||||
log.debug('Unlocking ' + id)
|
||||
if (socketRef.current && socketRef.current.connected == true) {
|
||||
socketRef.current.emit('unlock', { _id: id, type: type })
|
||||
log.debug('Sent unlock command for object:', id)
|
||||
}
|
||||
}
|
||||
|
||||
const fetchObjectLock = async (id, type) => {
|
||||
if (socketRef.current && socketRef.current.connected == true) {
|
||||
log.debug('Fetching lock status for ' + id)
|
||||
return new Promise((resolve) => {
|
||||
socketRef.current.emit(
|
||||
'getLock',
|
||||
{
|
||||
_id: id,
|
||||
type: type
|
||||
},
|
||||
(lockEvent) => {
|
||||
log.debug('Received lock event for object:', id, lockEvent)
|
||||
resolve(lockEvent)
|
||||
}
|
||||
)
|
||||
log.debug('Sent fetch lock command for object:', id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onLockEvent = (id, callback) => {
|
||||
if (socketRef.current && socketRef.current.connected == true) {
|
||||
const eventHandler = (data) => {
|
||||
if (data._id === id && data?.user !== userProfile._id) {
|
||||
log.debug(
|
||||
'Lock update received for object:',
|
||||
id,
|
||||
'locked:',
|
||||
data.locked
|
||||
)
|
||||
callback(data)
|
||||
}
|
||||
}
|
||||
|
||||
socketRef.current.on('notify_lock_update', eventHandler)
|
||||
log.debug('Registered lock event listener for object:', id)
|
||||
|
||||
// Return cleanup function
|
||||
return () => offLockEvent(id, eventHandler)
|
||||
}
|
||||
}
|
||||
|
||||
const offLockEvent = (id, eventHandler) => {
|
||||
if (socketRef.current && socketRef.current.connected == true) {
|
||||
socketRef.current.off('notify_lock_update', eventHandler)
|
||||
log.debug('Removed lock event listener for object:', id)
|
||||
}
|
||||
}
|
||||
|
||||
const onUpdateEvent = (id, callback) => {
|
||||
if (socketRef.current && socketRef.current.connected == true) {
|
||||
const eventHandler = (data) => {
|
||||
if (data._id === id && data?.user !== userProfile._id) {
|
||||
log.debug(
|
||||
'Update event received for object:',
|
||||
id,
|
||||
'updatedAt:',
|
||||
data.updatedAt
|
||||
)
|
||||
callback(data)
|
||||
}
|
||||
}
|
||||
|
||||
socketRef.current.on('notify_object_update', eventHandler)
|
||||
log.debug('Registered update event listener for object:', id)
|
||||
|
||||
// Return cleanup function
|
||||
return () => offUpdateEvent(id, eventHandler)
|
||||
}
|
||||
}
|
||||
|
||||
const offUpdateEvent = (id, eventHandler) => {
|
||||
if (socketRef.current && socketRef.current.connected == true) {
|
||||
socketRef.current.off('notify_update', eventHandler)
|
||||
log.debug('Removed update event listener for object:', id)
|
||||
}
|
||||
}
|
||||
|
||||
const showError = (content, callback = null) => {
|
||||
setErrorModalContent(content)
|
||||
setRetryCallback(() => callback)
|
||||
setShowErrorModal(true)
|
||||
}
|
||||
|
||||
const handleRetry = () => {
|
||||
setShowErrorModal(false)
|
||||
setErrorModalContent('')
|
||||
if (retryCallback) {
|
||||
retryCallback()
|
||||
}
|
||||
setRetryCallback(null)
|
||||
}
|
||||
|
||||
// Generalized fetchObjectInfo function
|
||||
const fetchObjectInfo = async (id, type) => {
|
||||
const fetchUrl = `${config.backendUrl}/${type}s/${id}`
|
||||
setFetchLoading(true)
|
||||
log.debug('Fetching from ' + fetchUrl)
|
||||
try {
|
||||
const response = await axios.get(fetchUrl, {
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
},
|
||||
withCredentials: true
|
||||
})
|
||||
return response.data
|
||||
} catch (err) {
|
||||
log.error('Failed to fetch object information:', err)
|
||||
// Don't automatically show error - let the component handle it
|
||||
throw err
|
||||
} finally {
|
||||
setFetchLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
// Update filament information
|
||||
const updateObjectInfo = async (id, type, value) => {
|
||||
const updateUrl = `${config.backendUrl}/${type}s/${id}`
|
||||
log.debug('Updating info for ' + id)
|
||||
try {
|
||||
const response = await axios.put(updateUrl, value, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
withCredentials: true
|
||||
})
|
||||
log.debug('Filament updated successfully')
|
||||
if (socketRef.current && socketRef.current.connected == true) {
|
||||
await socketRef.current.emit('update', {
|
||||
_id: id,
|
||||
type: type,
|
||||
updatedAt: response.data.updatedAt
|
||||
})
|
||||
}
|
||||
return response.data
|
||||
} catch (err) {
|
||||
log.error('Failed to update filament information:', err)
|
||||
// Don't automatically show error - let the component handle it
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ApiServerContext.Provider
|
||||
value={{
|
||||
apiServer: socketRef.current,
|
||||
error,
|
||||
connecting,
|
||||
lockObject,
|
||||
unlockObject,
|
||||
fetchObjectLock,
|
||||
updateObjectInfo,
|
||||
onLockEvent,
|
||||
onUpdateEvent,
|
||||
offUpdateEvent,
|
||||
fetchObjectInfo,
|
||||
fetchLoading,
|
||||
showError
|
||||
}}
|
||||
>
|
||||
{contextHolder}
|
||||
{children}
|
||||
<Modal
|
||||
title={
|
||||
<Space size={'middle'}>
|
||||
<ExclamationOctagonIcon />
|
||||
Error
|
||||
</Space>
|
||||
}
|
||||
open={showErrorModal}
|
||||
okText='OK'
|
||||
style={{ maxWidth: 430 }}
|
||||
closable={false}
|
||||
centered
|
||||
maskClosable={true}
|
||||
footer={[
|
||||
<Button key='retry' icon={<ReloadIcon />} onClick={handleRetry}>
|
||||
Retry
|
||||
</Button>
|
||||
]}
|
||||
>
|
||||
{errorModalContent}
|
||||
</Modal>
|
||||
</ApiServerContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
ApiServerProvider.propTypes = {
|
||||
children: PropTypes.node.isRequired
|
||||
}
|
||||
|
||||
export { ApiServerContext, ApiServerProvider }
|
||||
@ -1,212 +0,0 @@
|
||||
// src/contexts/NotificationContext.js
|
||||
import React, {
|
||||
createContext,
|
||||
useEffect,
|
||||
useState,
|
||||
useContext,
|
||||
useRef
|
||||
} from 'react'
|
||||
import io from 'socket.io-client'
|
||||
import { message, notification, Drawer } from 'antd'
|
||||
import PropTypes from 'prop-types'
|
||||
import { AuthContext } from './AuthContext'
|
||||
import config from '../../../config'
|
||||
import NotificationCenter from '../common/NotificationCenter'
|
||||
|
||||
const NotificationContext = createContext()
|
||||
|
||||
const NotificationProvider = ({ children }) => {
|
||||
const { token } = useContext(AuthContext)
|
||||
const socketRef = useRef(null)
|
||||
const [connecting, setConnecting] = useState(false)
|
||||
const [error, setError] = useState(null)
|
||||
const [notificationVisible, setNotificationVisible] = useState(false)
|
||||
const [notifications, setNotifications] = useState([])
|
||||
const [messageApi, contextHolder] = message.useMessage()
|
||||
const [notificationApi] = notification.useNotification()
|
||||
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
console.log(
|
||||
'Token is available, connecting to notification web socket server...'
|
||||
)
|
||||
|
||||
const newSocket = io(
|
||||
config.notificationWsUrl || `${config.wsUrl}/notifications`,
|
||||
{
|
||||
reconnectionAttempts: 3,
|
||||
timeout: 3000,
|
||||
auth: { token: token }
|
||||
}
|
||||
)
|
||||
|
||||
setConnecting(true)
|
||||
|
||||
newSocket.on('connect', () => {
|
||||
console.log('Notification socket connected')
|
||||
setConnecting(false)
|
||||
setError(null)
|
||||
})
|
||||
|
||||
newSocket.on('disconnect', () => {
|
||||
console.log('Notification socket disconnected')
|
||||
setError('Notification socket disconnected')
|
||||
})
|
||||
|
||||
newSocket.on('connect_error', (err) => {
|
||||
console.error('Notification socket connection error:', err)
|
||||
messageApi.error('Notification socket connection error: ' + err.message)
|
||||
setError('Notification socket connection error')
|
||||
})
|
||||
|
||||
newSocket.on('notification.new', (data) => {
|
||||
console.log('New notification received:', data)
|
||||
// Add new notification to state
|
||||
setNotifications((prev) => [data, ...prev])
|
||||
|
||||
// Show toast notification
|
||||
notificationApi.info({
|
||||
message: data.title || 'New Notification',
|
||||
description: data.message,
|
||||
placement: 'topRight',
|
||||
duration: 4.5
|
||||
})
|
||||
})
|
||||
|
||||
newSocket.on('notification.update', (data) => {
|
||||
console.log('Notification updated:', data)
|
||||
setNotifications((prev) =>
|
||||
prev.map((notification) => {
|
||||
if (notification._id === data._id) {
|
||||
return { ...notification, ...data }
|
||||
}
|
||||
return notification
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
newSocket.on('notification.delete', (data) => {
|
||||
console.log('Notification deleted:', data)
|
||||
setNotifications((prev) =>
|
||||
prev.filter((notification) => notification._id !== data._id)
|
||||
)
|
||||
})
|
||||
|
||||
newSocket.on('error', (err) => {
|
||||
console.error('Notification socket error:', err)
|
||||
setError('Notification socket error')
|
||||
})
|
||||
|
||||
socketRef.current = newSocket
|
||||
|
||||
// Clean up function
|
||||
return () => {
|
||||
if (socketRef.current) {
|
||||
console.log('Cleaning up notification socket connection...')
|
||||
socketRef.current.disconnect()
|
||||
socketRef.current = null
|
||||
}
|
||||
}
|
||||
} else if (!token && socketRef.current) {
|
||||
console.log('Token not available, disconnecting notification socket...')
|
||||
socketRef.current.disconnect()
|
||||
socketRef.current = null
|
||||
}
|
||||
}, [token, messageApi, notificationApi])
|
||||
|
||||
const showNotificationCenter = () => {
|
||||
setNotificationVisible(true)
|
||||
}
|
||||
|
||||
const hideNotificationCenter = () => {
|
||||
setNotificationVisible(false)
|
||||
}
|
||||
|
||||
const toggleNotificationCenter = () => {
|
||||
setNotificationVisible((prev) => !prev)
|
||||
}
|
||||
|
||||
const updateNotifications = (newNotifications) => {
|
||||
setNotifications(newNotifications)
|
||||
}
|
||||
|
||||
const addNotification = (notification) => {
|
||||
setNotifications((prev) => [notification, ...prev])
|
||||
}
|
||||
|
||||
const removeNotification = (notificationId) => {
|
||||
setNotifications((prev) =>
|
||||
prev.filter((notification) => notification._id !== notificationId)
|
||||
)
|
||||
}
|
||||
|
||||
const markNotificationAsRead = (notificationId) => {
|
||||
setNotifications((prev) =>
|
||||
prev.map((notification) => {
|
||||
if (notification._id === notificationId) {
|
||||
return { ...notification, read: true }
|
||||
}
|
||||
return notification
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const markAllNotificationsAsRead = () => {
|
||||
setNotifications((prev) =>
|
||||
prev.map((notification) => ({ ...notification, read: true }))
|
||||
)
|
||||
}
|
||||
|
||||
const clearAllNotifications = () => {
|
||||
setNotifications([])
|
||||
}
|
||||
|
||||
const getUnreadCount = () => {
|
||||
return notifications.filter((notification) => !notification.read).length
|
||||
}
|
||||
|
||||
return (
|
||||
<NotificationContext.Provider
|
||||
value={{
|
||||
socket: socketRef.current,
|
||||
error,
|
||||
connecting,
|
||||
notifications,
|
||||
notificationVisible,
|
||||
unreadCount: getUnreadCount(),
|
||||
showNotificationCenter,
|
||||
hideNotificationCenter,
|
||||
toggleNotificationCenter,
|
||||
updateNotifications,
|
||||
addNotification,
|
||||
removeNotification,
|
||||
markNotificationAsRead,
|
||||
markAllNotificationsAsRead,
|
||||
clearAllNotifications
|
||||
}}
|
||||
>
|
||||
{contextHolder}
|
||||
{children}
|
||||
|
||||
{/* Notification Drawer */}
|
||||
<Drawer
|
||||
title='Notifications'
|
||||
placement='right'
|
||||
width={400}
|
||||
onClose={hideNotificationCenter}
|
||||
open={notificationVisible}
|
||||
style={{
|
||||
zIndex: 1001
|
||||
}}
|
||||
>
|
||||
<NotificationCenter visible={notificationVisible} />
|
||||
</Drawer>
|
||||
</NotificationContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
NotificationProvider.propTypes = {
|
||||
children: PropTypes.node.isRequired
|
||||
}
|
||||
|
||||
export { NotificationContext, NotificationProvider }
|
||||
@ -1,4 +1,4 @@
|
||||
// src/contexts/SocketContext.js
|
||||
// src/contexts/PrintServerContext.js
|
||||
import React, {
|
||||
createContext,
|
||||
useEffect,
|
||||
@ -11,10 +11,13 @@ import { message, notification } from 'antd'
|
||||
import PropTypes from 'prop-types'
|
||||
import { AuthContext } from './AuthContext'
|
||||
import config from '../../../config'
|
||||
import loglevel from 'loglevel'
|
||||
const log = loglevel.getLogger('Print Server')
|
||||
log.setLevel(config.logLevel)
|
||||
|
||||
const SocketContext = createContext()
|
||||
const PrintServerContext = createContext()
|
||||
|
||||
const SocketProvider = ({ children }) => {
|
||||
const PrintServerProvider = ({ children }) => {
|
||||
const { token } = useContext(AuthContext)
|
||||
const socketRef = useRef(null)
|
||||
const [connecting, setConnecting] = useState(false)
|
||||
@ -24,9 +27,9 @@ const SocketProvider = ({ children }) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
console.log('Token is available, connecting to web socket server...')
|
||||
log.debug('Token is available, connecting to print server...')
|
||||
|
||||
const newSocket = io(config.wsUrl, {
|
||||
const newSocket = io(config.printServerUrl, {
|
||||
reconnectionAttempts: 3,
|
||||
timeout: 3000,
|
||||
auth: { token: token }
|
||||
@ -35,20 +38,20 @@ const SocketProvider = ({ children }) => {
|
||||
setConnecting(true)
|
||||
|
||||
newSocket.on('connect', () => {
|
||||
console.log('Socket connected')
|
||||
log.debug('Print server connected')
|
||||
setConnecting(false)
|
||||
setError(null)
|
||||
})
|
||||
|
||||
newSocket.on('disconnect', () => {
|
||||
console.log('Socket disconnected')
|
||||
setError('Socket disconnected')
|
||||
log.debug('Print server disconnected')
|
||||
setError('Print server disconnected')
|
||||
})
|
||||
|
||||
newSocket.on('connect_error', (err) => {
|
||||
console.error('Socket connection error:', err)
|
||||
messageApi.error('Socket connection error: ' + err.message)
|
||||
setError('Socket connection error')
|
||||
log.error('Print server connection error:', err)
|
||||
messageApi.error('Print server connection error: ' + err.message)
|
||||
setError('Print server connection error')
|
||||
})
|
||||
|
||||
newSocket.on('bridge.notification', (data) => {
|
||||
@ -59,8 +62,8 @@ const SocketProvider = ({ children }) => {
|
||||
})
|
||||
|
||||
newSocket.on('error', (err) => {
|
||||
console.error('Socket error:', err)
|
||||
setError('Socket error')
|
||||
log.error('Print server error:', err)
|
||||
setError('Print server error')
|
||||
})
|
||||
|
||||
socketRef.current = newSocket
|
||||
@ -68,30 +71,30 @@ const SocketProvider = ({ children }) => {
|
||||
// Clean up function
|
||||
return () => {
|
||||
if (socketRef.current) {
|
||||
console.log('Cleaning up socket connection...')
|
||||
log.debug('Cleaning up socket connection...')
|
||||
socketRef.current.disconnect()
|
||||
socketRef.current = null
|
||||
}
|
||||
}
|
||||
} else if (!token && socketRef.current) {
|
||||
console.log('Token not available, disconnecting socket...')
|
||||
log.debug('Token not available, disconnecting socket...')
|
||||
socketRef.current.disconnect()
|
||||
socketRef.current = null
|
||||
}
|
||||
}, [token, messageApi])
|
||||
|
||||
return (
|
||||
<SocketContext.Provider
|
||||
value={{ socket: socketRef.current, error, connecting }}
|
||||
<PrintServerContext.Provider
|
||||
value={{ printServer: socketRef.current, error, connecting }}
|
||||
>
|
||||
{contextHolder}
|
||||
{children}
|
||||
</SocketContext.Provider>
|
||||
</PrintServerContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
SocketProvider.propTypes = {
|
||||
PrintServerProvider.propTypes = {
|
||||
children: PropTypes.node.isRequired
|
||||
}
|
||||
|
||||
export { SocketContext, SocketProvider }
|
||||
export { PrintServerContext, PrintServerProvider }
|
||||
@ -345,24 +345,6 @@ const SpotlightProvider = ({ children }) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Add keyboard shortcut listener
|
||||
useEffect(() => {
|
||||
const handleKeyPress = (e) => {
|
||||
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === 'p') {
|
||||
e.preventDefault() // Prevent browser's default behavior
|
||||
showSpotlight()
|
||||
}
|
||||
}
|
||||
|
||||
// Add event listener
|
||||
window.addEventListener('keydown', handleKeyPress)
|
||||
|
||||
// Clean up
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyPress)
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Focus and select text in input when modal becomes visible
|
||||
useEffect(() => {
|
||||
if (showModal && inputRef.current) {
|
||||
|
||||
7
src/components/Icons/LockIcon.jsx
Normal file
7
src/components/Icons/LockIcon.jsx
Normal file
@ -0,0 +1,7 @@
|
||||
import React from 'react'
|
||||
import Icon from '@ant-design/icons'
|
||||
import { ReactComponent as CustomIconSvg } from '../../assets/icons/lockicon.min.svg'
|
||||
|
||||
const LockIcon = (props) => <Icon component={CustomIconSvg} {...props} />
|
||||
|
||||
export default LockIcon
|
||||
@ -1,11 +1,15 @@
|
||||
const config = {
|
||||
development: {
|
||||
backendUrl: 'http://192.168.68.53:8080',
|
||||
wsUrl: 'ws://192.168.68.53:8081'
|
||||
printServerUrl: 'ws://192.168.68.53:8081',
|
||||
apiServerUrl: 'ws://192.168.68.53:9090',
|
||||
logLevel: 'trace'
|
||||
},
|
||||
production: {
|
||||
backendUrl: 'http://192.168.68.53:8080', // Replace with your production backend URL
|
||||
wsUrl: 'http://192.168.68.53:8081' // Replace with your production WebSocket URL
|
||||
backendUrl: 'http://192.168.68.53:8080',
|
||||
printServerUrl: 'ws://192.168.68.53:8081',
|
||||
apiServerUrl: 'ws://192.168.68.53:9090',
|
||||
logLevel: 'error'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user