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",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"gcode-preview": "^2.18.0",
|
"gcode-preview": "^2.18.0",
|
||||||
"keycloak-js": "^26.2.0",
|
"keycloak-js": "^26.2.0",
|
||||||
"log4js": "^6.9.1",
|
"loglevel": "^1.9.2",
|
||||||
"moment": "*",
|
"moment": "*",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"prettier-eslint": "^16.4.2",
|
"prettier-eslint": "^16.4.2",
|
||||||
@ -9986,15 +9986,6 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"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": {
|
"node_modules/dayjs": {
|
||||||
"version": "1.11.13",
|
"version": "1.11.13",
|
||||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||||
@ -16008,27 +15999,10 @@
|
|||||||
"integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
|
"integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/loglevel": {
|
||||||
"version": "1.9.2",
|
"version": "1.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz",
|
||||||
"integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==",
|
"integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6.0"
|
"node": ">= 0.6.0"
|
||||||
@ -21486,12 +21460,6 @@
|
|||||||
"node": ">=0.10.0"
|
"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": {
|
"node_modules/rimraf": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
@ -22819,52 +22787,6 @@
|
|||||||
"node": ">= 0.4"
|
"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": {
|
"node_modules/string_decoder": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"gcode-preview": "^2.18.0",
|
"gcode-preview": "^2.18.0",
|
||||||
"keycloak-js": "^26.2.0",
|
"keycloak-js": "^26.2.0",
|
||||||
"log4js": "^6.9.1",
|
"loglevel": "^1.9.2",
|
||||||
"moment": "*",
|
"moment": "*",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"prettier-eslint": "^16.4.2",
|
"prettier-eslint": "^16.4.2",
|
||||||
|
|||||||
11
src/App.css
11
src/App.css
@ -22,11 +22,14 @@
|
|||||||
.ant-input,
|
.ant-input,
|
||||||
.ant-input-number .ant-input-number-input,
|
.ant-input-number .ant-input-number-input,
|
||||||
.ant-segmented-item-label,
|
.ant-segmented-item-label,
|
||||||
.ant-badge-status-text {
|
.ant-badge-status-text,
|
||||||
|
.ant-tree-title,
|
||||||
|
.ant-select {
|
||||||
font-family: 'DM Sans';
|
font-family: 'DM Sans';
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-typography code {
|
.ant-typography code,
|
||||||
|
.ant-typography pre {
|
||||||
font-family: 'DM Mono';
|
font-family: 'DM Mono';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +118,10 @@ code {
|
|||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-popover-inner:has(.keyboard-shortcut-tooltip) {
|
||||||
|
padding: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* --- Start of src/index.css --- */
|
/* --- Start of src/index.css --- */
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
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 Dashboard from './components/Dashboard/Dashboard.jsx'
|
||||||
import PrivateRoute from './components/PrivateRoute'
|
import PrivateRoute from './components/PrivateRoute'
|
||||||
import './App.css'
|
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 { AuthProvider } from './components/Dashboard/context/AuthContext.js'
|
||||||
import { SpotlightProvider } from './components/Dashboard/context/SpotlightContext.js'
|
import { SpotlightProvider } from './components/Dashboard/context/SpotlightContext.js'
|
||||||
import StockEvents from './components/Dashboard/Inventory/StockEvents.jsx'
|
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 NoteTypeInfo from './components/Dashboard/Management/NoteTypes/NoteTypeInfo.jsx'
|
||||||
import SessionStorage from './components/Dashboard/Developer/SessionStorage.jsx'
|
import SessionStorage from './components/Dashboard/Developer/SessionStorage.jsx'
|
||||||
import AuthContextDebug from './components/Dashboard/Developer/AuthContextDebug.jsx'
|
import AuthContextDebug from './components/Dashboard/Developer/AuthContextDebug.jsx'
|
||||||
import SocketContextDebug from './components/Dashboard/Developer/SocketContextDebug.jsx'
|
import PrintServerContextDebug from './components/Dashboard/Developer/PrintServerContextDebug.jsx'
|
||||||
import { NotificationProvider } from './components/Dashboard/context/NotificationContext.js'
|
import { ApiServerProvider } from './components/Dashboard/context/ApiServerContext.js'
|
||||||
import Users from './components/Dashboard/Management/Users.jsx'
|
import Users from './components/Dashboard/Management/Users.jsx'
|
||||||
import UserInfo from './components/Dashboard/Management/Users/UserInfo.jsx'
|
import UserInfo from './components/Dashboard/Management/Users/UserInfo.jsx'
|
||||||
|
|
||||||
@ -74,8 +74,8 @@ const AppContent = () => {
|
|||||||
<App>
|
<App>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<Router>
|
<Router>
|
||||||
<SocketProvider>
|
<PrintServerProvider>
|
||||||
<NotificationProvider>
|
<ApiServerProvider>
|
||||||
<SpotlightProvider>
|
<SpotlightProvider>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
@ -213,8 +213,8 @@ const AppContent = () => {
|
|||||||
element={<AuthContextDebug />}
|
element={<AuthContextDebug />}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path='developer/socketcontextdebug'
|
path='developer/printservercontextdebug'
|
||||||
element={<SocketContextDebug />}
|
element={<PrintServerContextDebug />}
|
||||||
/>
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
<Route
|
<Route
|
||||||
@ -228,8 +228,8 @@ const AppContent = () => {
|
|||||||
/>
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</SpotlightProvider>
|
</SpotlightProvider>
|
||||||
</NotificationProvider>
|
</ApiServerProvider>
|
||||||
</SocketProvider>
|
</PrintServerProvider>
|
||||||
</Router>
|
</Router>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</App>
|
</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 React from 'react'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import DashboardSidebar from '../common/DashboardSidebar'
|
import DashboardSidebar from '../common/DashboardSidebar'
|
||||||
|
import { Typography } from 'antd'
|
||||||
|
|
||||||
|
const { Text } = Typography
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
key: 'sessionstorage',
|
key: 'sessionstorage',
|
||||||
label: 'Session Storage',
|
label: 'Session Storage',
|
||||||
|
icon: <Text>🗃️</Text>,
|
||||||
path: '/dashboard/developer/sessionstorage'
|
path: '/dashboard/developer/sessionstorage'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'authcontextdebug',
|
key: 'authcontextdebug',
|
||||||
label: 'Auth Context Debug',
|
label: 'Auth Debug',
|
||||||
|
icon: <Text>🔐</Text>,
|
||||||
path: '/dashboard/developer/authcontextdebug'
|
path: '/dashboard/developer/authcontextdebug'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'socketcontextdebug',
|
key: 'printservercontextdebug',
|
||||||
label: 'Socket Context Debug',
|
label: 'Print Server Debug',
|
||||||
path: '/dashboard/developer/socketcontextdebug'
|
icon: <Text>🖨️</Text>,
|
||||||
|
path: '/dashboard/developer/printservercontextdebug'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const routeKeyMap = {
|
const routeKeyMap = {
|
||||||
'/dashboard/developer/sessionstorage': 'sessionstorage',
|
'/dashboard/developer/sessionstorage': 'sessionstorage',
|
||||||
'/dashboard/developer/authcontext': 'authcontextdebug',
|
'/dashboard/developer/authcontext': 'authcontextdebug',
|
||||||
'/dashboard/developer/socketcontext': 'socketcontextdebug'
|
'/dashboard/developer/printservercontext': 'printservercontextdebug'
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeveloperSidebar = (props) => {
|
const DeveloperSidebar = (props) => {
|
||||||
|
|||||||
@ -9,13 +9,13 @@ import {
|
|||||||
message
|
message
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import ReloadIcon from '../../Icons/ReloadIcon.jsx'
|
import ReloadIcon from '../../Icons/ReloadIcon.jsx'
|
||||||
import { SocketContext } from '../context/SocketContext.js'
|
import { PrintServerContext } from '../context/PrintServerContext.js'
|
||||||
import BoolDisplay from '../common/BoolDisplay.jsx'
|
import BoolDisplay from '../common/BoolDisplay.jsx'
|
||||||
|
|
||||||
const { Text, Paragraph } = Typography
|
const { Text, Paragraph } = Typography
|
||||||
|
|
||||||
const SocketContextDebug = () => {
|
const PrintServerContextDebug = () => {
|
||||||
const { socket, error, connecting } = useContext(SocketContext)
|
const { printServer, error, connecting } = useContext(PrintServerContext)
|
||||||
const [msgApi, contextHolder] = message.useMessage()
|
const [msgApi, contextHolder] = message.useMessage()
|
||||||
|
|
||||||
const actionItems = {
|
const actionItems = {
|
||||||
@ -36,9 +36,9 @@ const SocketContextDebug = () => {
|
|||||||
|
|
||||||
// Helper to display socket info safely
|
// Helper to display socket info safely
|
||||||
const getSocketInfo = () => {
|
const getSocketInfo = () => {
|
||||||
if (!socket) return 'n/a'
|
if (!printServer) return 'n/a'
|
||||||
// Only show safe properties
|
// 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)
|
return JSON.stringify({ id, connected, disconnected, nsp }, null, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ const SocketContextDebug = () => {
|
|||||||
<div style={{ height: '100%', overflow: 'auto' }}>
|
<div style={{ height: '100%', overflow: 'auto' }}>
|
||||||
<Descriptions bordered column={1}>
|
<Descriptions bordered column={1}>
|
||||||
<Descriptions.Item label='Connected'>
|
<Descriptions.Item label='Connected'>
|
||||||
<BoolDisplay value={socket?.connected || false} />
|
<BoolDisplay value={printServer?.connected || false} />
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label='Connecting'>
|
<Descriptions.Item label='Connecting'>
|
||||||
<BoolDisplay value={connecting} />
|
<BoolDisplay value={connecting} />
|
||||||
@ -74,4 +74,4 @@ const SocketContextDebug = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SocketContextDebug
|
export default PrintServerContextDebug
|
||||||
@ -16,7 +16,7 @@ import {
|
|||||||
} from 'antd'
|
} from 'antd'
|
||||||
|
|
||||||
import { AuthContext } from '../context/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
|
|
||||||
import NewFilamentStock from './FilamentStocks/NewFilamentStock'
|
import NewFilamentStock from './FilamentStocks/NewFilamentStock'
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
@ -41,7 +41,7 @@ const { Text } = Typography
|
|||||||
const FilamentStocks = () => {
|
const FilamentStocks = () => {
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
const tableRef = useRef()
|
const tableRef = useRef()
|
||||||
|
|
||||||
@ -213,9 +213,9 @@ const FilamentStocks = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (socket && !initialized) {
|
if (printServer && !initialized) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
socket.on('notify_filamentstock_update', (updateData) => {
|
printServer.on('notify_filamentstock_update', (updateData) => {
|
||||||
console.log('Received filament stock update:', updateData)
|
console.log('Received filament stock update:', updateData)
|
||||||
if (tableRef.current) {
|
if (tableRef.current) {
|
||||||
tableRef.current.updateData(updateData._id, updateData)
|
tableRef.current.updateData(updateData._id, updateData)
|
||||||
@ -224,12 +224,12 @@ const FilamentStocks = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
console.log('Deregistering filament stock update listener')
|
console.log('Deregistering filament stock update listener')
|
||||||
socket.off('notify_filamentstock_update')
|
printServer.off('notify_filamentstock_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, initialized])
|
}, [printServer, initialized])
|
||||||
|
|
||||||
const getFilamentStockActionItems = (id) => {
|
const getFilamentStockActionItems = (id) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import {
|
|||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
||||||
import IdText from '../../common/IdText'
|
import IdText from '../../common/IdText'
|
||||||
import { SocketContext } from '../../context/SocketContext'
|
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||||
import FilamentStockState from '../../common/FilamentStockState'
|
import FilamentStockState from '../../common/FilamentStockState'
|
||||||
import StockEventTable from '../../common/StockEventTable'
|
import StockEventTable from '../../common/StockEventTable'
|
||||||
import useCollapseState from '../../hooks/useCollapseState'
|
import useCollapseState from '../../hooks/useCollapseState'
|
||||||
@ -48,7 +48,7 @@ const FilamentStockInfo = () => {
|
|||||||
'filamentStockId'
|
'filamentStockId'
|
||||||
)
|
)
|
||||||
const [form] = Form.useForm()
|
const [form] = Form.useForm()
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [collapseState, updateCollapseState] = useCollapseState(
|
const [collapseState, updateCollapseState] = useCollapseState(
|
||||||
'FilamentStockInfo',
|
'FilamentStockInfo',
|
||||||
{
|
{
|
||||||
@ -75,9 +75,9 @@ const FilamentStockInfo = () => {
|
|||||||
|
|
||||||
// Add WebSocket event listener for real-time updates
|
// Add WebSocket event listener for real-time updates
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket && !initialized && filamentStockId) {
|
if (printServer && !initialized && filamentStockId) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
socket.on('notify_filamentstock_update', (statusUpdate) => {
|
printServer.on('notify_filamentstock_update', (statusUpdate) => {
|
||||||
console.log('GOT FILAMENT STOCK UPDATE', statusUpdate)
|
console.log('GOT FILAMENT STOCK UPDATE', statusUpdate)
|
||||||
setFilamentStockData((prevData) => {
|
setFilamentStockData((prevData) => {
|
||||||
if (statusUpdate?._id === filamentStockId) {
|
if (statusUpdate?._id === filamentStockId) {
|
||||||
@ -91,12 +91,12 @@ const FilamentStockInfo = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
console.log('Deregistering filament stock update listener')
|
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 () => {
|
const fetchFilamentStockDetails = async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { useMediaQuery } from 'react-responsive'
|
import { useMediaQuery } from 'react-responsive'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { SocketContext } from '../../context/SocketContext'
|
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||||
|
|
||||||
import FilamentStockSelect from '../../common/FilamentStockSelect'
|
import FilamentStockSelect from '../../common/FilamentStockSelect'
|
||||||
import PrinterSelect from '../../common/PrinterSelect'
|
import PrinterSelect from '../../common/PrinterSelect'
|
||||||
@ -38,7 +38,7 @@ const LoadFilamentStock = ({
|
|||||||
filamentStockLoaded: PropTypes.bool
|
filamentStockLoaded: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
|
|
||||||
const initialLoadFilamentStockForm = {
|
const initialLoadFilamentStockForm = {
|
||||||
printer: printer,
|
printer: printer,
|
||||||
@ -93,16 +93,16 @@ const LoadFilamentStock = ({
|
|||||||
console.log(statusUpdate)
|
console.log(statusUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit('printer.objects.subscribe', params)
|
printServer.emit('printer.objects.subscribe', params)
|
||||||
socket.emit('printer.objects.query', params)
|
printServer.emit('printer.objects.query', params)
|
||||||
socket.on('notify_status_update', notifyStatusUpdate)
|
printServer.on('notify_status_update', notifyStatusUpdate)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.off('notify_status_update', notifyStatusUpdate)
|
printServer.off('notify_status_update', notifyStatusUpdate)
|
||||||
socket.emit('printer.objects.unsubscribe', params)
|
printServer.emit('printer.objects.unsubscribe', params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, loadFilamentStockFormValues.printer])
|
}, [printServer, loadFilamentStockFormValues.printer])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
loadFilamentStockForm
|
loadFilamentStockForm
|
||||||
@ -170,7 +170,7 @@ const LoadFilamentStock = ({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Set the extruder temperature
|
// Set the extruder temperature
|
||||||
await socket.emit('printer.filamentstock.load', {
|
await printServer.emit('printer.filamentstock.load', {
|
||||||
printerId: loadFilamentStockFormValues.printer._id,
|
printerId: loadFilamentStockFormValues.printer._id,
|
||||||
filamentStockId: loadFilamentStockFormValues.filamentStock._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 { Form, Button, Typography, Flex, Steps, Divider, Alert } from 'antd'
|
||||||
import { useMediaQuery } from 'react-responsive'
|
import { useMediaQuery } from 'react-responsive'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { SocketContext } from '../../context/SocketContext'
|
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||||
|
|
||||||
import PrinterSelect from '../../common/PrinterSelect'
|
import PrinterSelect from '../../common/PrinterSelect'
|
||||||
import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'
|
import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'
|
||||||
@ -18,7 +18,7 @@ const UnloadFilamentStock = ({ onOk, reset, printer = null }) => {
|
|||||||
printer: PropTypes.object
|
printer: PropTypes.object
|
||||||
}
|
}
|
||||||
|
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||||
|
|
||||||
const initialUnloadFilamentStockForm = {
|
const initialUnloadFilamentStockForm = {
|
||||||
@ -66,16 +66,16 @@ const UnloadFilamentStock = ({ onOk, reset, printer = null }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit('printer.objects.subscribe', params)
|
printServer.emit('printer.objects.subscribe', params)
|
||||||
socket.emit('printer.objects.query', params)
|
printServer.emit('printer.objects.query', params)
|
||||||
socket.on('notify_status_update', notifyStatusUpdate)
|
printServer.on('notify_status_update', notifyStatusUpdate)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.off('notify_status_update', notifyStatusUpdate)
|
printServer.off('notify_status_update', notifyStatusUpdate)
|
||||||
socket.emit('printer.objects.unsubscribe', params)
|
printServer.emit('printer.objects.unsubscribe', params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, unloadFilamentStockFormValues.printer])
|
}, [printServer, unloadFilamentStockFormValues.printer])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (reset) {
|
if (reset) {
|
||||||
@ -109,7 +109,7 @@ const UnloadFilamentStock = ({ onOk, reset, printer = null }) => {
|
|||||||
const handleUnloadFilamentStock = async () => {
|
const handleUnloadFilamentStock = async () => {
|
||||||
setUnloadFilamentStockLoading(true)
|
setUnloadFilamentStockLoading(true)
|
||||||
// Send G-code to retract the filament
|
// Send G-code to retract the filament
|
||||||
await socket.emit('printer.gcode.script', {
|
await printServer.emit('printer.gcode.script', {
|
||||||
printerId: unloadFilamentStockFormValues.printer._id,
|
printerId: unloadFilamentStockFormValues.printer._id,
|
||||||
script: `_CLIENT_LINEAR_MOVE E=-200 F=1000`
|
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 { Button, Flex, Space, message, Dropdown, Typography } from 'antd'
|
||||||
|
|
||||||
import { AuthContext } from '../context/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
|
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
import StockAuditIcon from '../../Icons/StockAuditIcon'
|
import StockAuditIcon from '../../Icons/StockAuditIcon'
|
||||||
@ -20,16 +20,16 @@ const { Text } = Typography
|
|||||||
const StockAudits = () => {
|
const StockAudits = () => {
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
const tableRef = useRef()
|
const tableRef = useRef()
|
||||||
|
|
||||||
const { authenticated } = useContext(AuthContext)
|
const { authenticated } = useContext(AuthContext)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (socket && !initialized) {
|
if (printServer && !initialized) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
socket.on('notify_stockaudit_update', (updateData) => {
|
printServer.on('notify_stockaudit_update', (updateData) => {
|
||||||
console.log('Received stock audit update:', updateData)
|
console.log('Received stock audit update:', updateData)
|
||||||
if (tableRef.current) {
|
if (tableRef.current) {
|
||||||
tableRef.current.updateData(updateData._id, updateData)
|
tableRef.current.updateData(updateData._id, updateData)
|
||||||
@ -38,12 +38,12 @@ const StockAudits = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
console.log('Deregistering stock audit update listener')
|
console.log('Deregistering stock audit update listener')
|
||||||
socket.off('notify_stockaudit_update')
|
printServer.off('notify_stockaudit_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, initialized])
|
}, [printServer, initialized])
|
||||||
|
|
||||||
const getStockAuditActionItems = (id) => {
|
const getStockAuditActionItems = (id) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
} from 'antd'
|
} from 'antd'
|
||||||
|
|
||||||
import { AuthContext } from '../context/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
import TimeDisplay from '../common/TimeDisplay'
|
import TimeDisplay from '../common/TimeDisplay'
|
||||||
import ReloadIcon from '../../Icons/ReloadIcon'
|
import ReloadIcon from '../../Icons/ReloadIcon'
|
||||||
@ -31,7 +31,7 @@ import StockEventIcon from '../../Icons/StockEventIcon'
|
|||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
|
|
||||||
const StockEvents = () => {
|
const StockEvents = () => {
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
const tableRef = useRef()
|
const tableRef = useRef()
|
||||||
const [viewMode, setViewMode] = useViewMode('StockEvents')
|
const [viewMode, setViewMode] = useViewMode('StockEvents')
|
||||||
@ -225,9 +225,9 @@ const StockEvents = () => {
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
// Add WebSocket event listener for real-time updates
|
// Add WebSocket event listener for real-time updates
|
||||||
if (socket && !initialized) {
|
if (printServer && !initialized) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
socket.on('notify_stockevent_update', (updateData) => {
|
printServer.on('notify_stockevent_update', (updateData) => {
|
||||||
console.log('Received stock event update:', updateData)
|
console.log('Received stock event update:', updateData)
|
||||||
if (tableRef.current) {
|
if (tableRef.current) {
|
||||||
tableRef.current.updateData(updateData._id, updateData)
|
tableRef.current.updateData(updateData._id, updateData)
|
||||||
@ -236,12 +236,12 @@ const StockEvents = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
console.log('Deregistering stock event update listener')
|
console.log('Deregistering stock event update listener')
|
||||||
socket.off('notify_stockevent_update')
|
printServer.off('notify_stockevent_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, initialized])
|
}, [printServer, initialized])
|
||||||
|
|
||||||
const actionItems = {
|
const actionItems = {
|
||||||
items: [
|
items: [
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect, useContext, useCallback } from 'react'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import axios from 'axios'
|
|
||||||
import {
|
import {
|
||||||
Descriptions,
|
Descriptions,
|
||||||
Spin,
|
Spin,
|
||||||
@ -15,13 +14,15 @@ import {
|
|||||||
InputNumber,
|
InputNumber,
|
||||||
ColorPicker,
|
ColorPicker,
|
||||||
Select,
|
Select,
|
||||||
Collapse,
|
|
||||||
Dropdown,
|
Dropdown,
|
||||||
Popover,
|
Popover,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Card
|
Card,
|
||||||
|
Tag
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
import loglevel from 'loglevel'
|
||||||
|
import config from '../../../../config'
|
||||||
import IdText from '../../common/IdText'
|
import IdText from '../../common/IdText'
|
||||||
import ReloadIcon from '../../../Icons/ReloadIcon'
|
import ReloadIcon from '../../../Icons/ReloadIcon'
|
||||||
import EditIcon from '../../../Icons/EditIcon.jsx'
|
import EditIcon from '../../../Icons/EditIcon.jsx'
|
||||||
@ -32,19 +33,25 @@ import VendorSelect from '../../common/VendorSelect'
|
|||||||
import useCollapseState from '../../hooks/useCollapseState'
|
import useCollapseState from '../../hooks/useCollapseState'
|
||||||
import AuditLogTable from '../../common/AuditLogTable'
|
import AuditLogTable from '../../common/AuditLogTable'
|
||||||
import DashboardNotes from '../../common/DashboardNotes'
|
import DashboardNotes from '../../common/DashboardNotes'
|
||||||
|
import InfoCollapse from '../../common/InfoCollapse'
|
||||||
|
|
||||||
import config from '../../../../config.js'
|
|
||||||
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
|
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
|
||||||
import NoteIcon from '../../../Icons/NoteIcon.jsx'
|
import NoteIcon from '../../../Icons/NoteIcon.jsx'
|
||||||
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
|
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
|
||||||
|
import LockIcon from '../../../Icons/LockIcon.jsx'
|
||||||
|
import { ApiServerContext } from '../../context/ApiServerContext'
|
||||||
|
|
||||||
const { Title, Link, Text } = Typography
|
const log = loglevel.getLogger('FilamentInfo')
|
||||||
|
log.setLevel(config.logLevel)
|
||||||
|
|
||||||
|
const { Link, Text } = Typography
|
||||||
|
|
||||||
const FilamentInfo = () => {
|
const FilamentInfo = () => {
|
||||||
const [filamentData, setFilamentData] = useState(null)
|
const [filamentData, setFilamentData] = useState(null)
|
||||||
const [fetchLoading, setFetchLoading] = useState(true)
|
const [fetchLoading, setFetchLoading] = useState(true)
|
||||||
const [editLoading, setEditLoading] = useState(false)
|
const [editLoading, setEditLoading] = useState(false)
|
||||||
const [error, setError] = useState(null)
|
const [lockUser, setLockUser] = useState(null)
|
||||||
|
const [initialized, setInitialized] = useState(false)
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
const filamentId = new URLSearchParams(location.search).get('filamentId')
|
const filamentId = new URLSearchParams(location.search).get('filamentId')
|
||||||
@ -59,12 +66,36 @@ const FilamentInfo = () => {
|
|||||||
auditLogs: true
|
auditLogs: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
const {
|
||||||
|
apiServer,
|
||||||
|
fetchObjectInfo,
|
||||||
|
updateObjectInfo,
|
||||||
|
lockObject,
|
||||||
|
unlockObject,
|
||||||
|
onLockEvent,
|
||||||
|
onUpdateEvent,
|
||||||
|
fetchObjectLock,
|
||||||
|
showError
|
||||||
|
} = useContext(ApiServerContext)
|
||||||
|
|
||||||
useEffect(() => {
|
// Define the event handler function
|
||||||
if (filamentId) {
|
const lockEventHandler = useCallback((lockEvent) => {
|
||||||
fetchFilamentDetails()
|
if (lockEvent.locked === true) {
|
||||||
|
setLockUser(lockEvent.user)
|
||||||
|
} else {
|
||||||
|
setLockUser(null)
|
||||||
}
|
}
|
||||||
}, [filamentId])
|
}, [])
|
||||||
|
|
||||||
|
// Cleanup effect for component unmount
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (filamentId) {
|
||||||
|
// Ensure any remaining locks are released when component unmounts
|
||||||
|
unlockObject(filamentId, 'filament')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [filamentId, unlockObject])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (filamentData) {
|
if (filamentData) {
|
||||||
@ -83,32 +114,84 @@ const FilamentInfo = () => {
|
|||||||
}
|
}
|
||||||
}, [filamentData, form])
|
}, [filamentData, form])
|
||||||
|
|
||||||
const fetchFilamentDetails = async () => {
|
const fetchFilamentInfo = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
setFetchLoading(true)
|
setFetchLoading(true)
|
||||||
const response = await axios.get(
|
const data = await fetchObjectInfo(filamentId, 'filament')
|
||||||
`${config.backendUrl}/filaments/${filamentId}`,
|
const lockEvent = await fetchObjectLock(filamentId, 'filament')
|
||||||
{
|
setLockUser(lockEvent?.user || null)
|
||||||
headers: {
|
setFilamentData(data)
|
||||||
Accept: 'application/json'
|
form.setFieldsValue(data)
|
||||||
},
|
|
||||||
withCredentials: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
setFilamentData(response.data)
|
|
||||||
form.setFieldsValue(response.data)
|
|
||||||
setError(null)
|
|
||||||
} catch (err) {
|
|
||||||
setError('Failed to fetch filament details')
|
|
||||||
messageApi.error('Failed to fetch filament details')
|
|
||||||
} finally {
|
|
||||||
setFetchLoading(false)
|
setFetchLoading(false)
|
||||||
|
} catch (err) {
|
||||||
|
messageApi.error('Failed to fetch filament info')
|
||||||
|
// Show error modal with retry functionality
|
||||||
|
showError(
|
||||||
|
`Failed to fetch filament information. Message: ${err.message}. Code: ${err.code}`,
|
||||||
|
fetchFilamentInfo
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}, [
|
||||||
|
fetchObjectInfo,
|
||||||
|
fetchObjectLock,
|
||||||
|
filamentId,
|
||||||
|
form,
|
||||||
|
messageApi,
|
||||||
|
showError
|
||||||
|
])
|
||||||
|
|
||||||
|
const updateFilamentInfo = async () => {
|
||||||
|
const values = form.getFieldsValue()
|
||||||
|
const updateValue = {
|
||||||
|
name: values.name,
|
||||||
|
vendor: values.vendor,
|
||||||
|
type: values.type,
|
||||||
|
cost: values.cost,
|
||||||
|
color: values.color,
|
||||||
|
diameter: values.diameter,
|
||||||
|
density: values.density,
|
||||||
|
url: values.url,
|
||||||
|
barcode: values.barcode,
|
||||||
|
emptySpoolWeight: values.emptySpoolWeight
|
||||||
}
|
}
|
||||||
|
await updateObjectInfo(filamentId, 'filament', updateValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the update event handler function
|
||||||
|
const updateEventHandler = useCallback(
|
||||||
|
(updateEvent) => {
|
||||||
|
log.debug('Update event received for filament:', updateEvent)
|
||||||
|
// Refresh the filament data when an update is received
|
||||||
|
fetchFilamentInfo()
|
||||||
|
},
|
||||||
|
[fetchFilamentInfo]
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (initialized == false && filamentId && apiServer?.connected === true) {
|
||||||
|
setInitialized(true)
|
||||||
|
fetchFilamentInfo()
|
||||||
|
}
|
||||||
|
}, [filamentId, apiServer?.connected, initialized, fetchFilamentInfo])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (filamentId) {
|
||||||
|
const cleanup = onLockEvent(filamentId, lockEventHandler)
|
||||||
|
return cleanup
|
||||||
|
}
|
||||||
|
}, [filamentId, onLockEvent, lockEventHandler])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (filamentId) {
|
||||||
|
const cleanup = onUpdateEvent(filamentId, updateEventHandler)
|
||||||
|
return cleanup
|
||||||
|
}
|
||||||
|
}, [filamentId, onUpdateEvent, updateEventHandler])
|
||||||
|
|
||||||
const startEditing = () => {
|
const startEditing = () => {
|
||||||
updateCollapseState('info', true)
|
updateCollapseState('info', true)
|
||||||
setIsEditing(true)
|
setIsEditing(true)
|
||||||
|
lockObject(filamentId, 'filament')
|
||||||
}
|
}
|
||||||
|
|
||||||
const cancelEditing = () => {
|
const cancelEditing = () => {
|
||||||
@ -128,34 +211,15 @@ const FilamentInfo = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
setIsEditing(false)
|
setIsEditing(false)
|
||||||
|
unlockObject(filamentId, 'filament')
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateFilamentInfo = async () => {
|
const handleUpdateFilamentInfo = async () => {
|
||||||
try {
|
try {
|
||||||
const values = await form.validateFields()
|
const values = await form.validateFields()
|
||||||
setEditLoading(true)
|
setEditLoading(true)
|
||||||
|
|
||||||
await axios.put(
|
await updateFilamentInfo()
|
||||||
`${config.backendUrl}/filaments/${filamentId}`,
|
|
||||||
{
|
|
||||||
name: values.name,
|
|
||||||
vendor: values.vendor,
|
|
||||||
type: values.type,
|
|
||||||
cost: values.cost,
|
|
||||||
color: values.color,
|
|
||||||
diameter: values.diameter,
|
|
||||||
density: values.density,
|
|
||||||
url: values.url,
|
|
||||||
barcode: values.barcode,
|
|
||||||
emptySpoolWeight: values.emptySpoolWeight
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
withCredentials: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Update the local state with the new values
|
// Update the local state with the new values
|
||||||
setFilamentData({ ...filamentData, ...values })
|
setFilamentData({ ...filamentData, ...values })
|
||||||
@ -168,8 +232,13 @@ const FilamentInfo = () => {
|
|||||||
}
|
}
|
||||||
console.error('Failed to update filament information:', err)
|
console.error('Failed to update filament information:', err)
|
||||||
messageApi.error('Failed to update filament information')
|
messageApi.error('Failed to update filament information')
|
||||||
|
// Show error modal with retry functionality
|
||||||
|
showError(
|
||||||
|
`Failed to update filament information. Message: ${err.message}. Code: ${err.code}`,
|
||||||
|
() => handleUpdateFilamentInfo()
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
fetchFilamentDetails()
|
fetchFilamentInfo()
|
||||||
setEditLoading(false)
|
setEditLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,7 +253,7 @@ const FilamentInfo = () => {
|
|||||||
],
|
],
|
||||||
onClick: ({ key }) => {
|
onClick: ({ key }) => {
|
||||||
if (key === 'reload') {
|
if (key === 'reload') {
|
||||||
fetchFilamentDetails()
|
fetchFilamentInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,20 +284,6 @@ const FilamentInfo = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<Space
|
|
||||||
direction='vertical'
|
|
||||||
style={{ width: '100%', textAlign: 'center' }}
|
|
||||||
>
|
|
||||||
<p>{error || 'Filament not found'}</p>
|
|
||||||
<Button icon={<ReloadIcon />} onClick={fetchFilamentDetails}>
|
|
||||||
Retry
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
@ -238,25 +293,42 @@ const FilamentInfo = () => {
|
|||||||
style={{ height: '100%', minHeight: 0 }}
|
style={{ height: '100%', minHeight: 0 }}
|
||||||
>
|
>
|
||||||
<Flex justify={'space-between'}>
|
<Flex justify={'space-between'}>
|
||||||
|
<Space size='middle'>
|
||||||
<Space size='small'>
|
<Space size='small'>
|
||||||
<Dropdown menu={actionItems}>
|
<Dropdown menu={actionItems}>
|
||||||
<Button>Actions</Button>
|
<Button disabled={fetchLoading}>Actions</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
<Popover
|
<Popover
|
||||||
content={getViewDropdownItems()}
|
content={getViewDropdownItems()}
|
||||||
placement='bottomLeft'
|
placement='bottomLeft'
|
||||||
arrow={false}
|
arrow={false}
|
||||||
>
|
>
|
||||||
<Button>View</Button>
|
<Button disabled={fetchLoading}>View</Button>
|
||||||
</Popover>
|
</Popover>
|
||||||
</Space>
|
</Space>
|
||||||
|
{lockUser && (
|
||||||
|
<Flex gap={'small'} align='center'>
|
||||||
|
<Tag
|
||||||
|
icon={<LockIcon />}
|
||||||
|
style={{ margin: 0 }}
|
||||||
|
color={'orange'}
|
||||||
|
/>
|
||||||
|
<IdText
|
||||||
|
id={lockUser}
|
||||||
|
type={'user'}
|
||||||
|
longId={false}
|
||||||
|
showCopy={false}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
{isEditing ? (
|
{isEditing ? (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
icon={<CheckIcon />}
|
icon={<CheckIcon />}
|
||||||
type='primary'
|
type='primary'
|
||||||
onClick={updateFilamentInfo}
|
onClick={handleUpdateFilamentInfo}
|
||||||
loading={editLoading}
|
loading={editLoading}
|
||||||
disabled={editLoading}
|
disabled={editLoading}
|
||||||
/>
|
/>
|
||||||
@ -267,46 +339,24 @@ const FilamentInfo = () => {
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Button icon={<EditIcon />} onClick={startEditing} />
|
<Button
|
||||||
|
icon={<EditIcon />}
|
||||||
|
onClick={startEditing}
|
||||||
|
disabled={lockUser !== null || fetchLoading}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
{error ? (
|
|
||||||
<Space
|
|
||||||
direction='vertical'
|
|
||||||
style={{ width: '100%', textAlign: 'center' }}
|
|
||||||
>
|
|
||||||
<p>{error || 'Print job not found'}</p>
|
|
||||||
<Button icon={<ReloadIcon />} onClick={fetchFilamentDetails}>
|
|
||||||
Retry
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
) : (
|
|
||||||
<div style={{ height: '100%', overflow: 'auto' }}>
|
<div style={{ height: '100%', overflow: 'auto' }}>
|
||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<Collapse
|
<InfoCollapse
|
||||||
ghost
|
title='Filament Information'
|
||||||
expandIconPosition='end'
|
icon={<InfoCircleIcon />}
|
||||||
activeKey={collapseState.info ? ['1'] : []}
|
active={collapseState.info}
|
||||||
onChange={(keys) =>
|
onToggle={(expanded) => updateCollapseState('info', expanded)}
|
||||||
updateCollapseState('info', keys.length > 0)
|
className='no-t-padding-collapse'
|
||||||
}
|
key='info'
|
||||||
expandIcon={({ isActive }) => (
|
|
||||||
<CaretLeftOutlined rotate={isActive ? -90 : 0} />
|
|
||||||
)}
|
|
||||||
className='no-h-padding-collapse no-t-padding-collapse'
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
header={
|
|
||||||
<Flex align='center' gap={'middle'}>
|
|
||||||
<InfoCircleIcon />
|
|
||||||
<Title level={5} style={{ margin: 0 }}>
|
|
||||||
Filament Information
|
|
||||||
</Title>
|
|
||||||
</Flex>
|
|
||||||
}
|
|
||||||
key='1'
|
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
@ -323,10 +373,7 @@ const FilamentInfo = () => {
|
|||||||
barcode: filamentData?.barcode || ''
|
barcode: filamentData?.barcode || ''
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Spin
|
<Spin indicator={<LoadingOutlined />} spinning={fetchLoading}>
|
||||||
indicator={<LoadingOutlined />}
|
|
||||||
spinning={fetchLoading}
|
|
||||||
>
|
|
||||||
<Descriptions
|
<Descriptions
|
||||||
bordered
|
bordered
|
||||||
column={{
|
column={{
|
||||||
@ -519,10 +566,7 @@ const FilamentInfo = () => {
|
|||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber suffix='mm' style={{ width: '100%' }} />
|
||||||
suffix='mm'
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
) : filamentData?.diameter ? (
|
) : filamentData?.diameter ? (
|
||||||
<Text>{`${filamentData.diameter}mm`}</Text>
|
<Text>{`${filamentData.diameter}mm`}</Text>
|
||||||
@ -583,58 +627,26 @@ const FilamentInfo = () => {
|
|||||||
</Descriptions>
|
</Descriptions>
|
||||||
</Spin>
|
</Spin>
|
||||||
</Form>
|
</Form>
|
||||||
</Collapse.Panel>
|
</InfoCollapse>
|
||||||
</Collapse>
|
|
||||||
|
|
||||||
<Collapse
|
<InfoCollapse
|
||||||
ghost
|
title='Notes'
|
||||||
expandIconPosition='end'
|
icon={<NoteIcon />}
|
||||||
activeKey={collapseState.notes ? ['notes'] : []}
|
active={collapseState.notes}
|
||||||
onChange={(keys) =>
|
onToggle={(expanded) => updateCollapseState('notes', expanded)}
|
||||||
updateCollapseState('notes', keys.length > 0)
|
|
||||||
}
|
|
||||||
expandIcon={({ isActive }) => (
|
|
||||||
<CaretLeftOutlined rotate={isActive ? -90 : 0} />
|
|
||||||
)}
|
|
||||||
className='no-h-padding-collapse'
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
header={
|
|
||||||
<Flex align='center' gap={'middle'}>
|
|
||||||
<NoteIcon />
|
|
||||||
<Title level={5} style={{ margin: 0 }}>
|
|
||||||
Notes
|
|
||||||
</Title>
|
|
||||||
</Flex>
|
|
||||||
}
|
|
||||||
key='notes'
|
key='notes'
|
||||||
>
|
>
|
||||||
<Card>
|
<Card>
|
||||||
<DashboardNotes _id={filamentId} />
|
<DashboardNotes _id={filamentId} />
|
||||||
</Card>
|
</Card>
|
||||||
</Collapse.Panel>
|
</InfoCollapse>
|
||||||
</Collapse>
|
|
||||||
|
|
||||||
<Collapse
|
<InfoCollapse
|
||||||
ghost
|
title='Audit Logs'
|
||||||
expandIconPosition='end'
|
icon={<AuditLogIcon />}
|
||||||
activeKey={collapseState.auditLogs ? ['auditLogs'] : []}
|
active={collapseState.auditLogs}
|
||||||
onChange={(keys) =>
|
onToggle={(expanded) =>
|
||||||
updateCollapseState('auditLogs', keys.length > 0)
|
updateCollapseState('auditLogs', expanded)
|
||||||
}
|
|
||||||
expandIcon={({ isActive }) => (
|
|
||||||
<CaretLeftOutlined rotate={isActive ? -90 : 0} />
|
|
||||||
)}
|
|
||||||
className='no-h-padding-collapse'
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
header={
|
|
||||||
<Flex align='center' gap={'middle'}>
|
|
||||||
<AuditLogIcon />
|
|
||||||
<Title level={5} style={{ margin: 0 }}>
|
|
||||||
Audit Logs
|
|
||||||
</Title>
|
|
||||||
</Flex>
|
|
||||||
}
|
}
|
||||||
key='auditLogs'
|
key='auditLogs'
|
||||||
>
|
>
|
||||||
@ -643,11 +655,9 @@ const FilamentInfo = () => {
|
|||||||
loading={fetchLoading}
|
loading={fetchLoading}
|
||||||
showTargetColumn={false}
|
showTargetColumn={false}
|
||||||
/>
|
/>
|
||||||
</Collapse.Panel>
|
</InfoCollapse>
|
||||||
</Collapse>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -72,7 +72,7 @@ const NewGCodeFile = ({ onOk, reset }) => {
|
|||||||
|
|
||||||
const { token, authenticated } = useContext(AuthContext)
|
const { token, authenticated } = useContext(AuthContext)
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const fetchFilamentDetails = async () => {
|
const fetchFilamentInfo = async () => {
|
||||||
if (!authenticated) {
|
if (!authenticated) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import {
|
|||||||
} from 'antd'
|
} from 'antd'
|
||||||
|
|
||||||
import { AuthContext } from '../context/AuthContext.js'
|
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 NewJob from './Jobs/NewJob.jsx'
|
||||||
import JobState from '../common/JobState.jsx'
|
import JobState from '../common/JobState.jsx'
|
||||||
import SubJobCounter from '../common/SubJobCounter.jsx'
|
import SubJobCounter from '../common/SubJobCounter.jsx'
|
||||||
@ -257,7 +257,7 @@ const Jobs = () => {
|
|||||||
]
|
]
|
||||||
|
|
||||||
const { authenticated } = useContext(AuthContext)
|
const { authenticated } = useContext(AuthContext)
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
|
|
||||||
const [columnVisibility, updateColumnVisibility] = useColumnVisibility(
|
const [columnVisibility, updateColumnVisibility] = useColumnVisibility(
|
||||||
'Jobs',
|
'Jobs',
|
||||||
@ -265,9 +265,9 @@ const Jobs = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const handleDeployJob = (jobId) => {
|
const handleDeployJob = (jobId) => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
messageApi.info(`Print job ${jobId} deployment initiated`)
|
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) {
|
if (response == false) {
|
||||||
notificationApi.error({
|
notificationApi.error({
|
||||||
message: 'Print job deployment failed',
|
message: 'Print job deployment failed',
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import TimeDisplay from '../../common/TimeDisplay'
|
|||||||
import JobState from '../../common/JobState'
|
import JobState from '../../common/JobState'
|
||||||
import IdText from '../../common/IdText'
|
import IdText from '../../common/IdText'
|
||||||
import SubJobsTree from '../../common/SubJobsTree'
|
import SubJobsTree from '../../common/SubJobsTree'
|
||||||
import { SocketContext } from '../../context/SocketContext'
|
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||||
import GCodeFileIcon from '../../../Icons/GCodeFileIcon'
|
import GCodeFileIcon from '../../../Icons/GCodeFileIcon'
|
||||||
import ReloadIcon from '../../../Icons/ReloadIcon'
|
import ReloadIcon from '../../../Icons/ReloadIcon'
|
||||||
import useCollapseState from '../../hooks/useCollapseState'
|
import useCollapseState from '../../hooks/useCollapseState'
|
||||||
@ -42,7 +42,7 @@ const JobInfo = () => {
|
|||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const [messageApi] = message.useMessage()
|
const [messageApi] = message.useMessage()
|
||||||
const jobId = new URLSearchParams(location.search).get('jobId')
|
const jobId = new URLSearchParams(location.search).get('jobId')
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [collapseState, updateCollapseState] = useCollapseState('JobInfo', {
|
const [collapseState, updateCollapseState] = useCollapseState('JobInfo', {
|
||||||
info: true,
|
info: true,
|
||||||
subJobs: true,
|
subJobs: true,
|
||||||
@ -57,8 +57,8 @@ const JobInfo = () => {
|
|||||||
}, [jobId])
|
}, [jobId])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket && jobId) {
|
if (printServer && jobId) {
|
||||||
socket.on('notify_job_update', (updateData) => {
|
printServer.on('notify_job_update', (updateData) => {
|
||||||
if (updateData._id === jobId) {
|
if (updateData._id === jobId) {
|
||||||
setJobData((prevData) => {
|
setJobData((prevData) => {
|
||||||
if (!prevData) return prevData
|
if (!prevData) return prevData
|
||||||
@ -73,11 +73,11 @@ const JobInfo = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
socket.off('notify_job_update')
|
printServer.off('notify_job_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, jobId])
|
}, [printServer, jobId])
|
||||||
|
|
||||||
const fetchJobDetails = async () => {
|
const fetchJobDetails = async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import {
|
|||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { SocketContext } from '../../context/SocketContext'
|
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||||
|
|
||||||
import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'
|
import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'
|
||||||
import PrinterPositionPanel from '../../common/PrinterPositionPanel'
|
import PrinterPositionPanel from '../../common/PrinterPositionPanel'
|
||||||
@ -106,7 +106,7 @@ const ControlPrinter = () => {
|
|||||||
)
|
)
|
||||||
}, [componentVisibility])
|
}, [componentVisibility])
|
||||||
|
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const { authenticated } = useContext(AuthContext)
|
const { authenticated } = useContext(AuthContext)
|
||||||
|
|
||||||
// Fetch printer details when the component mounts
|
// Fetch printer details when the component mounts
|
||||||
@ -143,9 +143,9 @@ const ControlPrinter = () => {
|
|||||||
|
|
||||||
// Add WebSocket event listener for real-time updates
|
// Add WebSocket event listener for real-time updates
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket && !initialized && printerId) {
|
if (printServer && !initialized && printerId) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
socket.on('notify_printer_update', (statusUpdate) => {
|
printServer.on('notify_printer_update', (statusUpdate) => {
|
||||||
setPrinterData((prevData) => {
|
setPrinterData((prevData) => {
|
||||||
if (statusUpdate?._id === printerId) {
|
if (statusUpdate?._id === printerId) {
|
||||||
return {
|
return {
|
||||||
@ -158,7 +158,7 @@ const ControlPrinter = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Add WebSocket event listener for filament stock updates
|
// Add WebSocket event listener for filament stock updates
|
||||||
socket.on('notify_filamentstock_update', (filamentStockUpdate) => {
|
printServer.on('notify_filamentstock_update', (filamentStockUpdate) => {
|
||||||
setPrinterData((prevData) => {
|
setPrinterData((prevData) => {
|
||||||
if (prevData?.currentFilamentStock) {
|
if (prevData?.currentFilamentStock) {
|
||||||
if (
|
if (
|
||||||
@ -178,17 +178,17 @@ const ControlPrinter = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
console.log('Deregistering')
|
console.log('Deregistering')
|
||||||
socket.off('notify_printer_update')
|
printServer.off('notify_printer_update')
|
||||||
socket.off('notify_filamentstock_update')
|
printServer.off('notify_filamentstock_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, initialized, printerId])
|
}, [printServer, initialized, printerId])
|
||||||
|
|
||||||
function handleEmergencyStop() {
|
function handleEmergencyStop() {
|
||||||
console.log('Emergency stop button clicked')
|
console.log('Emergency stop button clicked')
|
||||||
socket.emit('printer.emergency_stop', { printerId })
|
printServer.emit('printer.emergency_stop', { printerId })
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -328,19 +328,19 @@ const ControlPrinter = () => {
|
|||||||
],
|
],
|
||||||
onClick: ({ key }) => {
|
onClick: ({ key }) => {
|
||||||
if (key === 'restartHost') {
|
if (key === 'restartHost') {
|
||||||
socket.emit('printer.restart', { printerId })
|
printServer.emit('printer.restart', { printerId })
|
||||||
} else if (key === 'restartFirmware') {
|
} else if (key === 'restartFirmware') {
|
||||||
socket.emit('printer.firmware_restart', { printerId })
|
printServer.emit('printer.firmware_restart', { printerId })
|
||||||
} else if (key === 'resumePrint') {
|
} else if (key === 'resumePrint') {
|
||||||
socket.emit('printer.print.resume', { printerId })
|
printServer.emit('printer.print.resume', { printerId })
|
||||||
} else if (key === 'pausePrint') {
|
} else if (key === 'pausePrint') {
|
||||||
socket.emit('printer.print.pause', { printerId })
|
printServer.emit('printer.print.pause', { printerId })
|
||||||
} else if (key === 'cancelPrint') {
|
} else if (key === 'cancelPrint') {
|
||||||
socket.emit('printer.print.cancel', { printerId })
|
printServer.emit('printer.print.cancel', { printerId })
|
||||||
} else if (key === 'startQueue') {
|
} else if (key === 'startQueue') {
|
||||||
socket.emit('server.job_queue.start', { printerId })
|
printServer.emit('server.job_queue.start', { printerId })
|
||||||
} else if (key === 'pauseQueue') {
|
} else if (key === 'pauseQueue') {
|
||||||
socket.emit('server.job_queue.pause', { printerId })
|
printServer.emit('server.job_queue.pause', { printerId })
|
||||||
} else if (key === 'loadFilamentStock') {
|
} else if (key === 'loadFilamentStock') {
|
||||||
setLoadFilamentStockModalOpen(true)
|
setLoadFilamentStockModalOpen(true)
|
||||||
} else if (key === 'unloadFilamentStock') {
|
} else if (key === 'unloadFilamentStock') {
|
||||||
@ -467,9 +467,9 @@ const ControlPrinter = () => {
|
|||||||
}
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (printerData?.state?.type === 'paused') {
|
if (printerData?.state?.type === 'paused') {
|
||||||
socket.emit('printer.print.resume', { printerId })
|
printServer.emit('printer.print.resume', { printerId })
|
||||||
} else {
|
} else {
|
||||||
socket.emit('printer.print.pause', { printerId })
|
printServer.emit('printer.print.pause', { printerId })
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
></Button>
|
></Button>
|
||||||
@ -482,7 +482,7 @@ const ControlPrinter = () => {
|
|||||||
printerData?.state?.type === 'error'
|
printerData?.state?.type === 'error'
|
||||||
}
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
socket.emit('server.job_queue.start', { printerId })
|
printServer.emit('server.job_queue.start', { printerId })
|
||||||
}}
|
}}
|
||||||
></Button>
|
></Button>
|
||||||
</Space>
|
</Space>
|
||||||
@ -933,7 +933,7 @@ const ControlPrinter = () => {
|
|||||||
key='firmwareRestart'
|
key='firmwareRestart'
|
||||||
icon={<ReloadIcon />}
|
icon={<ReloadIcon />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
socket.emit('printer.firmware_restart', { printerId })
|
printServer.emit('printer.firmware_restart', { printerId })
|
||||||
setKlippyErrorModalOpen(false)
|
setKlippyErrorModalOpen(false)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import {
|
|||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { SearchOutlined, SettingOutlined } from '@ant-design/icons'
|
import { SearchOutlined, SettingOutlined } from '@ant-design/icons'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { SocketContext } from '../../context/SocketContext'
|
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||||
import EditIcon from '../../../Icons/EditIcon.jsx'
|
import EditIcon from '../../../Icons/EditIcon.jsx'
|
||||||
|
|
||||||
import config from '../../../../config.js'
|
import config from '../../../../config.js'
|
||||||
@ -43,7 +43,7 @@ const NewPrinter = ({ onOk, reset }) => {
|
|||||||
reset: PropTypes.bool.isRequired
|
reset: PropTypes.bool.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
const [notificationApi, notificationContextHolder] =
|
const [notificationApi, notificationContextHolder] =
|
||||||
notification.useNotification()
|
notification.useNotification()
|
||||||
@ -243,22 +243,22 @@ const NewPrinter = ({ onOk, reset }) => {
|
|||||||
setDiscovering(true)
|
setDiscovering(true)
|
||||||
setDiscoveredPrinters([])
|
setDiscoveredPrinters([])
|
||||||
messageApi.info('Discovering printers...')
|
messageApi.info('Discovering printers...')
|
||||||
socket.off('notify_scan_network_found')
|
printServer.off('notify_scan_network_found')
|
||||||
socket.off('notify_scan_network_progress')
|
printServer.off('notify_scan_network_progress')
|
||||||
socket.off('notify_scan_network_complete')
|
printServer.off('notify_scan_network_complete')
|
||||||
|
|
||||||
socket.on('notify_scan_network_found', notifyScanNetworkFound)
|
printServer.on('notify_scan_network_found', notifyScanNetworkFound)
|
||||||
socket.on('notify_scan_network_progress', notifyScanNetworkProgress)
|
printServer.on('notify_scan_network_progress', notifyScanNetworkProgress)
|
||||||
socket.on('notify_scan_network_complete', notifyScanNetworkComplete)
|
printServer.on('notify_scan_network_complete', notifyScanNetworkComplete)
|
||||||
|
|
||||||
socket.emit('bridge.scan_network.start', {
|
printServer.emit('bridge.scan_network.start', {
|
||||||
port: scanPort,
|
port: scanPort,
|
||||||
protocol: scanProtocol
|
protocol: scanProtocol
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
discovering,
|
discovering,
|
||||||
socket,
|
printServer,
|
||||||
scanPort,
|
scanPort,
|
||||||
scanProtocol,
|
scanProtocol,
|
||||||
messageApi,
|
messageApi,
|
||||||
@ -279,10 +279,10 @@ const NewPrinter = ({ onOk, reset }) => {
|
|||||||
setDiscovering(false)
|
setDiscovering(false)
|
||||||
notificationApi.destroy('network-scan')
|
notificationApi.destroy('network-scan')
|
||||||
messageApi.info('Stopping discovery...')
|
messageApi.info('Stopping discovery...')
|
||||||
socket.off('notify_scan_network_found')
|
printServer.off('notify_scan_network_found')
|
||||||
socket.off('notify_scan_network_progress')
|
printServer.off('notify_scan_network_progress')
|
||||||
socket.off('notify_scan_network_complete')
|
printServer.off('notify_scan_network_complete')
|
||||||
socket.emit('bridge.scan_network.stop', (response) => {
|
printServer.emit('bridge.scan_network.stop', (response) => {
|
||||||
if (response == false) {
|
if (response == false) {
|
||||||
messageApi.error('Error stopping discovery!')
|
messageApi.error('Error stopping discovery!')
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,7 +46,7 @@ const breadcrumbNameMap = {
|
|||||||
'/dashboard/inventory/stockaudits/info': 'Info',
|
'/dashboard/inventory/stockaudits/info': 'Info',
|
||||||
'/dashboard/developer/sessionstorage': 'Session Storage',
|
'/dashboard/developer/sessionstorage': 'Session Storage',
|
||||||
'/dashboard/developer/authcontextdebug': 'Auth Context Debug',
|
'/dashboard/developer/authcontextdebug': 'Auth Context Debug',
|
||||||
'/dashboard/developer/socketcontextdebug': 'Socket Context Debug'
|
'/dashboard/developer/printservercontextdebug': 'Print Server Context Debug'
|
||||||
}
|
}
|
||||||
|
|
||||||
const DashboardBreadcrumb = () => {
|
const DashboardBreadcrumb = () => {
|
||||||
|
|||||||
@ -8,9 +8,8 @@ import {
|
|||||||
Dropdown,
|
Dropdown,
|
||||||
Button,
|
Button,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography,
|
Badge,
|
||||||
Divider,
|
Divider
|
||||||
Badge
|
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import {
|
import {
|
||||||
LogoutOutlined,
|
LogoutOutlined,
|
||||||
@ -19,12 +18,13 @@ import {
|
|||||||
LoadingOutlined
|
LoadingOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import { AuthContext } from '../context/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import { SpotlightContext } from '../context/SpotlightContext'
|
import { SpotlightContext } from '../context/SpotlightContext'
|
||||||
import { NotificationContext } from '../context/NotificationContext'
|
import { ApiServerContext } from '../context/ApiServerContext'
|
||||||
import { useNavigate, useLocation } from 'react-router-dom'
|
import { useNavigate, useLocation } from 'react-router-dom'
|
||||||
import { Header } from 'antd/es/layout/layout'
|
import { Header } from 'antd/es/layout/layout'
|
||||||
import { useMediaQuery } from 'react-responsive'
|
import { useMediaQuery } from 'react-responsive'
|
||||||
|
import KeyboardShortcut from './KeyboardShortcut'
|
||||||
|
|
||||||
import FarmControlLogo from '../../Logos/FarmControlLogo'
|
import FarmControlLogo from '../../Logos/FarmControlLogo'
|
||||||
import FarmControlLogoSmall from '../../Logos/FarmControlLogoSmall'
|
import FarmControlLogoSmall from '../../Logos/FarmControlLogoSmall'
|
||||||
@ -36,16 +36,16 @@ import BellIcon from '../../Icons/BellIcon'
|
|||||||
import SearchIcon from '../../Icons/SearchIcon'
|
import SearchIcon from '../../Icons/SearchIcon'
|
||||||
import SettingsIcon from '../../Icons/SettingsIcon'
|
import SettingsIcon from '../../Icons/SettingsIcon'
|
||||||
import DeveloperIcon from '../../Icons/DeveloperIcon'
|
import DeveloperIcon from '../../Icons/DeveloperIcon'
|
||||||
|
import PrinterIcon from '../../Icons/PrinterIcon'
|
||||||
const { Text } = Typography
|
|
||||||
|
|
||||||
const DashboardNavigation = () => {
|
const DashboardNavigation = () => {
|
||||||
const { logout, userProfile } = useContext(AuthContext)
|
const { logout, userProfile } = useContext(AuthContext)
|
||||||
const { showSpotlight } = useContext(SpotlightContext)
|
const { showSpotlight } = useContext(SpotlightContext)
|
||||||
const { toggleNotificationCenter, unreadCount } =
|
const { toggleNotificationCenter, unreadCount } = useContext(ApiServerContext)
|
||||||
useContext(NotificationContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const { socket } = useContext(SocketContext)
|
const { apiServer } = useContext(ApiServerContext)
|
||||||
const [socketState, setSocketState] = useState('disconnected')
|
const [printServerState, setPrintServerState] = useState('disconnected')
|
||||||
|
const [apiServerState, setApiServerState] = useState('disconnected')
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const [selectedKey, setSelectedKey] = useState('production')
|
const [selectedKey, setSelectedKey] = useState('production')
|
||||||
@ -59,14 +59,24 @@ const DashboardNavigation = () => {
|
|||||||
}, [location.pathname])
|
}, [location.pathname])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket?.connecting) {
|
if (printServer?.connecting) {
|
||||||
setSocketState('connecting')
|
setPrintServerState('connecting')
|
||||||
} else if (socket?.connected) {
|
} else if (printServer?.connected) {
|
||||||
setSocketState('connected')
|
setPrintServerState('connected')
|
||||||
} else {
|
} 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 = [
|
const mainMenuItems = [
|
||||||
{
|
{
|
||||||
@ -165,35 +175,47 @@ const DashboardNavigation = () => {
|
|||||||
/>
|
/>
|
||||||
<Flex gap={'middle'} align='center'>
|
<Flex gap={'middle'} align='center'>
|
||||||
<Space>
|
<Space>
|
||||||
<Tooltip title={<Text keyboard>⌘ ⇧ P</Text>} arrow={false}>
|
<KeyboardShortcut
|
||||||
|
shortcut='alt+shift+q'
|
||||||
|
hint='⌘ ⇧ P'
|
||||||
|
onTrigger={() => showSpotlight()}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
icon={<SearchIcon />}
|
icon={<SearchIcon />}
|
||||||
type='text'
|
type='text'
|
||||||
style={{ marginTop: '2px' }}
|
style={{ marginTop: '2px' }}
|
||||||
onClick={() => showSpotlight()}
|
onClick={() => showSpotlight()}
|
||||||
></Button>
|
/>
|
||||||
</Tooltip>
|
</KeyboardShortcut>
|
||||||
<Badge count={unreadCount} size='small'>
|
<Badge count={unreadCount} size='small'>
|
||||||
|
<KeyboardShortcut
|
||||||
|
shortcut='alt+n'
|
||||||
|
hint='ALT N'
|
||||||
|
onTrigger={() => toggleNotificationCenter()}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
icon={<BellIcon />}
|
icon={<BellIcon />}
|
||||||
type='text'
|
type='text'
|
||||||
style={{ marginTop: '2px' }}
|
style={{ marginTop: '2px' }}
|
||||||
onClick={toggleNotificationCenter}
|
onClick={() => toggleNotificationCenter()}
|
||||||
></Button>
|
/>
|
||||||
|
</KeyboardShortcut>
|
||||||
</Badge>
|
</Badge>
|
||||||
</Space>
|
</Space>
|
||||||
|
|
||||||
|
{process.env.NODE_ENV === 'development' && (
|
||||||
<Space>
|
<Space>
|
||||||
{socketState === 'connected' ? (
|
{printServerState === 'connected' ? (
|
||||||
<Tooltip title='Connected to server' arrow={false}>
|
<Tooltip title='Connected to print server' arrow={false}>
|
||||||
<Tag
|
<Tag
|
||||||
color='success'
|
color='success'
|
||||||
style={{ marginRight: 0 }}
|
style={{ marginRight: 0 }}
|
||||||
icon={<CloudIcon />}
|
icon={<PrinterIcon />}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : null}
|
) : null}
|
||||||
{socketState === 'connecting' ? (
|
{printServerState === 'connecting' ? (
|
||||||
<Tooltip title='Connecting to server...' arrow={false}>
|
<Tooltip title='Connecting to print erver...' arrow={false}>
|
||||||
<Tag
|
<Tag
|
||||||
color='default'
|
color='default'
|
||||||
style={{ marginRight: 0 }}
|
style={{ marginRight: 0 }}
|
||||||
@ -201,8 +223,35 @@ const DashboardNavigation = () => {
|
|||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : null}
|
) : null}
|
||||||
{socketState === 'disconnected' ? (
|
{printServerState === 'disconnected' ? (
|
||||||
<Tooltip title='Disconnected from server' arrow={false}>
|
<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
|
<Tag
|
||||||
color='error'
|
color='error'
|
||||||
style={{ marginRight: 0 }}
|
style={{ marginRight: 0 }}
|
||||||
@ -210,9 +259,6 @@ const DashboardNavigation = () => {
|
|||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : null}
|
) : null}
|
||||||
</Space>
|
|
||||||
{process.env.NODE_ENV === 'development' && (
|
|
||||||
<Space>
|
|
||||||
<Tooltip title='Developer' arrow={false}>
|
<Tooltip title='Developer' arrow={false}>
|
||||||
<Tag
|
<Tag
|
||||||
color='yellow'
|
color='yellow'
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import PropTypes from 'prop-types'
|
|||||||
import { Badge, Progress, Flex, Space, Tag, Typography } from 'antd'
|
import { Badge, Progress, Flex, Space, Tag, Typography } from 'antd'
|
||||||
import { green } from '@ant-design/colors'
|
import { green } from '@ant-design/colors'
|
||||||
import React, { useState, useContext, useEffect } from 'react'
|
import React, { useState, useContext, useEffect } from 'react'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
|
|
||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ const FilamentStockState = ({
|
|||||||
showProgress = true,
|
showProgress = true,
|
||||||
showStatus = true
|
showStatus = true
|
||||||
}) => {
|
}) => {
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [badgeStatus, setBadgeStatus] = useState('unknown')
|
const [badgeStatus, setBadgeStatus] = useState('unknown')
|
||||||
const [badgeText, setBadgeText] = useState('Unknown')
|
const [badgeText, setBadgeText] = useState('Unknown')
|
||||||
const [currentState, setCurrentState] = useState(
|
const [currentState, setCurrentState] = useState(
|
||||||
@ -37,20 +37,20 @@ const FilamentStockState = ({
|
|||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket && !initialized && filamentStock?._id) {
|
if (printServer && !initialized && filamentStock?._id) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
socket.on('notify_filamentstock_update', (statusUpdate) => {
|
printServer.on('notify_filamentstock_update', (statusUpdate) => {
|
||||||
if (statusUpdate?._id === filamentStock?._id && statusUpdate?.state) {
|
if (statusUpdate?._id === filamentStock?._id && statusUpdate?.state) {
|
||||||
setCurrentState(statusUpdate.state)
|
setCurrentState(statusUpdate.state)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
socket.off('notify_filamentstock_update')
|
printServer.off('notify_filamentstock_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, initialized, filamentStock?._id])
|
}, [printServer, initialized, filamentStock?._id])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
switch (currentState.type) {
|
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 PropTypes from 'prop-types'
|
||||||
import { Progress, Flex, Typography, Space } from 'antd'
|
import { Progress, Flex, Typography, Space } from 'antd'
|
||||||
import React, { useState, useContext, useEffect } from 'react'
|
import React, { useState, useContext, useEffect } from 'react'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import IdText from './IdText'
|
import IdText from './IdText'
|
||||||
import StateTag from './StateTag'
|
import StateTag from './StateTag'
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ const JobState = ({
|
|||||||
showId = true,
|
showId = true,
|
||||||
showQuantity = true
|
showQuantity = true
|
||||||
}) => {
|
}) => {
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [currentState, setCurrentState] = useState(
|
const [currentState, setCurrentState] = useState(
|
||||||
job?.state || { type: 'unknown', progress: 0 }
|
job?.state || { type: 'unknown', progress: 0 }
|
||||||
)
|
)
|
||||||
@ -20,20 +20,20 @@ const JobState = ({
|
|||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket && !initialized && job?._id) {
|
if (printServer && !initialized && job?._id) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
socket.on('notify_job_update', (statusUpdate) => {
|
printServer.on('notify_job_update', (statusUpdate) => {
|
||||||
if (statusUpdate?._id === job._id && statusUpdate?.state) {
|
if (statusUpdate?._id === job._id && statusUpdate?.state) {
|
||||||
setCurrentState(statusUpdate.state)
|
setCurrentState(statusUpdate.state)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
socket.off('notify_job_update')
|
printServer.off('notify_job_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, initialized, job?._id])
|
}, [printServer, initialized, job?._id])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex gap='small' align={'center'}>
|
<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 React, { useState, useEffect, useContext } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import SubJobState from './SubJobState'
|
import SubJobState from './SubJobState'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import JobState from './JobState'
|
import JobState from './JobState'
|
||||||
import JobIcon from '../../Icons/JobIcon'
|
import JobIcon from '../../Icons/JobIcon'
|
||||||
@ -20,7 +20,7 @@ const PrinterJobsTree = ({
|
|||||||
const [subJobs, setSubJobs] = useState(initialSubJobs || [])
|
const [subJobs, setSubJobs] = useState(initialSubJobs || [])
|
||||||
const [treeLoading, setTreeLoading] = useState(initialLoading)
|
const [treeLoading, setTreeLoading] = useState(initialLoading)
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [messageApi] = message.useMessage()
|
const [messageApi] = message.useMessage()
|
||||||
const [expandedKeys, setExpandedKeys] = useState([])
|
const [expandedKeys, setExpandedKeys] = useState([])
|
||||||
const [treeData, setTreeData] = useState([])
|
const [treeData, setTreeData] = useState([])
|
||||||
@ -116,9 +116,9 @@ const PrinterJobsTree = ({
|
|||||||
|
|
||||||
initializeData()
|
initializeData()
|
||||||
|
|
||||||
// Add socket.io event listener for subjob updates
|
// Add printServer.io event listener for subjob updates
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
socket.on('notify_subjob_update', (updateData) => {
|
printServer.on('notify_subjob_update', (updateData) => {
|
||||||
if (updateData.subJobId) {
|
if (updateData.subJobId) {
|
||||||
setSubJobs((prevSubJobs) =>
|
setSubJobs((prevSubJobs) =>
|
||||||
prevSubJobs.map((subJob) => {
|
prevSubJobs.map((subJob) => {
|
||||||
@ -137,11 +137,11 @@ const PrinterJobsTree = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
socket.off('notify_subjob_update')
|
printServer.off('notify_subjob_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [initialSubJobs, socket])
|
}, [initialSubJobs, printServer])
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { useContext, useState, useEffect } from 'react'
|
import React, { useContext, useState, useEffect } from 'react'
|
||||||
import { Typography, Spin, Flex, Space, Slider, Descriptions, Tag } from 'antd'
|
import { Typography, Spin, Flex, Space, Slider, Descriptions, Tag } from 'antd'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
@ -33,7 +33,7 @@ const PrinterMiscPanel = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [fanSpeed, setFanSpeed] = useState(0)
|
const [fanSpeed, setFanSpeed] = useState(0)
|
||||||
const [ledBrightness, setLedBrightness] = useState(0)
|
const [ledBrightness, setLedBrightness] = useState(0)
|
||||||
const [beeperValue, setBeeperValue] = useState(0)
|
const [beeperValue, setBeeperValue] = useState(0)
|
||||||
@ -89,30 +89,30 @@ const PrinterMiscPanel = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!initialized && socket.connected) {
|
if (!initialized && printServer.connected) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
|
|
||||||
socket.on('connect', () => {
|
printServer.on('connect', () => {
|
||||||
socket.emit('printer.objects.subscribe', params)
|
printServer.emit('printer.objects.subscribe', params)
|
||||||
socket.emit('printer.objects.query', params)
|
printServer.emit('printer.objects.query', params)
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.emit('printer.objects.subscribe', params)
|
printServer.emit('printer.objects.subscribe', params)
|
||||||
socket.emit('printer.objects.query', params)
|
printServer.emit('printer.objects.query', params)
|
||||||
socket.on('notify_status_update', notifyMiscStatusUpdate)
|
printServer.on('notify_status_update', notifyMiscStatusUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (socket.connected && initialized && shouldUnsubscribe) {
|
if (printServer.connected && initialized && shouldUnsubscribe) {
|
||||||
socket.off('notify_status_update', notifyMiscStatusUpdate)
|
printServer.off('notify_status_update', notifyMiscStatusUpdate)
|
||||||
socket.emit('printer.objects.unsubscribe', params)
|
printServer.emit('printer.objects.unsubscribe', params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, initialized, printerId, shouldUnsubscribe])
|
}, [printServer, initialized, printerId, shouldUnsubscribe])
|
||||||
|
|
||||||
const handleSetFanSpeed = (value) => {
|
const handleSetFanSpeed = (value) => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
socket.emit('printer.gcode.script', {
|
printServer.emit('printer.gcode.script', {
|
||||||
printerId,
|
printerId,
|
||||||
script: `M106 S${Math.round(value * 255)}`
|
script: `M106 S${Math.round(value * 255)}`
|
||||||
})
|
})
|
||||||
@ -120,8 +120,8 @@ const PrinterMiscPanel = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleSetLedBrightness = (value) => {
|
const handleSetLedBrightness = (value) => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
socket.emit('printer.gcode.script', {
|
printServer.emit('printer.gcode.script', {
|
||||||
printerId,
|
printerId,
|
||||||
script: `SET_LED LED=led_backlight BRIGHTNESS=${value}`
|
script: `SET_LED LED=led_backlight BRIGHTNESS=${value}`
|
||||||
})
|
})
|
||||||
@ -129,8 +129,8 @@ const PrinterMiscPanel = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleSetBeeperValue = (value) => {
|
const handleSetBeeperValue = (value) => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
socket.emit('printer.gcode.script', {
|
printServer.emit('printer.gcode.script', {
|
||||||
printerId,
|
printerId,
|
||||||
script: `M300 S440 P200 V${Math.round(value * 100)}`
|
script: `M300 S440 P200 V${Math.round(value * 100)}`
|
||||||
})
|
})
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import {
|
|||||||
Card,
|
Card,
|
||||||
message // eslint-disable-line
|
message // eslint-disable-line
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import LevelBedIcon from '../../Icons/LevelBedIcon'
|
import LevelBedIcon from '../../Icons/LevelBedIcon'
|
||||||
import ArrowLeftIcon from '../../Icons/ArrowLeftIcon'
|
import ArrowLeftIcon from '../../Icons/ArrowLeftIcon'
|
||||||
@ -22,7 +22,7 @@ import HomeIcon from '../../Icons/HomeIcon'
|
|||||||
const PrinterMovementPanel = ({ printerId }) => {
|
const PrinterMovementPanel = ({ printerId }) => {
|
||||||
const [posValue, setPosValue] = useState(10)
|
const [posValue, setPosValue] = useState(10)
|
||||||
const [rateValue, setRateValue] = useState(1000)
|
const [rateValue, setRateValue] = useState(1000)
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
|
|
||||||
//const messageApi = message.useMessage()
|
//const messageApi = message.useMessage()
|
||||||
|
|
||||||
@ -40,9 +40,9 @@ const PrinterMovementPanel = ({ printerId }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleHomeAxisClick = (axis) => {
|
const handleHomeAxisClick = (axis) => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
console.log('Homeing Axis:', axis)
|
console.log('Homeing Axis:', axis)
|
||||||
socket.emit('printer.gcode.script', {
|
printServer.emit('printer.gcode.script', {
|
||||||
printerId,
|
printerId,
|
||||||
script: `G28 ${axis}`
|
script: `G28 ${axis}`
|
||||||
})
|
})
|
||||||
@ -51,9 +51,9 @@ const PrinterMovementPanel = ({ printerId }) => {
|
|||||||
|
|
||||||
const handleMoveAxisClick = (axis, minus) => {
|
const handleMoveAxisClick = (axis, minus) => {
|
||||||
const distanceValue = !minus ? posValue * -1 : posValue
|
const distanceValue = !minus ? posValue * -1 : posValue
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
console.log('Moving Axis:', axis, distanceValue)
|
console.log('Moving Axis:', axis, distanceValue)
|
||||||
socket.emit('printer.gcode.script', {
|
printServer.emit('printer.gcode.script', {
|
||||||
printerId,
|
printerId,
|
||||||
script: `_CLIENT_LINEAR_MOVE ${axis}=${distanceValue} F=${rateValue}`
|
script: `_CLIENT_LINEAR_MOVE ${axis}=${distanceValue} F=${rateValue}`
|
||||||
})
|
})
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import {
|
|||||||
Button
|
Button
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import BoolDisplay from './BoolDisplay'
|
import BoolDisplay from './BoolDisplay'
|
||||||
@ -46,7 +46,7 @@ const PrinterPositionPanel = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [speedFactor, setSpeedFactor] = useState(positionData.speed_factor)
|
const [speedFactor, setSpeedFactor] = useState(positionData.speed_factor)
|
||||||
const [extrudeFactor, setExtrudeFactor] = useState(
|
const [extrudeFactor, setExtrudeFactor] = useState(
|
||||||
positionData.extrude_factor
|
positionData.extrude_factor
|
||||||
@ -76,33 +76,33 @@ const PrinterPositionPanel = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!initialized && socket?.connected) {
|
if (!initialized && printServer?.connected) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
|
|
||||||
socket.on('connect', () => {
|
printServer.on('connect', () => {
|
||||||
socket.emit('printer.objects.subscribe', params)
|
printServer.emit('printer.objects.subscribe', params)
|
||||||
socket.emit('printer.objects.query', params)
|
printServer.emit('printer.objects.query', params)
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.emit('printer.objects.subscribe', params)
|
printServer.emit('printer.objects.subscribe', params)
|
||||||
socket.emit('printer.objects.query', params)
|
printServer.emit('printer.objects.query', params)
|
||||||
socket.on('notify_status_update', notifyPositionStatusUpdate)
|
printServer.on('notify_status_update', notifyPositionStatusUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
setSpeedFactor(positionData.speed_factor)
|
setSpeedFactor(positionData.speed_factor)
|
||||||
setExtrudeFactor(positionData.extrude_factor)
|
setExtrudeFactor(positionData.extrude_factor)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (socket?.connected && initialized && shouldUnsubscribe) {
|
if (printServer?.connected && initialized && shouldUnsubscribe) {
|
||||||
socket.off('notify_status_update', notifyPositionStatusUpdate)
|
printServer.off('notify_status_update', notifyPositionStatusUpdate)
|
||||||
socket.emit('printer.objects.unsubscribe', params)
|
printServer.emit('printer.objects.unsubscribe', params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, initialized, printerId, shouldUnsubscribe])
|
}, [printServer, initialized, printerId, shouldUnsubscribe])
|
||||||
|
|
||||||
const handleSetSpeedFactor = () => {
|
const handleSetSpeedFactor = () => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
socket.emit('printer.gcode.script', {
|
printServer.emit('printer.gcode.script', {
|
||||||
printerId,
|
printerId,
|
||||||
script: `M220 S${speedFactor * 100}`
|
script: `M220 S${speedFactor * 100}`
|
||||||
})
|
})
|
||||||
@ -110,8 +110,8 @@ const PrinterPositionPanel = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleSetExtrudeFactor = () => {
|
const handleSetExtrudeFactor = () => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
socket.emit('printer.gcode.script', {
|
printServer.emit('printer.gcode.script', {
|
||||||
printerId,
|
printerId,
|
||||||
script: `M221 S${extrudeFactor * 100}`
|
script: `M221 S${extrudeFactor * 100}`
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Progress, Flex, Space, Typography, Button, Tooltip } from 'antd'
|
import { Progress, Flex, Space, Typography, Button, Tooltip } from 'antd'
|
||||||
import React, { useState, useContext, useEffect } from 'react'
|
import React, { useState, useContext, useEffect } from 'react'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import { CaretLeftOutlined } from '@ant-design/icons'
|
import { CaretLeftOutlined } from '@ant-design/icons'
|
||||||
import XMarkIcon from '../../Icons/XMarkIcon'
|
import XMarkIcon from '../../Icons/XMarkIcon'
|
||||||
import PauseIcon from '../../Icons/PauseIcon'
|
import PauseIcon from '../../Icons/PauseIcon'
|
||||||
@ -15,7 +15,7 @@ const PrinterState = ({
|
|||||||
showPrinterName = true,
|
showPrinterName = true,
|
||||||
showControls = true
|
showControls = true
|
||||||
}) => {
|
}) => {
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [currentState, setCurrentState] = useState(
|
const [currentState, setCurrentState] = useState(
|
||||||
printer?.state || {
|
printer?.state || {
|
||||||
type: 'unknown',
|
type: 'unknown',
|
||||||
@ -26,20 +26,20 @@ const PrinterState = ({
|
|||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket && !initialized && printer?.id) {
|
if (printServer && !initialized && printer?.id) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
socket.on('notify_printer_update', (statusUpdate) => {
|
printServer.on('notify_printer_update', (statusUpdate) => {
|
||||||
if (statusUpdate?._id === printer.id && statusUpdate?.state) {
|
if (statusUpdate?._id === printer.id && statusUpdate?.state) {
|
||||||
setCurrentState(statusUpdate.state)
|
setCurrentState(statusUpdate.state)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
socket.off('notify_printer_update')
|
printServer.off('notify_printer_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, initialized, printer?.id])
|
}, [printServer, initialized, printer?.id])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex gap='small' align={'center'}>
|
<Flex gap='small' align={'center'}>
|
||||||
@ -67,11 +67,11 @@ const PrinterState = ({
|
|||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (currentState.type === 'printing') {
|
if (currentState.type === 'printing') {
|
||||||
socket.emit('printer.print.pause', {
|
printServer.emit('printer.print.pause', {
|
||||||
printerId: printer.id
|
printerId: printer.id
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
socket.emit('printer.print.resume', {
|
printServer.emit('printer.print.resume', {
|
||||||
printerId: printer.id
|
printerId: printer.id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ const PrinterState = ({
|
|||||||
<Tooltip title='Cancel' arrow={false}>
|
<Tooltip title='Cancel' arrow={false}>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
socket.emit('printer.print.cancel', {
|
printServer.emit('printer.print.cancel', {
|
||||||
printerId: printer.id
|
printerId: printer.id
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
Button
|
Button
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ const PrinterTemperaturePanel = ({
|
|||||||
const [heatedBedTemperature, setHeatedBedTemperature] = useState(
|
const [heatedBedTemperature, setHeatedBedTemperature] = useState(
|
||||||
temperatureData?.heatedBed?.target || 0
|
temperatureData?.heatedBed?.target || 0
|
||||||
)
|
)
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
|
|
||||||
const notifyTemperatureStatusUpdate = useCallback((statusUpdate) => {
|
const notifyTemperatureStatusUpdate = useCallback((statusUpdate) => {
|
||||||
setTemperatureData((prev) => {
|
setTemperatureData((prev) => {
|
||||||
@ -96,25 +96,25 @@ const PrinterTemperaturePanel = ({
|
|||||||
heater_bed: null // eslint-disable-line
|
heater_bed: null // eslint-disable-line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (socket?.connected == true) {
|
if (printServer?.connected == true) {
|
||||||
console.log('Printer Temperature Panel is subscribing...')
|
console.log('Printer Temperature Panel is subscribing...')
|
||||||
socket.emit('printer.objects.subscribe', params)
|
printServer.emit('printer.objects.subscribe', params)
|
||||||
socket.emit('printer.objects.query', params)
|
printServer.emit('printer.objects.query', params)
|
||||||
socket.on('notify_status_update', notifyTemperatureStatusUpdate)
|
printServer.on('notify_status_update', notifyTemperatureStatusUpdate)
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && shouldUnsubscribe == true) {
|
if (printServer && shouldUnsubscribe == true) {
|
||||||
console.log('Printer Temperature Panel is unsubscribing...')
|
console.log('Printer Temperature Panel is unsubscribing...')
|
||||||
socket.off('notify_status_update', notifyTemperatureStatusUpdate)
|
printServer.off('notify_status_update', notifyTemperatureStatusUpdate)
|
||||||
socket.emit('printer.objects.unsubscribe', params)
|
printServer.emit('printer.objects.unsubscribe', params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, printerId, notifyTemperatureStatusUpdate, shouldUnsubscribe])
|
}, [printServer, printerId, notifyTemperatureStatusUpdate, shouldUnsubscribe])
|
||||||
|
|
||||||
const handleSetTemperatureClick = (target, value) => {
|
const handleSetTemperatureClick = (target, value) => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
console.log('printer.gcode.script', target, value)
|
console.log('printer.gcode.script', target, value)
|
||||||
socket.emit('printer.gcode.script', {
|
printServer.emit('printer.gcode.script', {
|
||||||
printerId,
|
printerId,
|
||||||
script: `SET_HEATER_TEMPERATURE HEATER=${target} TARGET=${value}`
|
script: `SET_HEATER_TEMPERATURE HEATER=${target} TARGET=${value}`
|
||||||
})
|
})
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { Table, Typography } from 'antd'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import IdText from './IdText'
|
import IdText from './IdText'
|
||||||
import { AuditOutlined } from '@ant-design/icons'
|
import { AuditOutlined } from '@ant-design/icons'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import TimeDisplay from '../common/TimeDisplay'
|
import TimeDisplay from '../common/TimeDisplay'
|
||||||
import PlusMinusIcon from '../../Icons/PlusMinusIcon'
|
import PlusMinusIcon from '../../Icons/PlusMinusIcon'
|
||||||
@ -13,15 +13,15 @@ import PlayCircleIcon from '../../Icons/PlayCircleIcon'
|
|||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
|
|
||||||
const StockEventTable = ({ stockEvents }) => {
|
const StockEventTable = ({ stockEvents }) => {
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
const [stockEventsData, setStockEventsData] = useState(stockEvents)
|
const [stockEventsData, setStockEventsData] = useState(stockEvents)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Add WebSocket event listener for real-time updates
|
// Add WebSocket event listener for real-time updates
|
||||||
if (socket && !initialized) {
|
if (printServer && !initialized) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
socket.on('notify_stockevent_update', (updateData) => {
|
printServer.on('notify_stockevent_update', (updateData) => {
|
||||||
console.log('Received stock event update:', updateData)
|
console.log('Received stock event update:', updateData)
|
||||||
setStockEventsData((prevData) => {
|
setStockEventsData((prevData) => {
|
||||||
return prevData.map((stockEvent) => {
|
return prevData.map((stockEvent) => {
|
||||||
@ -41,12 +41,12 @@ const StockEventTable = ({ stockEvents }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
console.log('Deregistering stock event update listener')
|
console.log('Deregistering stock event update listener')
|
||||||
socket.off('notify_stockevent_update')
|
printServer.off('notify_stockevent_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [socket, initialized])
|
}, [printServer, initialized])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setStockEventsData(stockEvents)
|
setStockEventsData(stockEvents)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Typography, Tag } from 'antd' // eslint-disable-line
|
import { Typography, Tag } from 'antd' // eslint-disable-line
|
||||||
import React, { useState, useContext, useEffect } from 'react'
|
import React, { useState, useContext, useEffect } from 'react'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
|
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
|
||||||
import PauseCircleIcon from '../../Icons/PauseCircleIcon'
|
import PauseCircleIcon from '../../Icons/PauseCircleIcon'
|
||||||
import XMarkCircleIcon from '../../Icons/XMarkCircleIcon'
|
import XMarkCircleIcon from '../../Icons/XMarkCircleIcon'
|
||||||
@ -12,7 +12,7 @@ const SubJobCounter = ({
|
|||||||
showIcon = true,
|
showIcon = true,
|
||||||
state = { type: 'complete' }
|
state = { type: 'complete' }
|
||||||
}) => {
|
}) => {
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
var badgeStatus = 'unknown'
|
var badgeStatus = 'unknown'
|
||||||
var badgeIcon = <QuestionCircleIcon />
|
var badgeIcon = <QuestionCircleIcon />
|
||||||
@ -21,10 +21,10 @@ const SubJobCounter = ({
|
|||||||
const [count, setCount] = useState(0)
|
const [count, setCount] = useState(0)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket && !initialized && job?.id) {
|
if (printServer && !initialized && job?.id) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
console.log('on notify_subjob_update')
|
console.log('on notify_subjob_update')
|
||||||
socket.on('notify_subjob_update', (statusUpdate) => {
|
printServer.on('notify_subjob_update', (statusUpdate) => {
|
||||||
for (const subJob of job.subJobs) {
|
for (const subJob of job.subJobs) {
|
||||||
if (statusUpdate?._id === subJob.id && statusUpdate?.state) {
|
if (statusUpdate?._id === subJob.id && statusUpdate?.state) {
|
||||||
console.log('statusUpdate', statusUpdate)
|
console.log('statusUpdate', statusUpdate)
|
||||||
@ -34,12 +34,12 @@ const SubJobCounter = ({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
console.log('off notify_subjob_update')
|
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) {
|
switch (state.type) {
|
||||||
case 'draft':
|
case 'draft':
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import PropTypes from 'prop-types'
|
|||||||
import { Progress, Flex, Button, Space, Tooltip } from 'antd' // eslint-disable-line
|
import { Progress, Flex, Button, Space, Tooltip } from 'antd' // eslint-disable-line
|
||||||
import { CaretLeftOutlined } from '@ant-design/icons' // eslint-disable-line
|
import { CaretLeftOutlined } from '@ant-design/icons' // eslint-disable-line
|
||||||
import React, { useState, useContext, useEffect } from 'react'
|
import React, { useState, useContext, useEffect } from 'react'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import IdText from './IdText'
|
import IdText from './IdText'
|
||||||
import StateTag from './StateTag'
|
import StateTag from './StateTag'
|
||||||
import XMarkIcon from '../../Icons/XMarkIcon'
|
import XMarkIcon from '../../Icons/XMarkIcon'
|
||||||
@ -16,7 +16,7 @@ const SubJobState = ({
|
|||||||
showProgress = true,
|
showProgress = true,
|
||||||
showControls = true //eslint-disable-line
|
showControls = true //eslint-disable-line
|
||||||
}) => {
|
}) => {
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [currentState, setCurrentState] = useState(
|
const [currentState, setCurrentState] = useState(
|
||||||
subJob?.state || {
|
subJob?.state || {
|
||||||
type: 'unknown',
|
type: 'unknown',
|
||||||
@ -26,10 +26,10 @@ const SubJobState = ({
|
|||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket && !initialized && subJob?._id) {
|
if (printServer && !initialized && subJob?._id) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
console.log('on notify_subjob_update')
|
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) {
|
if (statusUpdate?._id === subJob._id && statusUpdate?.state) {
|
||||||
console.log('statusUpdate', statusUpdate)
|
console.log('statusUpdate', statusUpdate)
|
||||||
setCurrentState(statusUpdate.state)
|
setCurrentState(statusUpdate.state)
|
||||||
@ -37,12 +37,12 @@ const SubJobState = ({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (socket && initialized) {
|
if (printServer && initialized) {
|
||||||
console.log('off notify_subjob_update')
|
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 (
|
return (
|
||||||
<Flex gap='small' align={'center'}>
|
<Flex gap='small' align={'center'}>
|
||||||
@ -73,11 +73,11 @@ const SubJobState = ({
|
|||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (currentState.type === 'printing') {
|
if (currentState.type === 'printing') {
|
||||||
socket.emit('printer.print.pause', {
|
printServer.emit('printer.print.pause', {
|
||||||
printerId: subJob.printer
|
printerId: subJob.printer
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
socket.emit('printer.print.resume', {
|
printServer.emit('printer.print.resume', {
|
||||||
printerId: subJob.printer
|
printerId: subJob.printer
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ const SubJobState = ({
|
|||||||
<Tooltip title='Cancel' arrow={false}>
|
<Tooltip title='Cancel' arrow={false}>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
socket.emit('printer.print.cancel', {
|
printServer.emit('printer.print.cancel', {
|
||||||
printerId: subJob.printer
|
printerId: subJob.printer
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
@ -117,7 +117,7 @@ const SubJobState = ({
|
|||||||
<Tooltip title='Cancel' arrow={false}>
|
<Tooltip title='Cancel' arrow={false}>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
socket.emit('server.job_queue.cancel', {
|
printServer.emit('server.job_queue.cancel', {
|
||||||
subJobId: subJob._id
|
subJobId: subJob._id
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import React, { useState, useEffect, useContext, useCallback } from 'react'
|
|||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import PrinterState from './PrinterState'
|
import PrinterState from './PrinterState'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { PrintServerContext } from '../context/PrintServerContext'
|
||||||
import PrinterIcon from '../../Icons/PrinterIcon'
|
import PrinterIcon from '../../Icons/PrinterIcon'
|
||||||
import SubJobState from './SubJobState'
|
import SubJobState from './SubJobState'
|
||||||
import SubJobIcon from '../../Icons/SubJobIcon'
|
import SubJobIcon from '../../Icons/SubJobIcon'
|
||||||
@ -18,7 +18,7 @@ const SubJobsTree = ({ jobData, loading }) => {
|
|||||||
const [treeData, setTreeData] = useState([])
|
const [treeData, setTreeData] = useState([])
|
||||||
const [treeLoading, setTreeLoading] = useState(loading)
|
const [treeLoading, setTreeLoading] = useState(loading)
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
const { socket } = useContext(SocketContext)
|
const { printServer } = useContext(PrintServerContext)
|
||||||
const [messageApi] = message.useMessage()
|
const [messageApi] = message.useMessage()
|
||||||
const [expandedKeys, setExpandedKeys] = useState([])
|
const [expandedKeys, setExpandedKeys] = useState([])
|
||||||
const [currentJobData, setCurrentJobData] = useState(null)
|
const [currentJobData, setCurrentJobData] = useState(null)
|
||||||
@ -111,9 +111,9 @@ const SubJobsTree = ({ jobData, loading }) => {
|
|||||||
|
|
||||||
initializeData()
|
initializeData()
|
||||||
|
|
||||||
// Add socket.io event listener for deployment updates
|
// Add printServer.io event listener for deployment updates
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
socket.on('notify_deployment_update', (updateData) => {
|
printServer.on('notify_deployment_update', (updateData) => {
|
||||||
console.log('Received deployment update:', updateData)
|
console.log('Received deployment update:', updateData)
|
||||||
setCurrentJobData((prevData) => {
|
setCurrentJobData((prevData) => {
|
||||||
if (!prevData) return prevData
|
if (!prevData) return prevData
|
||||||
@ -148,7 +148,7 @@ const SubJobsTree = ({ jobData, loading }) => {
|
|||||||
return prevData
|
return prevData
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
socket.on('notify_subjob_update', (updateData) => {
|
printServer.on('notify_subjob_update', (updateData) => {
|
||||||
// Handle sub-job updates
|
// Handle sub-job updates
|
||||||
if (updateData.subJobId) {
|
if (updateData.subJobId) {
|
||||||
console.log('Received subjob update:', updateData)
|
console.log('Received subjob update:', updateData)
|
||||||
@ -174,11 +174,11 @@ const SubJobsTree = ({ jobData, loading }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (socket) {
|
if (printServer) {
|
||||||
socket.off('notify_deployment_update')
|
printServer.off('notify_deployment_update')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [jobData, socket])
|
}, [jobData, printServer])
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
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, {
|
import React, {
|
||||||
createContext,
|
createContext,
|
||||||
useEffect,
|
useEffect,
|
||||||
@ -11,10 +11,13 @@ import { message, notification } from 'antd'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { AuthContext } from './AuthContext'
|
import { AuthContext } from './AuthContext'
|
||||||
import config from '../../../config'
|
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 { token } = useContext(AuthContext)
|
||||||
const socketRef = useRef(null)
|
const socketRef = useRef(null)
|
||||||
const [connecting, setConnecting] = useState(false)
|
const [connecting, setConnecting] = useState(false)
|
||||||
@ -24,9 +27,9 @@ const SocketProvider = ({ children }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token) {
|
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,
|
reconnectionAttempts: 3,
|
||||||
timeout: 3000,
|
timeout: 3000,
|
||||||
auth: { token: token }
|
auth: { token: token }
|
||||||
@ -35,20 +38,20 @@ const SocketProvider = ({ children }) => {
|
|||||||
setConnecting(true)
|
setConnecting(true)
|
||||||
|
|
||||||
newSocket.on('connect', () => {
|
newSocket.on('connect', () => {
|
||||||
console.log('Socket connected')
|
log.debug('Print server connected')
|
||||||
setConnecting(false)
|
setConnecting(false)
|
||||||
setError(null)
|
setError(null)
|
||||||
})
|
})
|
||||||
|
|
||||||
newSocket.on('disconnect', () => {
|
newSocket.on('disconnect', () => {
|
||||||
console.log('Socket disconnected')
|
log.debug('Print server disconnected')
|
||||||
setError('Socket disconnected')
|
setError('Print server disconnected')
|
||||||
})
|
})
|
||||||
|
|
||||||
newSocket.on('connect_error', (err) => {
|
newSocket.on('connect_error', (err) => {
|
||||||
console.error('Socket connection error:', err)
|
log.error('Print server connection error:', err)
|
||||||
messageApi.error('Socket connection error: ' + err.message)
|
messageApi.error('Print server connection error: ' + err.message)
|
||||||
setError('Socket connection error')
|
setError('Print server connection error')
|
||||||
})
|
})
|
||||||
|
|
||||||
newSocket.on('bridge.notification', (data) => {
|
newSocket.on('bridge.notification', (data) => {
|
||||||
@ -59,8 +62,8 @@ const SocketProvider = ({ children }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
newSocket.on('error', (err) => {
|
newSocket.on('error', (err) => {
|
||||||
console.error('Socket error:', err)
|
log.error('Print server error:', err)
|
||||||
setError('Socket error')
|
setError('Print server error')
|
||||||
})
|
})
|
||||||
|
|
||||||
socketRef.current = newSocket
|
socketRef.current = newSocket
|
||||||
@ -68,30 +71,30 @@ const SocketProvider = ({ children }) => {
|
|||||||
// Clean up function
|
// Clean up function
|
||||||
return () => {
|
return () => {
|
||||||
if (socketRef.current) {
|
if (socketRef.current) {
|
||||||
console.log('Cleaning up socket connection...')
|
log.debug('Cleaning up socket connection...')
|
||||||
socketRef.current.disconnect()
|
socketRef.current.disconnect()
|
||||||
socketRef.current = null
|
socketRef.current = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!token && socketRef.current) {
|
} else if (!token && socketRef.current) {
|
||||||
console.log('Token not available, disconnecting socket...')
|
log.debug('Token not available, disconnecting socket...')
|
||||||
socketRef.current.disconnect()
|
socketRef.current.disconnect()
|
||||||
socketRef.current = null
|
socketRef.current = null
|
||||||
}
|
}
|
||||||
}, [token, messageApi])
|
}, [token, messageApi])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SocketContext.Provider
|
<PrintServerContext.Provider
|
||||||
value={{ socket: socketRef.current, error, connecting }}
|
value={{ printServer: socketRef.current, error, connecting }}
|
||||||
>
|
>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
{children}
|
{children}
|
||||||
</SocketContext.Provider>
|
</PrintServerContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SocketProvider.propTypes = {
|
PrintServerProvider.propTypes = {
|
||||||
children: PropTypes.node.isRequired
|
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
|
// Focus and select text in input when modal becomes visible
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (showModal && inputRef.current) {
|
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 = {
|
const config = {
|
||||||
development: {
|
development: {
|
||||||
backendUrl: 'http://192.168.68.53:8080',
|
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: {
|
production: {
|
||||||
backendUrl: 'http://192.168.68.53:8080', // Replace with your production backend URL
|
backendUrl: 'http://192.168.68.53:8080',
|
||||||
wsUrl: 'http://192.168.68.53:8081' // Replace with your production WebSocket URL
|
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