From 2746970e4f09d7d5b18f8bf06dadd3d4ef29814d Mon Sep 17 00:00:00 2001 From: Colin Denig Date: Wed, 23 Sep 2026 14:13:41 -0400 Subject: [PATCH 1/5] chore: add ESLint flat config and Prettier setup - eslint.config.js: @eslint/js + typescript-eslint recommended, React hooks, Vite react-refresh, plus type-aware no-floating-promises and no-misused-promises; eslint-config-prettier last to avoid conflicts - Rename prettierrc.json to .prettierrc.json so Prettier finds it, and add .prettierignore - Add lint, lint:fix, format and format:check scripts Co-Authored-By: Claude Opus 5.5 --- .prettierignore | 4 + prettierrc.json => .prettierrc.json | 0 eslint.config.js | 42 ++ package-lock.json | 814 ++++++++++++++++++++-------- package.json | 13 +- 5 files changed, 638 insertions(+), 235 deletions(-) create mode 100644 .prettierignore rename prettierrc.json => .prettierrc.json (100%) create mode 100644 eslint.config.js diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..82945b2 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +dist +coverage +package-lock.json +public diff --git a/prettierrc.json b/.prettierrc.json similarity index 100% rename from prettierrc.json rename to .prettierrc.json diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..b356351 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,42 @@ +import js from '@eslint/js'; +import eslintConfigPrettier from 'eslint-config-prettier/flat'; +import { defineConfig, globalIgnores } from 'eslint/config'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import globals from 'globals'; +import tseslint from 'typescript-eslint'; + +export default defineConfig([ + globalIgnores(['dist', 'coverage']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2022, + globals: globals.browser, + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + // Type-aware rules that catch real bugs: unhandled promises and async handlers + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-misused-promises': 'error', + // React Compiler-era rule; fixes can be non-trivial, so warn while we clean up + 'react-hooks/set-state-in-effect': 'warn', + }, + }, + { + files: ['eslint.config.js'], + extends: [js.configs.recommended], + languageOptions: { globals: globals.node }, + }, + // Must be last: turns off rules that conflict with Prettier + eslintConfigPrettier, +]); diff --git a/package-lock.json b/package-lock.json index 10cadac..f7869d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "web-vitals": "^5.2.0" }, "devDependencies": { + "@eslint/js": "^10.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", "@types/dagre": "^0.7.54", @@ -37,8 +38,14 @@ "@types/react-scroll-to-bottom": "^4.2.5", "@vitejs/plugin-react": "^6.0.1", "eslint": "^10.11.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.7", + "globals": "^17.12.0", "jsdom": "^29.0.1", + "prettier": "^3.9.9", "typescript": "^6.0.2", + "typescript-eslint": "^8.70.1", "vite": "^8.0.3", "vite-plugin-svgr": "^5.0.0", "vitest": "^4.1.2" @@ -51,19 +58,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "devOptional": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@asamuzakjp/css-color": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.1.tgz", @@ -147,12 +141,12 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -161,30 +155,32 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", - "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", - "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "devOptional": true, + "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.0", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -199,39 +195,32 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "devOptional": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "devOptional": true, + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "devOptional": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -239,71 +228,38 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "devOptional": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "devOptional": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "devOptional": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "devOptional": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", - "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "devOptional": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -312,79 +268,55 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "devOptional": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "devOptional": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", - "devOptional": true, + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -415,49 +347,45 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "devOptional": true, + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "devOptional": true, + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -872,6 +800,27 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, "node_modules/@eslint/object-schema": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", @@ -981,33 +930,31 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "devOptional": true, + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "devOptional": true, - "engines": { - "node": ">=6.0.0" + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "devOptional": true, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1016,14 +963,12 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "devOptional": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2452,6 +2397,249 @@ "integrity": "sha512-CqN8MnISMwQbLJXO3doBAV4Yw9hx9/Pyr2rZ78+NfaCnhyRA/nKrpyk6E7mKw17ZOaQdLpK9GiUjrqLzBlN3sg==", "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.70.1.tgz", + "integrity": "sha512-nDNrUQ/4ruSNYbu749TRY7cfrzPtoLHEXSNBI8aaNY32LlZCajixqRf3FqcKC4p5Cam4VOHYx/t+i5+nKXvrqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.70.1", + "@typescript-eslint/type-utils": "8.70.1", + "@typescript-eslint/utils": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.70.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.10.tgz", + "integrity": "sha512-HpbUakT7xp5miBUywCHf36ZEuAJNklBJDDsGpUIjMzOSmM8ELSfA9Sa/QDPeNeqeoN31u+UTCkL4klCOVvRm4Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.70.1.tgz", + "integrity": "sha512-nO974WLllwhSFWQXnMLj6nDGa8f0khKEz1JzpPJ1u7Vm/4X1X6ZHajpoknU4bb41vJyMB0HHVyS2GqdhWfIXZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.70.1", + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.70.1.tgz", + "integrity": "sha512-62xOgboPfwc3/IgPSX/W6oQR3ZbF04194FPGUGH8HL8iLFHbt/456/8Ph1wLNUgVF+s94FlHoipBsz+v7+LMnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.70.1", + "@typescript-eslint/types": "^8.70.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.70.1.tgz", + "integrity": "sha512-Pa0EeSeAusQc1WbjQMac+YfenewYTBu0KjgYvkUKwhXaHUKbFog23Dm/rp0DX/6tyYOQ3Xl1a+3EcFNZynGHCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.70.1.tgz", + "integrity": "sha512-jumze1fPI+sDOaM2TWGQdn39PDxTr7TZGeuyLkAbNyx2vtMT3uRnVKChN0hfht5V2TugphJzF6bYXvBcE09qqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.70.1.tgz", + "integrity": "sha512-7zKTnyvaVWqzLZHPFQtX1hVHqgkMC+WebPWakNCSyrQVbIP1AM0L0TlBZtACldIRb6PptI8Odk+jyZ5kP3B1VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1", + "@typescript-eslint/utils": "8.70.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.1.tgz", + "integrity": "sha512-Dm1ypdhhrGCTyyehxElhgJ6kgk8MVCv5qXdoOVqPr1uqk42jX8KjrZqhROvdShczA8qrDoYiOWn1ykWlx2k81Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.70.1.tgz", + "integrity": "sha512-TU8PwyGN0PQJUcE96mw8eCQ44SmxGdQlJmlWakHaHQ15eIuuvye5yNtmh/i6oS88jzXVQB71xdNkbkB/fMwL0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.70.1", + "@typescript-eslint/tsconfig-utils": "8.70.1", + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.70.1.tgz", + "integrity": "sha512-Esgul8MsnKnRLdYU2Eb2cRV9bS5HJYtKj1ByJnOzzG2M58DGdSUQ1jUuILxipqcpB2h9WLrbD5GijIWUjX/Tqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.70.1", + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.70.1.tgz", + "integrity": "sha512-Vwj9lUIW5Xq3wQ9w6gv3R86g1hMK8f2zNOdGTAgeXUMMXFK78G9ruCjjqutHMNJc0+CH7LYRnHeUB9IT8wFmcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.70.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", @@ -2785,9 +2973,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.13", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.13.tgz", - "integrity": "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw==", + "version": "2.11.25", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.25.tgz", + "integrity": "sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -2840,9 +3028,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz", + "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==", "devOptional": true, "funding": [ { @@ -2860,11 +3048,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.23", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.427", + "node-releases": "^2.0.55", + "update-browserslist-db": "^1.3.3" }, "bin": { "browserslist": "cli.js" @@ -2922,9 +3110,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001782", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001782.tgz", - "integrity": "sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw==", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "devOptional": true, "funding": [ { @@ -3368,9 +3556,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.329", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.329.tgz", - "integrity": "sha512-/4t+AS1l4S3ZC0Ja7PHFIWeBIxGA3QGqV8/yKsP36v7NcyUCl+bIcmw6s5zVuMIECWwBrAK/6QLzTmbJChBboQ==", + "version": "1.5.438", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.438.tgz", + "integrity": "sha512-AN9xMU1hJiT65LkCUPL1DZm5TCbOPb2Qsm5pYwFLEXp6/qj9SdT4yMiqs7Qqstwvkn1zF7l36SRGt+s6XcJ0FA==", "devOptional": true, "license": "ISC" }, @@ -3528,6 +3716,52 @@ } } }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.7.tgz", + "integrity": "sha512-XhJSzLljuYD4UjNuFGJu2v7aD3sqNVK12w5/DCUfrNfHWegZo2+TsavNx8MuxMwEquuFAzNbNfXKU0WoZ+YUIg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, "node_modules/eslint-scope": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", @@ -3868,12 +4102,16 @@ } }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "devOptional": true, + "version": "17.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.12.0.tgz", + "integrity": "sha512-cezEd/DTyyht9cvSSURyygXPfy04GtWO/5e6ZPvH7fCtjKz9PYOmuawphw1Ctd1f6C+5JypXfGD7ahNMXvevBA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/gopd": { @@ -3989,6 +4227,23 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, "node_modules/hookified": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", @@ -4314,15 +4569,15 @@ "license": "CC0-1.0" }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "devOptional": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-parse-even-better-errors": { @@ -4697,6 +4952,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "devOptional": true, + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } @@ -5689,11 +5945,14 @@ "optional": true }, "node_modules/node-releases": { - "version": "2.0.36", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", - "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "version": "2.0.57", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.57.tgz", + "integrity": "sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==", "devOptional": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/object-assign": { "version": "4.1.1", @@ -5941,6 +6200,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.9.tgz", + "integrity": "sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", @@ -6512,6 +6787,16 @@ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/set-cookie-parser": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", @@ -6805,6 +7090,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -6838,6 +7136,30 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.70.1.tgz", + "integrity": "sha512-AcWG7KDjZ2THNXsgwttMaGmzVi0VFRlFYfqFHYQRbDpF3owuYbuiL8c7UUrd2k8s3PoSfIQrWfrGXfcElrWLYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.70.1", + "@typescript-eslint/parser": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1", + "@typescript-eslint/utils": "8.70.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, "node_modules/uncontrollable": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", @@ -6957,9 +7279,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", "devOptional": true, "funding": [ { @@ -7345,7 +7667,8 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "devOptional": true + "devOptional": true, + "license": "ISC" }, "node_modules/yocto-queue": { "version": "0.1.0", @@ -7360,6 +7683,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zod": { + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", + "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, "node_modules/zustand": { "version": "4.5.7", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", diff --git a/package.json b/package.json index 186843b..e1ac1f9 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,14 @@ "start": "vite", "build": "tsc -b && vite build", "preview": "vite preview", - "test": "vitest" + "test": "vitest", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "format": "prettier --write .", + "format:check": "prettier --check ." }, "devDependencies": { + "@eslint/js": "^10.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", "@types/dagre": "^0.7.54", @@ -39,8 +44,14 @@ "@types/react-scroll-to-bottom": "^4.2.5", "@vitejs/plugin-react": "^6.0.1", "eslint": "^10.11.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.7", + "globals": "^17.12.0", "jsdom": "^29.0.1", + "prettier": "^3.9.9", "typescript": "^6.0.2", + "typescript-eslint": "^8.70.1", "vite": "^8.0.3", "vite-plugin-svgr": "^5.0.0", "vitest": "^4.1.2" From 240c88cfcecad248f9c230e85fd5a9d2779e145c Mon Sep 17 00:00:00 2001 From: Colin Denig Date: Wed, 23 Sep 2026 14:14:32 -0400 Subject: [PATCH 2/5] style: format codebase with Prettier No functional changes; generated by `npm run format`. Co-Authored-By: Claude Opus 5.5 --- .prettierrc.json | 2 +- .releaserc.json | 13 +- .vscode/launch.json | 21 +- .vscode/settings.json | 19 +- .vscode/snippets.code-snippets | 247 ++++++----- README.md | 29 +- docs/README.md | 7 +- docs/explanation/README.md | 33 +- docs/explanation/architecture.md | 41 +- docs/explanation/configuration-management.md | 43 +- docs/explanation/debug-console-design.md | 37 ++ docs/explanation/security.md | 61 ++- docs/how-to/README.md | 38 +- docs/how-to/export-configuration.md | 39 +- docs/how-to/filter-debug-messages.md | 53 ++- docs/how-to/monitor-performance.md | 32 +- docs/how-to/restart-reload-config.md | 49 ++- docs/how-to/trace-signal-routes.md | 23 +- docs/how-to/troubleshoot-connection.md | 38 +- docs/reference/README.md | 36 +- docs/reference/api-endpoints.md | 98 ++++- docs/reference/configuration-schema.md | 87 ++-- docs/reference/device-types.md | 62 ++- docs/reference/log-levels.md | 126 ++++-- docs/reference/ui-components.md | 137 +++++-- docs/tutorials/README.md | 16 +- docs/tutorials/debug-console-basics.md | 21 +- docs/tutorials/device-management-basics.md | 28 +- docs/tutorials/getting-started.md | 19 +- index.html | 2 +- src/App.test.tsx | 22 +- src/App.tsx | 110 ++--- src/features/ApiPathDetailDrawer.tsx | 10 +- src/features/ApiPaths.tsx | 18 +- src/features/ConfigFile.tsx | 15 +- src/features/DebugConsole/ConsoleWindow.tsx | 25 +- src/features/DebugConsole/DebugConsole.tsx | 110 +++-- src/features/DebugConsole/DebugFilters.tsx | 2 - .../DebugConsole/DeviceFilterDropdown.tsx | 18 +- .../DebugConsole/LogMessageDetailDrawer.tsx | 4 +- .../DebugConsole/MinimumLogLevelDropdown.tsx | 20 +- .../DebugConsole/RestartConfirmModal.tsx | 42 +- src/features/DebugConsole/debugConsts.ts | 38 +- src/features/DeviceDetail.tsx | 84 ++-- src/features/DeviceList.tsx | 8 +- src/features/ErrorBoundary.tsx | 6 +- src/features/Help/Help.test.tsx | 68 ++-- src/features/Help/Help.tsx | 10 +- src/features/Help/HelpArticle.tsx | 10 +- src/features/Help/HelpSidebar.tsx | 10 +- src/features/Help/docsContent.test.ts | 83 ++-- src/features/Help/docsContent.ts | 74 ++-- src/features/InitializationExceptions.tsx | 21 +- src/features/LoginForm.tsx | 40 +- src/features/MainLayout.tsx | 13 +- src/features/MobileControl.tsx | 42 +- .../MultiviewLayoutCanvas.module.scss | 5 +- src/features/MultiviewLayoutCanvas.tsx | 22 +- src/features/MultiviewLayoutPanel.tsx | 33 +- src/features/RequireAuth.tsx | 8 +- src/features/Routing.tsx | 383 +++++++++++------- src/features/RoutingDeviceNode.tsx | 146 +++++-- src/features/TieLineEdge.tsx | 4 +- src/features/TopNav.tsx | 44 +- src/features/Types.tsx | 4 +- src/features/Versions.tsx | 4 +- src/index.tsx | 18 +- src/react-app-env.d.ts | 4 +- src/shared/FilterDropdownSearchParams.tsx | 4 +- src/shared/FilterSearchText.tsx | 11 +- src/shared/ListFiltersHeader.tsx | 11 +- src/shared/functions/meetsMinimumVersion.ts | 12 +- src/shared/hooks/useAppParams.ts | 2 +- src/shared/icons/index.tsx | 1 - src/shared/types/LogMessage.ts | 2 +- src/store/apiSlice.ts | 124 +++--- src/store/commonUi/commonUiHooks.ts | 2 +- src/store/commonUi/commonUiSelectors.ts | 3 +- src/store/commonUi/commonUiSlice.ts | 3 +- src/store/commonUi/commonUiState.ts | 3 +- src/store/hooks.ts | 10 +- src/store/routingFeedbackMiddleware.ts | 53 +-- src/store/routingFeedbackSlice.ts | 28 +- src/store/store.ts | 42 +- src/store/websocketMiddleware.test.ts | 32 +- src/store/websocketMiddleware.ts | 22 +- src/store/websocketSlice.ts | 20 +- src/styles.scss | 18 +- src/vite-env.d.ts | 2 +- tsconfig.json | 11 +- vite.config.ts | 33 +- 91 files changed, 2297 insertions(+), 1187 deletions(-) diff --git a/.prettierrc.json b/.prettierrc.json index 1dc7164..0a72520 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -3,4 +3,4 @@ "tabWidth": 2, "semi": true, "singleQuote": true -} \ No newline at end of file +} diff --git a/.releaserc.json b/.releaserc.json index 416f7dc..0c9fae6 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -9,8 +9,9 @@ ] } ], - "@semantic-release/release-notes-generator", - ["@semantic-release/changelog", + "@semantic-release/release-notes-generator", + [ + "@semantic-release/changelog", { "changelogFile": "CHANGELOG.md" } @@ -22,15 +23,15 @@ "publishCmd": "echo \"version=${nextRelease.version}\" >> $GITHUB_OUTPUT && echo \"tag=${nextRelease.gitTag}\" >> $GITHUB_OUTPUT && echo \"type=${nextRelease.type}\" >> $GITHUB_OUTPUT && echo \"channel=${nextRelease.channel}\" >> $GITHUB_OUTPUT" } ] - ], + ], "branches": [ "main", - {"name": "development", "prerelease": "beta", "channel": "beta"}, - {"name": "release", "prerelease": "rc", "channel": "rc"}, + { "name": "development", "prerelease": "beta", "channel": "beta" }, + { "name": "release", "prerelease": "rc", "channel": "rc" }, { "name": "replace-me-feature-branch", "prerelease": "replace-me-prerelease", "channel": "replace-me-prerelease" } ] -} \ No newline at end of file +} diff --git a/.vscode/launch.json b/.vscode/launch.json index 302db40..4e51580 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,23 +4,20 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ - { - "name": "Launch Edge", - "request": "launch", - "type": "msedge", - "url": "http://localhost:8080", - "webRoot": "${workspaceFolder}" - }, + { + "name": "Launch Edge", + "request": "launch", + "type": "msedge", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + }, { "type": "msedge", "request": "launch", "name": "Launch Edge against localhost", "url": "https://localhost:3000/debug/", "webRoot": "${workspaceFolder}", - "outFiles": [ - "${workspaceFolder}/**/*.js", - "!**/node_modules/**" - ] + "outFiles": ["${workspaceFolder}/**/*.js", "!**/node_modules/**"] } ] -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 499de86..b25ebd0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,22 +1,11 @@ { - "conventionalCommits.scopes": [ - "force-patch" - ], + "conventionalCommits.scopes": ["force-patch"], "editor.tabSize": 2, "conventionalCommits.gitmoji": false, "conventionalCommits.promptFooter": false, - "eslint.validate": [ - "javascript", - "typescript", - "html" - ], + "eslint.validate": ["javascript", "typescript", "html"], "eslint.options": { - "extensions": [ - ".js", - ".ts", - "html", - "tsx" - ] + "extensions": [".js", ".ts", "html", "tsx"] }, "eslint.rules.customizations": [ { @@ -37,4 +26,4 @@ "typescript.updateImportsOnFileMove.enabled": "always", "javascript.updateImportsOnFileMove.enabled": "always", "editor.linkedEditing": true -} \ No newline at end of file +} diff --git a/.vscode/snippets.code-snippets b/.vscode/snippets.code-snippets index 1aed353..29d7d03 100644 --- a/.vscode/snippets.code-snippets +++ b/.vscode/snippets.code-snippets @@ -1,130 +1,121 @@ { - // Place your portal-frontend workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and - // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope - // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is - // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: - // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. - // Placeholders with the same ids are connected. - // Example: - // "Print to console": { - // "scope": "javascript,typescript", - // "prefix": "log", - // "body": [ - // "console.info('$1');", - // "$2" - // ], - // "description": "Log output to console" - // } - "Effects Comment": { - "prefix": "*eff", - "body": [ - "/* EFFECTS *********************************************************/$0" - ], - "description": "Adds EFFECTS comment" - }, - "Functions Comment": { - "prefix": "*fun", - "body": [ - "/* FUNCTIONS *******************************************************/$0" - ], - "description": "Adds FUNCTIONS comment" - }, - "Hooks Comment": { - "prefix": "*hoo", - "body": [ - "/* HOOKS ***********************************************************/$0" - ], - "description": "Adds HOOKS comment" - }, - "Render Comment": { - "prefix": "*ren", - "body": [ - "/* RENDER **********************************************************/$0" - ], - "description": "Adds RENDER comment" - }, - "State Comment": { - "prefix": "*state", - "body": [ - "/* STATE ***********************************************************/$0" - ], - "description": "Adds STATE comment" - }, - "Create Function Component": { - "prefix": "cfc", - "body": [ - "import React from 'react';", - "", - "const ${1:$TM_FILENAME_BASE} = () => {", - " return <>;", - "}", - "", - "export default $1;" - ], - "description": "Adds boilerplate for a function component without props", - "scope": "typescriptreact" - }, - "Create Function Component With Props": { - "prefix": "cfcp", - "body": [ - "import React from 'react';", - "", - "const ${1:$TM_FILENAME_BASE} = ({}: $1Props) => {", - " return <>;", - "}", - "", - "export default $1;", - "", - "interface ${1}Props {", - "", - "}" - ], - "description": "Adds boilerplate for a function component with props and interface", - "scope": "typescriptreact" - }, - "Create Props for Function Component": { - "prefix": "cprops", - "body": [ - "interface ${1:$TM_FILENAME_BASE}Props {", - " $0", - "}" - ], - "description": "Adds props interface to existing component", - "scope": "typescriptreact" - }, - "useAppTitle Hook": { - "prefix": "useapptitle", - "body": "const setTitle = useAppTitle$0();", - "description": "Adds useAppTitle hook", - "scope": "typescriptreact" - }, - "useAppTitleRight Hook": { - "prefix": "useapptitleright", - "body": "const setTitleRight = useAppTitleRight$0();", - "description": "Adds useAppTitleRight hook", - "scope": "typescriptreact" - }, - "useSearchParams Hook": { - "prefix": "usesearchparams", - "body": "const [searchParams, setSearchParams] = useSearchParams$0();", - "description": "Adds useSearchParams hook", - "scope": "typescriptreact" - }, - "useState Hook": { - "prefix": "usestate", - "body": [ - "const [$1, set${1/(.)/${1:/capitalize}/}] = useState$2($3);" - ], - "description": "Adds useState hook", - "scope": "typescriptreact" - }, - "useEffect Hook": { - "prefix":"useeffect", - "body": ["useEffect$0(() => {", - " ", - "}, [$1]);" - ], - "description": "Adds useEffect hook", - "scope": "typescriptreact" - } + // Place your portal-frontend workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and + // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope + // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is + // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: + // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. + // Placeholders with the same ids are connected. + // Example: + // "Print to console": { + // "scope": "javascript,typescript", + // "prefix": "log", + // "body": [ + // "console.info('$1');", + // "$2" + // ], + // "description": "Log output to console" + // } + "Effects Comment": { + "prefix": "*eff", + "body": [ + "/* EFFECTS *********************************************************/$0", + ], + "description": "Adds EFFECTS comment", + }, + "Functions Comment": { + "prefix": "*fun", + "body": [ + "/* FUNCTIONS *******************************************************/$0", + ], + "description": "Adds FUNCTIONS comment", + }, + "Hooks Comment": { + "prefix": "*hoo", + "body": [ + "/* HOOKS ***********************************************************/$0", + ], + "description": "Adds HOOKS comment", + }, + "Render Comment": { + "prefix": "*ren", + "body": [ + "/* RENDER **********************************************************/$0", + ], + "description": "Adds RENDER comment", + }, + "State Comment": { + "prefix": "*state", + "body": [ + "/* STATE ***********************************************************/$0", + ], + "description": "Adds STATE comment", + }, + "Create Function Component": { + "prefix": "cfc", + "body": [ + "import React from 'react';", + "", + "const ${1:$TM_FILENAME_BASE} = () => {", + " return <>;", + "}", + "", + "export default $1;", + ], + "description": "Adds boilerplate for a function component without props", + "scope": "typescriptreact", + }, + "Create Function Component With Props": { + "prefix": "cfcp", + "body": [ + "import React from 'react';", + "", + "const ${1:$TM_FILENAME_BASE} = ({}: $1Props) => {", + " return <>;", + "}", + "", + "export default $1;", + "", + "interface ${1}Props {", + "", + "}", + ], + "description": "Adds boilerplate for a function component with props and interface", + "scope": "typescriptreact", + }, + "Create Props for Function Component": { + "prefix": "cprops", + "body": ["interface ${1:$TM_FILENAME_BASE}Props {", " $0", "}"], + "description": "Adds props interface to existing component", + "scope": "typescriptreact", + }, + "useAppTitle Hook": { + "prefix": "useapptitle", + "body": "const setTitle = useAppTitle$0();", + "description": "Adds useAppTitle hook", + "scope": "typescriptreact", + }, + "useAppTitleRight Hook": { + "prefix": "useapptitleright", + "body": "const setTitleRight = useAppTitleRight$0();", + "description": "Adds useAppTitleRight hook", + "scope": "typescriptreact", + }, + "useSearchParams Hook": { + "prefix": "usesearchparams", + "body": "const [searchParams, setSearchParams] = useSearchParams$0();", + "description": "Adds useSearchParams hook", + "scope": "typescriptreact", + }, + "useState Hook": { + "prefix": "usestate", + "body": ["const [$1, set${1/(.)/${1:/capitalize}/}] = useState$2($3);"], + "description": "Adds useState hook", + "scope": "typescriptreact", + }, + "useEffect Hook": { + "prefix": "useeffect", + "body": ["useEffect$0(() => {", " ", "}, [$1]);"], + "description": "Adds useEffect hook", + "scope": "typescriptreact", + }, } diff --git a/README.md b/README.md index f224de4..a627418 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,13 @@ A powerful web-based configuration and debugging tool for PepperDash Essentials ## 🚀 Quick Start ### For Users + **New to the application?** Start with the [Getting Started Tutorial](./docs/tutorials/getting-started.md) for a guided introduction. **Need to solve a specific problem?** Check the [How-to Guides](./docs/how-to/) for step-by-step solutions. ### For Developers + **Setting up the development environment:** ```bash @@ -31,13 +33,17 @@ The app will be available at `http://localhost:5173/cws/debug/`. This project uses the [Diataxis framework](https://diataxis.fr/) to provide you with the right information at the right time: ### 🎯 [Tutorials](./docs/tutorials/) - Learning-oriented + **"Take me by the hand and teach me"** + - [Getting Started Tutorial](./docs/tutorials/getting-started.md) - Your first steps with the web config app - [Debug Console Tutorial](./docs/tutorials/debug-console-basics.md) - Master the debug console - [Device Management Tutorial](./docs/tutorials/device-management-basics.md) - Device inspection and management ### 🔧 [How-to Guides](./docs/how-to/) - Problem-oriented + **"Show me how to solve this specific problem"** + - [Troubleshooting Connection Issues](./docs/how-to/troubleshoot-connection.md) - [Filter and Search Debug Messages](./docs/how-to/filter-debug-messages.md) - [Export and Analyze Configuration](./docs/how-to/export-configuration.md) @@ -46,7 +52,9 @@ This project uses the [Diataxis framework](https://diataxis.fr/) to provide you - [Trace Signal Routes and Read the Routing Diagram](./docs/how-to/trace-signal-routes.md) ### 📚 [Reference](./docs/reference/) - Information-oriented + **"Tell me the facts"** + - [UI Components Reference](./docs/reference/ui-components.md) - Complete component documentation - [API Endpoints Reference](./docs/reference/api-endpoints.md) - All available REST endpoints - [Configuration Schema Reference](./docs/reference/configuration-schema.md) - Configuration file structure @@ -54,7 +62,9 @@ This project uses the [Diataxis framework](https://diataxis.fr/) to provide you - [Log Levels and Filters Reference](./docs/reference/log-levels.md) - Complete logging reference ### 💡 [Explanation](./docs/explanation/) - Understanding-oriented + **"Help me understand why and how this works"** + - [System Architecture](./docs/explanation/architecture.md) - How the web app integrates with Essentials - [Debug Console Design](./docs/explanation/debug-console-design.md) - How real-time debugging works - [Configuration Management](./docs/explanation/configuration-management.md) - How configuration is handled @@ -75,15 +85,19 @@ This project uses the [Diataxis framework](https://diataxis.fr/) to provide you ### Available Scripts #### `npm start` + Runs the app in development mode via Vite. The page will reload when you make edits. Available at `http://localhost:5173/cws/debug/`. #### `npm test` + Launches the Vitest test runner in interactive watch mode. #### `npm run build` + Compiles TypeScript and builds the app for production to the `dist/` folder with optimized bundles. #### `npm run preview` + Serves the production build locally for inspection before deployment. ### Environment Setup @@ -96,6 +110,7 @@ VITE_PROGRAM_ID=app01 # Optional: Default application slot ``` **Development Prerequisites:** + - Node.js 18+ - npm - Network access to target PepperDash Essentials processor @@ -104,6 +119,7 @@ VITE_PROGRAM_ID=app01 # Optional: Default application slot ### Architecture Overview **Frontend Stack:** + - React 19 with TypeScript - Redux Toolkit for state management (including WebSocket middleware) - React Router v7 for navigation @@ -111,6 +127,7 @@ VITE_PROGRAM_ID=app01 # Optional: Default application slot - WebSocket for real-time communication **Integration:** + - Connects to PepperDash Essentials processors via HTTPS API at `/cws//api/` - Uses WebSocket for real-time debug message streaming - In development, Vite proxies all `/cws/` API requests to `PROGRAM_HOST` @@ -126,12 +143,14 @@ VITE_PROGRAM_ID=app01 # Optional: Default application slot ## 🌐 Browser Compatibility **Supported Browsers:** + - Chrome 70+ - Firefox 65+ - Safari 12+ - Edge 79+ **Required Features:** + - WebSocket support for real-time debugging - Modern JavaScript (ES6+) support - CSS Grid and Flexbox for responsive layouts @@ -139,16 +158,19 @@ VITE_PROGRAM_ID=app01 # Optional: Default application slot ## 📖 Learning Resources **New Users:** + 1. Start with [Getting Started Tutorial](./docs/tutorials/getting-started.md) 2. Learn [Debug Console Basics](./docs/tutorials/debug-console-basics.md) 3. Explore [Device Management](./docs/tutorials/device-management-basics.md) **Troubleshooting:** + - Check [How-to Guides](./docs/how-to/) for specific solutions - Review [Connection Troubleshooting](./docs/how-to/troubleshoot-connection.md) for access issues - Use [Performance Monitoring](./docs/how-to/monitor-performance.md) for system health -**Advanced Usage:** +**Advanced Usage:** + - Understand [System Architecture](./docs/explanation/architecture.md) - Learn [Debug Console Design](./docs/explanation/debug-console-design.md) - Reference [API Documentation](./docs/reference/api-endpoints.md) @@ -156,6 +178,7 @@ VITE_PROGRAM_ID=app01 # Optional: Default application slot ## 🤝 Contributing This project follows standard React development practices: + - TypeScript for type safety - ESLint and Prettier for code formatting - Component-based architecture with feature organization @@ -168,15 +191,17 @@ MIT License - see [LICENSE](./LICENSE) file for details. ## 🆘 Support **For Application Issues:** + - Check the [How-to Guides](./docs/how-to/) for common solutions - Review system requirements and browser compatibility - Verify network connectivity to target processor **For PepperDash Essentials Questions:** + - Consult PepperDash documentation and support resources - Verify Essentials framework version compatibility - Check processor configuration and network settings --- -*Built with ❤️ for the PepperDash community. This web application makes PepperDash Essentials systems more accessible and manageable through modern web interfaces.* +_Built with ❤️ for the PepperDash community. This web application makes PepperDash Essentials systems more accessible and manageable through modern web interfaces._ diff --git a/docs/README.md b/docs/README.md index 315de13..8c4b408 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,6 +7,7 @@ Welcome to the comprehensive documentation for the PepperDash Essentials Web Con This documentation follows the [Diataxis framework](https://diataxis.fr/) to provide you with the right information at the right time: ### 🎯 [Tutorials](./tutorials/) - Learning-oriented + **"Take me by the hand and teach me"** Step-by-step guides that take you through your first experiences with the application. Perfect for newcomers who want to get started quickly. @@ -16,6 +17,7 @@ Step-by-step guides that take you through your first experiences with the applic - **[Device Management Tutorial](./tutorials/device-management-basics.md)** - Basic device inspection and management ### 🔧 [How-to Guides](./how-to/) - Problem-oriented + **"Show me how to solve this specific problem"** Practical guides that solve specific problems you might encounter. These assume you have basic familiarity with the system. @@ -28,6 +30,7 @@ Practical guides that solve specific problems you might encounter. These assume - **[Trace Signal Routes and Read the Routing Diagram](./how-to/trace-signal-routes.md)** ### 📚 [Reference](./reference/) - Information-oriented + **"Tell me the facts"** Complete technical information about all features, APIs, and components. Organized for easy lookup. @@ -39,6 +42,7 @@ Complete technical information about all features, APIs, and components. Organiz - **[Log Levels and Filters](./reference/log-levels.md)** - Complete logging reference ### 💡 [Explanation](./explanation/) - Understanding-oriented + **"Help me understand why and how this works"** Background information and design decisions that help you understand the system's architecture and concepts. @@ -85,10 +89,11 @@ The app supports up to 10 simultaneous PepperDash Essentials program slots (`app ## Support For technical support and questions: + - Check the [How-to Guides](./how-to/) for common solutions - Review the [Reference](./reference/) documentation for technical details - Consult the [Explanation](./explanation/) articles for deeper understanding --- -*This documentation is organized using the [Diataxis framework](https://diataxis.fr/) to ensure you get the right type of information for your needs.* +_This documentation is organized using the [Diataxis framework](https://diataxis.fr/) to ensure you get the right type of information for your needs._ diff --git a/docs/explanation/README.md b/docs/explanation/README.md index 1770d8c..c2f6f5a 100644 --- a/docs/explanation/README.md +++ b/docs/explanation/README.md @@ -7,9 +7,11 @@ This section provides background information, design rationale, and conceptual u ## 🏗️ System Design and Architecture ### [System Architecture](./architecture.md) + **Understanding the overall system design and integration patterns** **Key Topics**: + - How the web app fits into the broader PepperDash ecosystem - Architectural layers and their responsibilities - Communication patterns between components @@ -18,6 +20,7 @@ This section provides background information, design rationale, and conceptual u - Design philosophy and trade-offs **Why Read This**: + - Understand how the web app integrates with the Essentials framework - Learn about the technical decisions that shape system behavior - Gain insight into security and performance considerations @@ -26,9 +29,11 @@ This section provides background information, design rationale, and conceptual u --- ### [Debug Console Design](./debug-console-design.md) + **Deep dive into the design principles behind the core debugging feature** **Key Topics**: + - Real-time monitoring design philosophy - WebSocket vs. HTTP polling decision rationale - Information hierarchy and progressive disclosure @@ -37,6 +42,7 @@ This section provides background information, design rationale, and conceptual u - Workflow optimization for common debugging tasks **Why Read This**: + - Understand why the debug console works the way it does - Learn effective debugging strategies based on the design - Appreciate the complexity and sophistication of the feature @@ -47,9 +53,11 @@ This section provides background information, design rationale, and conceptual u ## 🔧 Feature Design Concepts ### [Configuration Management](./configuration-management.md) + **How configuration is handled, stored, and presented** **Key Topics**: + - Configuration merging and hierarchy concepts - Real-time vs. static configuration access - Security considerations for configuration data @@ -57,6 +65,7 @@ This section provides background information, design rationale, and conceptual u - Integration with the Essentials configuration system **Why Read This**: + - Understand how your system configuration is processed - Learn about configuration best practices - Understand the relationship between files and runtime configuration @@ -65,9 +74,11 @@ This section provides background information, design rationale, and conceptual u --- ### [Security Considerations](./security.md) + **Security model, threats, and best practices** **Key Topics**: + - Authentication and authorization model - Data sensitivity and protection measures - Network security requirements and recommendations @@ -76,6 +87,7 @@ This section provides background information, design rationale, and conceptual u - Best practices for secure deployment **Why Read This**: + - Understand the security implications of using the web app - Learn about proper deployment in enterprise environments - Understand what data is exposed and how it's protected @@ -114,16 +126,19 @@ Rather than replacing existing Essentials framework functionality, the web app i ### Mental Models for Different User Types **System Administrators**: + - Think in terms of overall system health and performance - Need broad visibility with ability to drill down to specifics - Focus on proactive monitoring and rapid problem resolution **Technicians**: + - Think in terms of specific devices and their behavior - Need detailed diagnostic information for troubleshooting - Focus on understanding device interactions and communication **Developers**: + - Think in terms of code behavior and system integration - Need access to detailed technical information and structured data - Focus on understanding system behavior for development and testing @@ -131,6 +146,7 @@ Rather than replacing existing Essentials framework functionality, the web app i ### Information Architecture Concepts **Hierarchical Information Structure**: + ``` System Level (Global messages, overall health) ↓ @@ -142,6 +158,7 @@ Detail Level (Complete technical information) ``` **Temporal Information Structure**: + ``` Historical (What happened before) ↓ @@ -158,12 +175,14 @@ Predictive (What might happen next) **Complementary Tools**: The web app doesn't replace other PepperDash tools but complements them: + - **Touch Panels**: Provide user control interfaces - **Mobile Apps**: Offer convenient user control - **Configuration Tools**: Handle system setup and management - **Web Config App**: Provides monitoring, debugging, and analysis **Data Flow Relationships**: + ``` Configuration Files ──► Framework ──► Web App Display │ @@ -175,12 +194,14 @@ User Interactions ────────┘ ### Operational Context **Development Lifecycle Support**: + - **Design Phase**: Types and configuration reference - **Implementation Phase**: Real-time debugging and testing - **Deployment Phase**: System validation and verification - **Maintenance Phase**: Monitoring and troubleshooting **User Workflow Integration**: + - **Daily Monitoring**: Quick health checks and status verification - **Problem Response**: Detailed investigation and diagnosis - **System Changes**: Configuration backup and change validation @@ -193,29 +214,34 @@ User Interactions ────────┘ ### Conceptual Learning Path **Basic Understanding** (Everyone should understand): + - What the web app is and how it fits in the system - Basic navigation and core features - Security model and access patterns **Operational Understanding** (Regular users should understand): + - How real-time monitoring works and why it's valuable - How filtering and search work together - How to interpret different types of messages and data **Deep Understanding** (Advanced users and developers should understand): -- Architectural design decisions and their implications + +- Architectural design decisions and their implications - Performance characteristics and optimization strategies - Integration patterns and extension possibilities ### Conceptual Dependencies **Prerequisites for Deep Understanding**: + - Basic familiarity with PepperDash Essentials framework - Understanding of web application architecture concepts - Knowledge of network communication patterns - Appreciation for user interface design principles **Building Conceptual Knowledge**: + 1. **Start with Architecture**: Understand the overall system design 2. **Focus on Core Features**: Deep dive into debug console design 3. **Expand to Specifics**: Learn about configuration and security @@ -254,6 +280,7 @@ The deep integration with the Essentials framework demonstrates patterns for bui ### Design Alternative Analysis **What If Different Choices Were Made?** + - Server-side filtering instead of client-side - HTTP polling instead of WebSocket streaming - Modal dialogs instead of slide-out drawers @@ -265,15 +292,17 @@ Each alternative choice would have different performance characteristics, user e ### Future Evolution Considerations **Scalability Questions**: + - How would the design handle 10x more devices? - What happens with 100x more message volume? - How would multiple simultaneous users impact performance? **Feature Extension Questions**: + - How would device control capabilities integrate? - What would configuration editing require? - How would multi-system support work? --- -*Explanation documentation helps you understand not just what the system does, but why it does it that way. This understanding enables more effective usage, better troubleshooting, and informed decision-making about how to integrate the tool into your workflows.* +_Explanation documentation helps you understand not just what the system does, but why it does it that way. This understanding enables more effective usage, better troubleshooting, and informed decision-making about how to integrate the tool into your workflows._ diff --git a/docs/explanation/architecture.md b/docs/explanation/architecture.md index 077db71..e736a67 100644 --- a/docs/explanation/architecture.md +++ b/docs/explanation/architecture.md @@ -34,21 +34,25 @@ This article explains the architectural design, system relationships, and techni The web application serves several specific roles within this ecosystem: **Configuration Management**: + - Provides read-only access to the merged system configuration - Allows visualization of complex configuration relationships - Enables configuration backup and documentation **Real-Time Monitoring**: + - Offers live insight into system operations through debug messages - Enables filtering and analysis of system behavior - Provides troubleshooting capabilities for system administrators **System Control** (Limited): + - Allows system restart and configuration reloading - Provides control over debug logging levels - Enables controlled system maintenance operations **Development Support**: + - Assists in system development and debugging - Provides detailed insight into device communications - Enables testing and validation of system configurations @@ -58,6 +62,7 @@ The web application serves several specific roles within this ecosystem: ### Presentation Layer (React Frontend) **Technology Stack**: + - **React 18**: Component-based UI framework - **TypeScript**: Type-safe development - **Bootstrap 5**: Responsive design framework @@ -67,16 +72,19 @@ The web application serves several specific roles within this ecosystem: **Key Design Decisions**: **Single Page Application (SPA)**: + - Eliminates page refreshes for better user experience - Maintains WebSocket connections across navigation - Provides responsive interface suitable for various devices **Component-Based Architecture**: + - Reusable UI components for consistent interface - Separation of concerns between display and logic - Maintainable codebase with clear component boundaries **State Management Strategy**: + - **RTK Query**: Server state management and caching - **Redux Toolkit**: Client state management for authentication, debug console filters, and UI state - `auth` slice: global authentication state and available app slot list @@ -115,17 +123,20 @@ Web Browser ──HTTPS──► Control Processor **API Design Principles**: -**RESTful Endpoints**: +**RESTful Endpoints**: + - Standard HTTP methods (GET for retrieval, POST for actions) - Resource-based URLs that map to system concepts - Consistent response formats across all endpoints **Minimal Surface Area**: + - Exposes only necessary functionality to the web interface - Maintains security by limiting available operations - Reduces complexity by focusing on specific use cases **Real-Time Capability**: + - WebSocket connection for live debug message streaming - Bidirectional communication potential (currently read-only) - Efficient handling of high-volume message streams @@ -136,16 +147,19 @@ Web Browser ──HTTPS──► Control Processor The API layer acts as a bridge between the web interface and the core Essentials framework: **Configuration Access**: + - Reads merged configuration from the framework's configuration system - Provides access to both static configuration and runtime state - Maintains consistency with the framework's configuration model **Device Management**: + - Accesses the framework's device registry for device information - Provides device property and method information - Maintains synchronization with actual device states **Logging Integration**: + - Taps into the framework's structured logging system - Provides real-time access to log messages as they're generated - Supports filtering and level control through the logging framework @@ -163,6 +177,7 @@ Most operations use standard HTTP request-response patterns: 4. **Client Processing**: Web app processes response and updates UI **Caching Strategy**: + - **Static Data**: Versions, device types cached in browser - **Dynamic Data**: Device lists, configurations fetched on demand - **Real-Time Data**: Debug messages streamed, not cached @@ -181,6 +196,7 @@ The debug console uses WebSocket communication for real-time message streaming: ``` **Message Flow Architecture**: + ``` Framework Logging ──► Message Buffer ──► WebSocket ──► Client Browser │ @@ -191,6 +207,7 @@ Framework Logging ──► Message Buffer ──► WebSocket ──► Client ``` **Performance Considerations**: + - **Message Buffering**: Framework buffers messages to handle bursts - **Rate Limiting**: Prevents overwhelming slow clients - **Connection Management**: Handles client disconnections gracefully @@ -213,10 +230,12 @@ The web app implements its own credential-based authentication flow on top of th After credentials are validated, the application probes all 10 possible slots (`app01`–`app10`) in parallel using `Promise.allSettled`. Slots that respond successfully are stored as `availableApps` and populate the app selector dropdown in the top navigation bar. **No Independent Authentication**: Web app doesn't implement its own persistent user system + - **Processor Integration**: Uses whatever authentication the processor has configured - **Session Management**: Relies on processor's session handling **Security Boundaries**: + ``` Internet ──[Firewall]──► Internal Network ──[HTTPS]──► Processor Web Server │ @@ -227,11 +246,13 @@ Internet ──[Firewall]──► Internal Network ──[HTTPS]──► Proce ### Data Protection **In-Transit Security**: + - **HTTPS Required**: All communication encrypted with TLS - **Certificate Handling**: Self-signed certificates common for internal devices - **WebSocket Security**: WSS (secure WebSocket) for debug messages **Data Sensitivity**: + - **Configuration Data**: May contain IP addresses, device information - **Debug Messages**: May contain operational details and error information - **No User Data**: Application doesn't store personal or credential information @@ -241,6 +262,7 @@ Internet ──[Firewall]──► Internal Network ──[HTTPS]──► Proce ### Browser Performance **Client-Side Optimization**: + ``` Message Volume ──► Client Filtering ──► DOM Updates ──► Display │ │ │ @@ -250,6 +272,7 @@ Message Buffers State Updates (Future Enhancement) ``` **Performance Characteristics**: + - **Message Processing**: Can handle 100+ messages per second - **Memory Management**: Messages accumulate in browser memory - **UI Responsiveness**: Maintained through efficient React updates @@ -257,11 +280,13 @@ Message Buffers State Updates (Future Enhancement) ### Server-Side Performance **Framework Integration Impact**: + - **Minimal Framework Load**: Web API designed for minimal impact - **Debug Session Overhead**: Each active session consumes resources - **Multiple Client Support**: Framework can support several concurrent web sessions **Resource Management**: + - **Connection Limits**: Framework may limit concurrent debug sessions - **Memory Usage**: Message buffering uses framework memory - **CPU Impact**: Minimal when not actively debugging @@ -271,6 +296,7 @@ Message Buffers State Updates (Future Enhancement) ### Code Organization **Frontend Structure**: + ``` src/ ├── features/ # Feature-based organization @@ -283,6 +309,7 @@ src/ ``` **Design Patterns**: + - **Feature-Based Organization**: Related components grouped together - **Shared Components**: Reusable UI elements across features - **Service Layer**: Abstracted API communication @@ -291,12 +318,14 @@ src/ ### Build and Deployment **Build Process**: + 1. **TypeScript Compilation**: Type checking and compilation 2. **Bundling**: Webpack bundles for browser delivery 3. **Asset Optimization**: Minification and compression 4. **Static File Generation**: Ready for web server deployment **Deployment Model**: + - **Static Files**: Compiled to static HTML, CSS, JavaScript - **Processor Hosting**: Files served by processor's web server - **No Server Requirements**: Pure client-side application @@ -306,12 +335,14 @@ src/ ### Essentials Framework Integration **Framework APIs Used**: + - **Device Manager**: For device information and control - **Configuration System**: For configuration access and management - **Logging Framework**: For debug message access - **System Control**: For restart and reload operations **Framework Dependencies**: + - **Version Compatibility**: Requires specific Essentials framework versions - **API Stability**: Depends on framework API consistency - **Feature Availability**: Some features require specific framework capabilities @@ -319,16 +350,19 @@ src/ ### Future Integration Possibilities **Enhanced Device Control**: + - Direct device method execution from web interface - Real-time device property monitoring - Device configuration modification capabilities **Extended System Management**: + - Configuration file editing and validation - System performance monitoring and analytics - Remote system updates and maintenance **Multi-System Support**: + - Management of multiple processors from single interface - System comparison and synchronization capabilities - Centralized monitoring for multiple installations @@ -338,11 +372,13 @@ src/ ### User-Centered Design **Progressive Disclosure**: + - Start with simple, common operations - Provide access to advanced features when needed - Maintain clear information hierarchy **Real-Time Feedback**: + - Immediate visual feedback for all actions - Real-time data updates where possible - Clear indication of system state and changes @@ -350,16 +386,19 @@ src/ ### Technical Excellence **Maintainability**: + - Clear separation of concerns - Consistent coding patterns and standards - Comprehensive type safety with TypeScript **Reliability**: + - Graceful handling of network issues - Robust error handling and recovery - Consistent behavior across different environments **Performance**: + - Efficient rendering and state management - Minimal impact on processor resources - Responsive interface under various load conditions diff --git a/docs/explanation/configuration-management.md b/docs/explanation/configuration-management.md index 312e278..3bd269a 100644 --- a/docs/explanation/configuration-management.md +++ b/docs/explanation/configuration-management.md @@ -13,6 +13,7 @@ The file system serves as the authoritative configuration source. The web app pr **Layered Configuration Model**: Configuration follows a layered approach where multiple files can contribute to the final system configuration. This allows for: + - Base system defaults - Template configurations for common setups - Site-specific customizations @@ -37,6 +38,7 @@ Rather than requiring a single monolithic configuration file, the system merges **Hot Reload Capability**: The system supports configuration refresh without full restart: + - Configuration files are re-read from disk - New configuration is merged and validated - Existing devices are updated where possible @@ -45,6 +47,7 @@ The system supports configuration refresh without full restart: **State Preservation**: During configuration reload, the system attempts to preserve: + - Device communication states - User interface states - Active connections and sessions @@ -68,6 +71,7 @@ System Configuration **Devices as Building Blocks**: Devices represent individual controllable entities in the system. Each device has: + - Unique identity (key) - Type definition (determines capabilities) - Properties (device-specific configuration) @@ -75,6 +79,7 @@ Devices represent individual controllable entities in the system. Each device ha **Rooms as Orchestrators**: Rooms define logical collections of devices and their relationships: + - Device membership (which devices belong to the room) - User interface bindings (how users interact with devices) - Default behaviors (power-on sequences, preferred sources) @@ -82,6 +87,7 @@ Rooms define logical collections of devices and their relationships: **Tie Lines as Connections**: Tie lines define physical or logical connections between devices: + - Signal routing (audio/video paths) - Control relationships (master/slave configurations) - Communication paths (device-to-device messaging) @@ -92,6 +98,7 @@ Tie lines define physical or logical connections between devices: **Deep Object Merging**: When merging configuration objects, the system performs deep merging: + - Nested objects are merged recursively - Arrays are replaced entirely (not merged) - Primitive values are overwritten @@ -99,6 +106,7 @@ When merging configuration objects, the system performs deep merging: **Precedence Rules**: Configuration files are processed in order of precedence: + 1. System defaults (lowest priority) 2. Template configurations 3. Base configuration files @@ -109,12 +117,14 @@ Configuration files are processed in order of precedence: **Property Conflicts**: When the same property exists in multiple configuration files: + - Later files override earlier ones - Warning messages are logged for reference - Original values are preserved in merge history **Reference Conflicts**: When object references conflict: + - Duplicate keys generate error messages - System attempts to resolve ambiguity using context - Manual intervention may be required for resolution @@ -124,16 +134,19 @@ When object references conflict: ### Multi-Level Validation **Syntax Validation**: + - JSON structure must be valid - Required properties must be present - Property types must match expectations **Semantic Validation**: + - Device types must be registered and available - Cross-references must point to existing objects - Property values must be within acceptable ranges **Runtime Validation**: + - Device communication settings must be reachable - Hardware capabilities must match configuration expectations - System resources must be sufficient for configuration demands @@ -141,12 +154,14 @@ When object references conflict: ### Validation Feedback **Error Categories**: + - **Fatal Errors**: Prevent system startup, require immediate attention - **Warnings**: Allow system operation but indicate potential issues - **Informational**: Provide guidance for optimization or best practices **Error Reporting**: Validation results are reported through multiple channels: + - Debug console messages during system startup - Configuration viewer warnings and errors - System log files for historical reference @@ -157,12 +172,14 @@ Validation results are reported through multiple channels: **Read-Only Architecture**: The web interface provides read-only access to configuration: + - Prevents accidental configuration changes through web interface - Ensures configuration changes go through proper change control - Maintains clear separation between monitoring and administration **File System Security**: Configuration security relies on file system permissions: + - Configuration files should have appropriate read/write permissions - Directory access should be restricted to authorized users - Backup and restore procedures should maintain security @@ -171,12 +188,14 @@ Configuration security relies on file system permissions: **Sensitive Information Handling**: Configuration may contain sensitive information: + - Passwords and credentials for device communication - Network addresses and security settings - Proprietary device configuration parameters **Display Filtering**: The web interface filters sensitive information: + - Passwords are masked or omitted from display - Security-sensitive properties may be hidden - Network topology information may be sanitized @@ -187,12 +206,14 @@ The web interface filters sensitive information: **Lazy Loading**: Configuration objects are loaded and processed on-demand: + - Large configurations don't impact startup time unnecessarily - Memory usage scales with active system components - Network requests are optimized for actual usage patterns **Caching Strategy**: Processed configuration is cached for performance: + - Parsed configuration objects are reused across requests - Expensive validation operations are cached - Change detection minimizes unnecessary processing @@ -201,12 +222,14 @@ Processed configuration is cached for performance: **Modular Configuration**: Large systems benefit from modular configuration: + - Room-specific configuration files - Device-type-specific templates - Feature-specific configuration modules **Configuration Partitioning**: Very large systems can partition configuration: + - Geographic partitioning (building, floor, room) - Functional partitioning (audio, video, control) - Administrative partitioning (different responsible parties) @@ -217,12 +240,14 @@ Very large systems can partition configuration: **Configuration Schema Versioning**: Configuration schemas evolve over time: + - Backward compatibility is maintained where possible - Migration tools help upgrade older configurations - Version-specific validation provides appropriate feedback **Change Management**: Configuration changes follow managed processes: + - Version control integration for configuration files - Rollback capabilities for problematic changes - Change approval workflows for production systems @@ -231,12 +256,14 @@ Configuration changes follow managed processes: **Schema Migration**: When configuration schemas change: + - Automatic migration for simple changes - Manual intervention for complex transformations - Validation and testing of migrated configurations **Data Migration**: When moving between system versions: + - Export/import tools for configuration transfer - Compatibility checking between versions - Validation of migrated system behavior @@ -247,12 +274,14 @@ When moving between system versions: **Logical Grouping**: Organize configuration logically: + - Group related devices together - Separate infrastructure from user-facing configuration - Use consistent naming conventions throughout **Documentation Integration**: Configuration should be self-documenting: + - Use descriptive names for devices and rooms - Include description fields for complex configurations - Maintain separate documentation for configuration rationale @@ -261,12 +290,14 @@ Configuration should be self-documenting: **Regular Review**: Configuration should be reviewed regularly: + - Remove unused devices and rooms - Update outdated property values - Verify that configuration matches physical reality **Change Documentation**: Document configuration changes: + - Maintain change logs for significant modifications - Include rationale for configuration decisions - Track configuration evolution over time @@ -277,11 +308,13 @@ Document configuration changes: **Shared Resources**: Multi-room systems often share expensive resources: + - Central DSP serving multiple rooms - Shared video switching infrastructure - Common source equipment **Configuration Strategy**: + ```json { "devices": { @@ -313,12 +346,14 @@ Multi-room systems often share expensive resources: **Device Templates**: Common device configurations can be templated: + - Standard display configurations - Common DSP setups - Typical room layouts **Template Usage**: Templates are merged with specific configurations: + - Base template provides common properties - Specific configuration overrides as needed - Result is fully merged configuration @@ -328,16 +363,19 @@ Templates are merged with specific configurations: ### Common Configuration Problems **Missing References**: + - Symptoms: Devices or rooms don't appear as expected - Cause: Broken references between configuration objects - Solution: Verify key names match exactly between references **Type Mismatches**: + - Symptoms: Devices don't behave as expected - Cause: Device type doesn't match actual device capabilities - Solution: Verify device type selection and properties **Property Conflicts**: + - Symptoms: Unexpected device behavior or error messages - Cause: Conflicting property values in multiple configuration files - Solution: Review merge precedence and resolve conflicts @@ -346,6 +384,7 @@ Templates are merged with specific configurations: **Use Debug Console**: The debug console provides valuable configuration debugging information: + - Device initialization messages - Configuration validation results - Property merge and override notifications @@ -353,11 +392,13 @@ The debug console provides valuable configuration debugging information: **Configuration Viewer Analysis**: The configuration viewer shows the final merged configuration: + - Compare expected vs. actual configuration - Identify merged property values - Trace configuration source for each property **Systematic Approach**: + 1. Verify basic JSON syntax in all configuration files 2. Check that all referenced objects exist 3. Validate device types and required properties @@ -366,4 +407,4 @@ The configuration viewer shows the final merged configuration: --- -*Understanding how configuration management works helps you make informed decisions about system design, troubleshoot configuration issues effectively, and optimize system performance through proper configuration practices.* +_Understanding how configuration management works helps you make informed decisions about system design, troubleshoot configuration issues effectively, and optimize system performance through proper configuration practices._ diff --git a/docs/explanation/debug-console-design.md b/docs/explanation/debug-console-design.md index 1dad5a3..8e9e215 100644 --- a/docs/explanation/debug-console-design.md +++ b/docs/explanation/debug-console-design.md @@ -10,6 +10,7 @@ The Debug Console represents a sophisticated approach to real-time system monito **The Core Problem**: Traditional system debugging requires either: + - Physical access to the control processor - Remote desktop connections to view local debugging tools - Static log file analysis after problems occur @@ -35,6 +36,7 @@ Complete Message Information ``` **Why This Approach**: + - **Prevents Overwhelm**: Users aren't confronted with all details immediately - **Supports Different Use Cases**: From high-level monitoring to detailed debugging - **Maintains Context**: Users can broaden or narrow focus as needed @@ -48,12 +50,14 @@ Complete Message Information **Alternative Considered**: HTTP polling every few seconds **Why WebSocket**: + - **True Real-Time**: Messages appear immediately when generated - **Efficient**: No repeated HTTP request overhead - **Scalable**: Server can handle multiple concurrent streams - **Responsive**: Instant feedback for system events **Trade-offs Accepted**: + - **Complexity**: WebSocket connections require more sophisticated handling - **Connection Management**: Need to handle disconnections and reconnections - **Browser Compatibility**: Requires modern browser support @@ -64,6 +68,7 @@ Complete Message Information **Alternative Considered**: Server-side filtering to reduce data transmission **Why Client-Side**: + - **Responsive Filtering**: Filter changes apply instantly to existing messages - **Rich Interaction**: Complex filter combinations (including per-device levels) without server round-trips - **Historical Analysis**: Can re-filter previously received messages @@ -71,6 +76,7 @@ Complete Message Information - **Persistent Across Navigation**: Filter state stored in Redux survives route changes within the same session **Trade-offs Accepted**: + - **Bandwidth Usage**: All messages transmitted even if filtered out - **Browser Performance**: High message volumes can impact browser performance - **Memory Usage**: Messages accumulate in browser memory @@ -92,6 +98,7 @@ Messages use structured logging with both human-readable text and machine-readab ``` **Why This Design**: + - **Human-Friendly**: Rendered message is immediately understandable - **Machine-Parseable**: Properties allow sophisticated filtering and analysis - **Consistent**: Template ensures similar events have similar structure @@ -103,6 +110,7 @@ Messages use structured logging with both human-readable text and machine-readab **Multiple Filter Types**: The console provides two distinct filtering mechanisms: + 1. **Device Selection with Per-Device Minimum Level**: Which devices to show, and what minimum severity to require per device 2. **Text Search**: What specific content are you looking for? @@ -110,11 +118,13 @@ The console provides two distinct filtering mechanisms: Each device in the filter list can have its own minimum log level threshold, independent of the server-side global minimum. When a device is checked in the Devices dropdown, it defaults to `Information`. A nested level dropdown next to each checked device allows selecting a higher threshold (e.g. `Warning` or `Error`) to reduce noise from that specific device while keeping other devices at a lower threshold. **Why Per-Device Rather Than Global-Only**: + - **Precision**: A busy device generating many `Information` messages can be silenced at `Warning` while other devices remain visible at `Information` - **Context Preservation**: Keeps the context of multiple devices without overwhelming the view with one device's verbose output - **Flexible Workflow**: Useful when one device is suspected of issues and you want high verbosity from it, but low noise from everything else **Why AND Logic**: + - **Intuitive**: Matches mental model of "show me messages that are X AND Y AND Z" - **Progressively Restrictive**: Each filter narrows results further - **Predictable**: Users can understand what will happen when they add filters @@ -125,17 +135,20 @@ Each device in the filter list can have its own minimum log level threshold, ind Messages display in a table format with fixed columns **Why Tables**: + - **Scannable**: Easy to scan timestamps, devices, and levels quickly - **Sortable**: Natural place for sorting functionality (future enhancement) - **Familiar**: Users understand table interfaces immediately - **Efficient**: Dense information display without clutter **Column Priority Design**: + ``` Timestamp (6) | Device (3) | Level (2) | Message (13) ``` **Why This Allocation**: + - **Timestamp**: Wide enough for full timestamp but not dominant - **Device**: Narrow because device keys are typically short - **Level**: Very narrow because levels are single words @@ -146,12 +159,14 @@ Timestamp (6) | Device (3) | Level (2) | Message (13) **Decision**: Use slide-out drawer instead of modal dialog or inline expansion **Why Drawer**: + - **Context Preservation**: Can see main message list while viewing details - **Non-Modal**: Doesn't interrupt workflow or require dismissal - **Large Display Area**: More space for detailed information than inline - **Consistent Pattern**: Familiar from mobile and desktop applications **Information Hierarchy in Details**: + 1. **Timestamp**: Precise timing information 2. **Rendered Message**: Complete human-readable text 3. **Message Template**: Shows structure for analysis @@ -167,16 +182,19 @@ Busy systems can generate hundreds of messages per minute, potentially overwhelm **Multi-Layer Approach**: **Server-Side Rate Control**: + - Minimum log level setting reduces message volume at source - Message buffering prevents burst impacts - Connection management limits concurrent sessions **Client-Side Optimization**: + - Efficient React rendering for high-frequency updates - Debounced filter updates prevent excessive re-rendering - Message accumulation management (manual session reset) **User Control Mechanisms**: + - Stop/start debug sessions to control data flow - Clear filters to reset and start fresh - Log level adjustment to focus on relevant messages @@ -184,16 +202,19 @@ Busy systems can generate hundreds of messages per minute, potentially overwhelm ### Browser Performance Strategy **DOM Management**: + - Fixed table headers to avoid layout recalculation - Efficient list rendering with consistent row heights - Minimal DOM manipulation for new messages **Memory Management**: + - Messages accumulate during session (intentional for historical analysis) - Page refresh clears accumulated messages - No automatic message trimming (user controls session length) **UI Responsiveness**: + - Debounced search input (1-second delay) - Immediate visual feedback for filter changes - Non-blocking operations for message processing @@ -204,12 +225,14 @@ Busy systems can generate hundreds of messages per minute, potentially overwhelm **Information Exposure**: Debug messages can contain sensitive operational information: + - Device IP addresses and network configuration - User interaction patterns and timing - System performance and reliability information - Error conditions that might reveal vulnerabilities **Design Response**: + - **No Persistent Storage**: Messages not stored long-term - **Session-Based**: Data only exists during active debug sessions - **Network-Only**: Relies on network security for protection @@ -218,11 +241,13 @@ Debug messages can contain sensitive operational information: ### Access Control Integration **Processor-Based Security**: + - Leverages existing processor authentication - No independent user management - Relies on network-level access control **Why This Approach**: + - **Consistency**: Same security model as other processor interfaces - **Simplicity**: No additional authentication system to maintain - **Integration**: Works with existing IT security policies @@ -234,6 +259,7 @@ Debug messages can contain sensitive operational information: **Primary User Workflows Optimized**: **Problem Identification**: + ``` 1. Start debug session 2. Set filters to Error + Warning levels @@ -242,6 +268,7 @@ Debug messages can contain sensitive operational information: ``` **Device Troubleshooting**: + ``` 1. Filter to specific problematic device 2. Monitor device-specific messages @@ -250,6 +277,7 @@ Debug messages can contain sensitive operational information: ``` **System Health Monitoring**: + ``` 1. Keep session running with minimal filters 2. Watch for unusual patterns or error rates @@ -260,12 +288,14 @@ Debug messages can contain sensitive operational information: ### Information Seeking Support **Different User Mental Models**: + - **Time-Based**: "What happened at 10:30 AM?" - **Device-Based**: "What's wrong with the conference room display?" - **Event-Based**: "Show me all power-related events" - **Problem-Based**: "What errors are occurring?" **Design Support**: + - **Timestamp Display**: Supports time-based investigation - **Device Filtering**: Supports device-focused troubleshooting - **Text Search**: Supports event and keyword-based searching @@ -277,6 +307,7 @@ Debug messages can contain sensitive operational information: **High Message Volume Systems**: Current design assumes manageable message rates (< 200/minute). Future enhancements might include: + - **Virtual Scrolling**: Handle thousands of messages efficiently - **Server-Side Filtering**: Reduce bandwidth for high-volume systems - **Message Sampling**: Statistical sampling for very high-rate systems @@ -285,6 +316,7 @@ Current design assumes manageable message rates (< 200/minute). Future enhanceme ### Enhanced Analysis Capabilities **Pattern Recognition**: + - **Message Correlation**: Link related messages across devices - **Timeline Visualization**: Graphical representation of events over time - **Statistical Analysis**: Message rate trends and anomaly detection @@ -293,6 +325,7 @@ Current design assumes manageable message rates (< 200/minute). Future enhanceme ### Multi-System Support **Distributed System Monitoring**: + - **Multiple Processor Support**: Monitor several systems simultaneously - **System Comparison**: Compare behavior across similar systems - **Centralized Dashboard**: High-level view of multiple installations @@ -302,11 +335,13 @@ Current design assumes manageable message rates (< 200/minute). Future enhanceme ### Usability Indicators **Efficient Problem Resolution**: + - Time from problem report to root cause identification - Reduction in site visits for troubleshooting - User ability to resolve issues without expert assistance **Learning Curve**: + - Time for new users to become proficient - Frequency of user errors or confusion - User retention and continued usage @@ -314,11 +349,13 @@ Current design assumes manageable message rates (< 200/minute). Future enhanceme ### Technical Performance **System Impact**: + - Processor resource usage during debug sessions - Network bandwidth consumption - Browser performance under various message loads **Reliability**: + - WebSocket connection stability - Graceful handling of network issues - Data consistency and accuracy diff --git a/docs/explanation/security.md b/docs/explanation/security.md index 0b4575a..b92fe1a 100644 --- a/docs/explanation/security.md +++ b/docs/explanation/security.md @@ -11,18 +11,21 @@ This document explains the security architecture, threat model, and design decis The web config app implements defense-in-depth through multiple security layers: **Network Layer Security**: + - HTTPS encryption for all web traffic - Internal network isolation - Firewall-based access control - Certificate-based authentication **Application Layer Security**: + - Read-only access model - Session-based authentication - Input validation and sanitization - Cross-site scripting (XSS) protection **Data Layer Security**: + - Sensitive information filtering - Access logging and auditing - Configuration data protection @@ -32,6 +35,7 @@ The web config app implements defense-in-depth through multiple security layers: **Principle of Least Privilege**: The web app operates with minimal necessary permissions: + - Read-only access to configuration data - No ability to modify system configuration through web interface - Limited system command execution capabilities @@ -39,6 +43,7 @@ The web app operates with minimal necessary permissions: **Fail-Safe Defaults**: Security defaults assume restrictive access: + - Default configuration denies rather than permits - Unknown users receive minimal access - Error conditions default to secure states @@ -49,18 +54,21 @@ Security defaults assume restrictive access: ### Identified Threat Vectors **Network-Based Attacks**: + - **Man-in-the-middle attacks**: Mitigated by HTTPS encryption - **Network eavesdropping**: Protected by certificate-based encryption - **Denial of service**: Limited by read-only nature and resource constraints - **Network scanning**: Reduced attack surface through minimal exposed services **Web Application Attacks**: + - **Cross-site scripting (XSS)**: Prevented by input sanitization and output encoding - **Cross-site request forgery (CSRF)**: Protected by same-origin policy - **Injection attacks**: Mitigated by parameterized queries and input validation - **Session hijacking**: Protected by secure session management **Physical Access Attacks**: + - **Console access**: Requires physical processor access - **Network port access**: Requires physical network access - **Storage access**: Configuration files protected by file system permissions @@ -70,18 +78,21 @@ Security defaults assume restrictive access: **High Risk - Network Exposure**: The web interface exposes system information over the network: + - **Impact**: Potential information disclosure about system configuration - **Mitigation**: HTTPS encryption, internal network isolation, access controls - **Residual Risk**: Low with proper network security implementation **Medium Risk - Information Disclosure**: Configuration data may contain sensitive information: + - **Impact**: Exposure of device credentials, network topology, system details - **Mitigation**: Sensitive data filtering, read-only access, audit logging - **Residual Risk**: Low to medium depending on configuration content **Low Risk - Denial of Service**: Web interface could be overwhelmed by requests: + - **Impact**: Temporary unavailability of web interface - **Mitigation**: Resource limits, connection throttling, graceful degradation - **Residual Risk**: Very low, system continues operating without web interface @@ -102,6 +113,7 @@ The web app implements a credential-based login flow that gates access to all ap **Session Management**: Web sessions are managed through the Redux store: + - Session exists for the lifetime of the browser tab - Logging out (or reloading) resets all auth state - No session tokens are stored client-side beyond the duration of the session @@ -112,18 +124,22 @@ Web sessions are managed through the Redux store: **Configuration Data Sensitivity**: Configuration files may contain various levels of sensitive information: + - **Highly Sensitive**: Device passwords, encryption keys, security tokens - **Moderately Sensitive**: Network addresses, user names, system topology - **Low Sensitivity**: Device names, room assignments, basic settings **Data Filtering Strategy**: The web interface implements multi-level filtering: + ```javascript // Example of sensitive data filtering const filterSensitiveProperties = (config) => { const sensitiveKeys = ['password', 'key', 'token', 'credential']; return Object.keys(config).reduce((filtered, key) => { - if (sensitiveKeys.some(sensitive => key.toLowerCase().includes(sensitive))) { + if ( + sensitiveKeys.some((sensitive) => key.toLowerCase().includes(sensitive)) + ) { filtered[key] = '[REDACTED]'; } else if (typeof config[key] === 'object') { filtered[key] = filterSensitiveProperties(config[key]); @@ -139,6 +155,7 @@ const filterSensitiveProperties = (config) => { **Encryption in Transit**: All data transmission is encrypted: + - **HTTPS/TLS**: Encrypts all web traffic between browser and processor - **WebSocket Secure (WSS)**: Encrypts real-time debug message streams - **Certificate Validation**: Ensures connection authenticity @@ -146,6 +163,7 @@ All data transmission is encrypted: **Message Integrity**: Data integrity is maintained through: + - TLS message authentication codes (MAC) - Application-level checksums for critical data - Real-time validation of received data @@ -157,6 +175,7 @@ Data integrity is maintained through: **Network Trust Model**: The system assumes deployment on trusted internal networks: + - **Physical Security**: Network infrastructure is physically secured - **Network Segmentation**: System networks are isolated from public internet - **Access Controls**: Network access is controlled through VLANs, firewalls @@ -164,6 +183,7 @@ The system assumes deployment on trusted internal networks: **Certificate Management in Internal Networks**: Internal deployments often use self-signed certificates: + - **Trust Establishment**: Users must explicitly accept certificates - **Certificate Rotation**: Manual certificate updates required - **Trust Validation**: Certificate fingerprint verification recommended @@ -172,6 +192,7 @@ Internal deployments often use self-signed certificates: ### Firewall and Network Controls **Recommended Firewall Rules**: + ``` # Allow HTTPS access from management network ALLOW tcp/443 from MGMT_NETWORK to PROCESSOR_IP @@ -184,6 +205,7 @@ DENY ALL from ANY to PROCESSOR_IP ``` **Network Segmentation Best Practices**: + - Isolate control systems from corporate networks - Use VLANs to separate management and operational traffic - Implement network access control (NAC) for device authentication @@ -195,6 +217,7 @@ DENY ALL from ANY to PROCESSOR_IP **Client-Side Validation**: User inputs are validated in the browser: + - Form validation prevents submission of invalid data - Input type constraints limit acceptable values - Length limits prevent buffer overflow attempts @@ -202,6 +225,7 @@ User inputs are validated in the browser: **Server-Side Validation**: All inputs are re-validated on the server: + - Never trust client-side validation alone - Parameterized queries prevent SQL injection - Input sanitization removes potentially harmful content @@ -210,17 +234,19 @@ All inputs are re-validated on the server: ### Cross-Site Scripting (XSS) Protection **Content Security Policy (CSP)**: + ```http -Content-Security-Policy: - default-src 'self'; - script-src 'self' 'unsafe-inline'; - style-src 'self' 'unsafe-inline'; - img-src 'self' data:; +Content-Security-Policy: + default-src 'self'; + script-src 'self' 'unsafe-inline'; + style-src 'self' 'unsafe-inline'; + img-src 'self' data:; connect-src 'self' wss:; ``` **Output Encoding**: All dynamic content is properly encoded: + - HTML entity encoding for text content - JavaScript escaping for script contexts - URL encoding for URL parameters @@ -229,6 +255,7 @@ All dynamic content is properly encoded: ### Session Security **Secure Session Configuration**: + ```javascript // Session cookie configuration { @@ -240,6 +267,7 @@ All dynamic content is properly encoded: ``` **Session Lifecycle Management**: + - Automatic session creation on first access - Session regeneration on privilege escalation - Proper session cleanup on logout @@ -250,6 +278,7 @@ All dynamic content is properly encoded: ### Security Event Logging **Logged Security Events**: + - User authentication attempts (success and failure) - Session creation, timeout, and termination - Access to sensitive configuration data @@ -257,6 +286,7 @@ All dynamic content is properly encoded: - Network connection establishment and termination **Log Format and Storage**: + ```json { "timestamp": "2024-01-15T10:30:00Z", @@ -272,12 +302,14 @@ All dynamic content is properly encoded: ### Audit Trail Maintenance **Log Retention Policy**: + - Security logs retained for minimum 90 days - Critical security events retained for 1 year - Log rotation to prevent storage exhaustion - Secure log storage with integrity protection **Monitoring and Alerting**: + - Real-time monitoring of authentication failures - Alerting on suspicious access patterns - Integration with security information and event management (SIEM) systems @@ -288,6 +320,7 @@ All dynamic content is properly encoded: ### Secure Installation Guidelines **Initial Setup Security**: + 1. **Change Default Credentials**: Update all default passwords immediately 2. **Certificate Installation**: Install proper SSL certificates for production 3. **Network Configuration**: Configure firewalls and network access controls @@ -295,6 +328,7 @@ All dynamic content is properly encoded: 5. **Security Testing**: Perform vulnerability assessment before production use **Production Hardening**: + - Disable unnecessary services and protocols - Apply security patches and updates regularly - Configure secure logging and monitoring @@ -304,6 +338,7 @@ All dynamic content is properly encoded: ### Ongoing Security Maintenance **Regular Security Tasks**: + - **Certificate Renewal**: Monitor and renew SSL certificates before expiration - **Access Review**: Regularly review user accounts and permissions - **Log Analysis**: Review security logs for suspicious activities @@ -311,6 +346,7 @@ All dynamic content is properly encoded: - **Incident Response**: Maintain procedures for security incident response **Security Update Management**: + - Monitor security advisories for PepperDash Essentials - Test security updates in development environment - Plan and execute security updates during maintenance windows @@ -321,12 +357,14 @@ All dynamic content is properly encoded: ### Regulatory Compliance **Industry Standards**: + - **NIST Cybersecurity Framework**: Align security practices with NIST guidelines - **ISO 27001**: Information security management system standards - **SOC 2**: Security controls for service organizations - **GDPR**: Data protection requirements (if applicable) **Compliance Documentation**: + - Security policy documentation - Risk assessment and mitigation documentation - Audit trail and logging documentation @@ -335,12 +373,14 @@ All dynamic content is properly encoded: ### Privacy Protection **Data Minimization**: + - Collect only necessary system information - Avoid logging personally identifiable information - Implement data retention policies - Provide data deletion capabilities where required **Consent and Transparency**: + - Clear documentation of data collection practices - User consent for optional data collection - Transparency about security measures and limitations @@ -351,11 +391,13 @@ All dynamic content is properly encoded: ### Known Limitations **Read-Only Security Model**: + - Prevents web-based configuration changes (positive security feature) - Does not protect against attacks through other system interfaces - Relies on processor-level security for comprehensive protection **Internal Network Dependency**: + - Security model assumes trusted internal network deployment - May not be suitable for internet-facing deployments without additional security measures - Self-signed certificates require manual trust establishment @@ -363,12 +405,14 @@ All dynamic content is properly encoded: ### Security Assumptions **Environmental Assumptions**: + - Physical security of processor and network infrastructure - Trusted internal network with appropriate access controls - Competent system administration and security management - Regular security updates and maintenance **Operational Assumptions**: + - Users receive appropriate security training - Security policies and procedures are followed - Incident response capabilities are available @@ -379,12 +423,14 @@ All dynamic content is properly encoded: ### Emerging Threats **Evolving Threat Landscape**: + - Internet of Things (IoT) security challenges - Advanced persistent threats (APT) - Supply chain security concerns - Zero-day vulnerability exploitation **Adaptation Strategies**: + - Continuous security monitoring and improvement - Integration with threat intelligence feeds - Automated security testing and validation @@ -393,6 +439,7 @@ All dynamic content is properly encoded: ### Security Enhancement Roadmap **Planned Security Improvements**: + - Enhanced multi-factor authentication options - Improved certificate management automation - Advanced threat detection and response @@ -400,4 +447,4 @@ All dynamic content is properly encoded: --- -*Understanding the security model helps you deploy and operate the web config app safely in your environment. Security is a shared responsibility between the application developers, system administrators, and end users.* +_Understanding the security model helps you deploy and operate the web config app safely in your environment. Security is a shared responsibility between the application developers, system administrators, and end users._ diff --git a/docs/how-to/README.md b/docs/how-to/README.md index 27e8e72..38cfdb0 100644 --- a/docs/how-to/README.md +++ b/docs/how-to/README.md @@ -7,15 +7,18 @@ These guides provide step-by-step solutions to specific problems you might encou ## 🔧 Connection and Access Issues ### [Troubleshooting Connection Issues](./troubleshoot-connection.md) + **Problem**: Can't access the web application or it's not loading properly **Common symptoms:** + - Browser can't reach the application URL -- Page won't load or shows errors +- Page won't load or shows errors - Security certificate warnings - Application loads but doesn't function **You'll learn to fix:** + - Network connectivity problems - Browser security settings - URL formatting issues @@ -26,15 +29,18 @@ These guides provide step-by-step solutions to specific problems you might encou ## 🔍 Debug Console Problems ### [Filter and Search Debug Messages](./filter-debug-messages.md) + **Problem**: Too many debug messages to find what you need **Common symptoms:** + - Debug console overwhelmed with messages - Can't find specific device information - Need to focus on particular types of events - Looking for specific errors or patterns **You'll learn to:** + - Use advanced filtering techniques effectively - Combine multiple search criteria - Find specific message types quickly @@ -45,15 +51,18 @@ These guides provide step-by-step solutions to specific problems you might encou ## 📄 Configuration Management ### [Export and Analyze Configuration](./export-configuration.md) + **Problem**: Need to examine, backup, or analyze system configuration **Common symptoms:** + - Need to document current system setup - Want to compare configurations between systems - Need to backup configuration before changes - Troubleshooting requires configuration analysis **You'll learn to:** + - Export complete configuration data - Analyze configuration structure and content - Compare configurations between systems @@ -64,15 +73,18 @@ These guides provide step-by-step solutions to specific problems you might encou ## 🔀 Routing ### [Trace Signal Routes and Read the Routing Diagram](./trace-signal-routes.md) + **Problem**: Need to find what's feeding a display, verify a route change, or make sense of a busy routing diagram **Common symptoms:** + - Wrong source appears on a display or output - Need to confirm a route or multiview layout change took effect - Routing diagram has too many devices/tie lines to read easily - Live feedback badge shows "Offline" or a certificate warning appears **You'll learn to:** + - Filter the diagram by signal type and device - Trace a signal path by clicking an edge, device, or multiview tile - Read and reposition multiview layout panels @@ -83,30 +95,36 @@ These guides provide step-by-step solutions to specific problems you might encou ## ⚡ Performance and Monitoring ### [Monitor System Performance](./monitor-performance.md) + **Problem**: Need to monitor system health and identify performance issues **Common symptoms:** + - System seems slow or unresponsive - Want to establish performance baselines - Need to identify problematic devices - Monitoring for proactive maintenance **You'll learn to:** + - Establish performance baselines - Identify performance problems early - Monitor device health systematically - Create performance reports and documentation ### [Restart and Reload Configuration](./restart-reload-config.md) + **Problem**: Need to restart the system or reload configuration changes **Common symptoms:** + - Made configuration changes that require restart - System is unresponsive and needs restart - Need to reload configuration without full restart - Troubleshooting requires clean system state **You'll learn to:** + - Choose appropriate restart methods - Safely restart without losing data - Reload configuration changes efficiently @@ -117,18 +135,23 @@ These guides provide step-by-step solutions to specific problems you might encou ## 📚 Guide Categories ### Connection and Access (Getting Connected) + Essential for basic application access and resolving connectivity problems -### Debug Console (Information Gathering) +### Debug Console (Information Gathering) + Core troubleshooting skills for monitoring and analyzing system behavior ### Configuration Management (System Understanding) + Tools for understanding, documenting, and managing system configuration ### Routing (Signal Visibility) + Filtering, tracing, and troubleshooting the live signal routing diagram ### Performance and Monitoring (System Health) + Proactive monitoring and maintenance techniques for system reliability --- @@ -136,18 +159,21 @@ Proactive monitoring and maintenance techniques for system reliability ## 🎯 How to Use These Guides ### Quick Problem Solving + 1. **Identify your symptom** from the descriptions above 2. **Jump directly to the relevant guide** 3. **Follow the step-by-step instructions** 4. **Apply the solution to your specific situation** ### Systematic Troubleshooting + 1. **Start with connection issues** if you can't access the app 2. **Use filtering guides** to focus on relevant information 3. **Apply performance monitoring** to understand system state 4. **Use configuration analysis** for deep troubleshooting ### Preventive Maintenance + 1. **Monitor performance regularly** using monitoring guides 2. **Export configurations periodically** for backup and documentation 3. **Use restart procedures** for planned maintenance @@ -172,12 +198,15 @@ Proactive monitoring and maintenance techniques for system reliability ## 🔗 Related Resources ### For Learning the Basics + Start with **[Tutorials](../tutorials/)** if you're new to the application -### For Technical Details +### For Technical Details + Check **[Reference](../reference/)** documentation for complete technical information ### For Understanding Concepts + Read **[Explanation](../explanation/)** articles for background and design rationale --- @@ -192,6 +221,7 @@ Read **[Explanation](../explanation/)** articles for background and design ratio 4. **Check explanation articles**: Understanding the underlying concepts might help **When to seek additional help:** + - Multiple guides haven't resolved the issue - You encounter error messages not covered in the guides - The problem seems to be with system hardware or network infrastructure @@ -209,4 +239,4 @@ These guides are designed to address the most common problems users encounter. T --- -*Remember: These guides assume you have basic familiarity with the application. If you're completely new, start with the [Getting Started Tutorial](../tutorials/getting-started.md) first.* +_Remember: These guides assume you have basic familiarity with the application. If you're completely new, start with the [Getting Started Tutorial](../tutorials/getting-started.md) first._ diff --git a/docs/how-to/export-configuration.md b/docs/how-to/export-configuration.md index 5df9c33..9061f9b 100644 --- a/docs/how-to/export-configuration.md +++ b/docs/how-to/export-configuration.md @@ -7,6 +7,7 @@ ## Quick Export **For immediate configuration access:** + 1. Navigate to **Config File** in the top menu 2. Wait for the configuration to load (shows "Loading..." initially) 3. Use browser's copy/paste to capture the displayed JSON @@ -21,6 +22,7 @@ 3. **Verify completeness** - Scroll to ensure the entire configuration loaded **What you'll see:** + - JSON-formatted configuration data - Hierarchical structure with devices, settings, and properties - Properly formatted and indented for readability @@ -28,12 +30,14 @@ ### 2. Copy Configuration Data **Method 1: Select All and Copy** + 1. Click in the configuration display area 2. Use `Ctrl+A` (Windows/Linux) or `Cmd+A` (Mac) to select all 3. Use `Ctrl+C` (Windows/Linux) or `Cmd+C` (Mac) to copy 4. Paste into your preferred text editor **Method 2: Browser Save Function** + 1. Right-click in the configuration area 2. Select "Save As" or "Save Page As" 3. Choose location and filename @@ -42,6 +46,7 @@ ### 3. Save and Organize **Recommended file naming:** + ``` [SystemName]_config_[YYYY-MM-DD].json Examples: @@ -51,6 +56,7 @@ Examples: ``` **Storage recommendations:** + - Create a dedicated folder for configuration backups - Include date and system identification in filenames - Store in version control system if available @@ -61,10 +67,11 @@ Examples: ### 4. Understanding Configuration Structure **Top-level sections** (common elements): + ```json { "devices": { ... }, // All configured devices - "routing": { ... }, // Signal routing configuration + "routing": { ... }, // Signal routing configuration "rooms": { ... }, // Room/space definitions "controlSystem": { ... }, // Control processor settings "applicationSettings": { ... } // Application-specific settings @@ -72,6 +79,7 @@ Examples: ``` **Device structure example:** + ```json "Display-Room1": { "key": "Display-Room1", @@ -91,21 +99,25 @@ Examples: ### 5. Common Analysis Tasks **Find all devices of a specific type:** + 1. Search for `"type": "samsungMDC"` (or other device type) 2. Note the device keys and names 3. Document IP addresses and settings **Identify network settings:** + 1. Search for `"address":` to find all IP addresses 2. Look for `"port":` to find communication ports 3. Check for `"username"` and authentication settings **Locate routing configuration:** + 1. Find the `"routing"` section 2. Examine input/output mappings 3. Check for audio/video route definitions **Review room definitions:** + 1. Look for `"rooms"` or similar sections 2. Check device assignments to rooms 3. Verify user interface configurations @@ -115,11 +127,13 @@ Examples: ### 6. Using External Tools **JSON viewers and editors:** + - **Online**: JSONLint, JSONFormatter, JSON Editor Online - **Desktop**: Visual Studio Code with JSON extensions - **Command line**: `jq` tool for JSON processing **Example using jq to extract device information:** + ```bash # Extract all device names jq '.devices | keys[]' config.json @@ -134,12 +148,14 @@ jq -r '.. | .address? // empty' config.json ### 7. Configuration Comparison **Compare configurations between systems:** + 1. Export configurations from multiple systems 2. Use diff tools (WinMerge, Beyond Compare, or `diff` command) 3. Identify differences in device settings 4. Document configuration variations **Version comparison workflow:** + 1. Export current configuration 2. Compare with previous backups 3. Identify what changed @@ -148,11 +164,13 @@ jq -r '.. | .address? // empty' config.json ### 8. Documentation Generation **Create device inventory:** + 1. Extract device information from configuration 2. Create spreadsheet with: Key, Name, Type, IP Address, Location 3. Add columns for maintenance notes and status **Network documentation:** + 1. List all IP addresses and ports used 2. Document network requirements 3. Create network diagram based on configuration @@ -162,17 +180,20 @@ jq -r '.. | .address? // empty' config.json ### 9. Configuration-Based Problem Solving **Device not responding:** + 1. Find the device in configuration 2. Verify IP address and port settings 3. Check if device type matches physical device 4. Confirm required properties are configured **Missing functionality:** + 1. Check if feature is configured in the device properties 2. Verify room assignments include necessary devices 3. Look for routing configurations that might be missing **Performance issues:** + 1. Count total number of devices 2. Check for excessive polling intervals 3. Look for redundant or unused device configurations @@ -180,6 +201,7 @@ jq -r '.. | .address? // empty' config.json ### 10. Configuration Validation **Common configuration errors to check:** + - Duplicate device keys - Invalid IP addresses or ports - Missing required properties for device types @@ -187,6 +209,7 @@ jq -r '.. | .address? // empty' config.json - Unused or orphaned device references **Validation checklist:** + - [ ] All devices have unique keys - [ ] IP addresses are valid and reachable - [ ] Device types match physical hardware @@ -199,12 +222,14 @@ jq -r '.. | .address? // empty' config.json ### 11. Configuration Security **Before sharing configuration files:** + - Remove or redact IP addresses if sharing externally - Remove authentication credentials (usernames/passwords) - Be cautious with network topology information - Consider what information reveals about your infrastructure **Sanitized configuration example:** + ```json { "Display-Room1": { @@ -224,12 +249,14 @@ jq -r '.. | .address? // empty' config.json ### 12. Backup and Version Control **Regular backup schedule:** + - Export configurations before making changes - Schedule automatic exports if possible - Store backups in multiple locations - Test restore procedures periodically **Change management:** + 1. Export configuration before changes 2. Document what changes are being made 3. Export configuration after changes @@ -241,6 +268,7 @@ jq -r '.. | .address? // empty' config.json ### 13. Cross-Reference with Device List **Verify configuration completeness:** + 1. Compare devices shown in **Devices** section 2. Cross-reference with configuration file 3. Identify devices configured but not active @@ -249,6 +277,7 @@ jq -r '.. | .address? // empty' config.json ### 14. Use with Debug Console **Configuration-guided troubleshooting:** + 1. Find device configuration details 2. Use device key to filter debug messages 3. Verify actual behavior matches configuration @@ -257,21 +286,25 @@ jq -r '.. | .address? // empty' config.json ## Common Use Cases ### System Documentation + - Create comprehensive system documentation - Generate device inventories and network maps - Document configuration standards and conventions ### Troubleshooting Support + - Provide configuration context to support teams - Compare working vs. non-working system configurations - Identify recent configuration changes ### System Planning + - Analyze current configuration before expansions - Plan IP address allocations and network requirements - Understand system complexity and dependencies ### Compliance and Auditing + - Document system configurations for compliance - Track configuration changes over time - Verify systems match approved standards @@ -279,6 +312,7 @@ jq -r '.. | .address? // empty' config.json ## Quick Reference ### Export Checklist + - [ ] Navigate to Config File section - [ ] Wait for complete loading - [ ] Select and copy all content @@ -287,6 +321,7 @@ jq -r '.. | .address? // empty' config.json - [ ] Store in organized backup location ### Analysis Tools + - **Built-in browser**: Search functionality (Ctrl+F) - **Text editors**: Syntax highlighting for JSON - **Online tools**: JSON formatters and validators @@ -294,6 +329,7 @@ jq -r '.. | .address? // empty' config.json - **Diff tools**: For comparing configurations ### Key Sections to Examine + - `devices`: All device configurations - `routing`: Signal routing settings - `rooms`: Room and space definitions @@ -301,6 +337,7 @@ jq -r '.. | .address? // empty' config.json - Authentication: Usernames and security settings ### Security Reminders + - Remove sensitive information before sharing - Redact IP addresses and credentials - Store backups securely diff --git a/docs/how-to/filter-debug-messages.md b/docs/how-to/filter-debug-messages.md index c4f123e..e4db546 100644 --- a/docs/how-to/filter-debug-messages.md +++ b/docs/how-to/filter-debug-messages.md @@ -7,6 +7,7 @@ ## Quick Filtering **For immediate results:** + 1. **Device filter**: Click "Devices" dropdown → Select specific devices 2. **Per-device level**: Once a device is checked, use its inline level dropdown to set a minimum severity 3. **Search box**: Type keywords related to your issue @@ -22,12 +23,14 @@ The Devices dropdown combines two capabilities: - **Level dropdown per device**: When checked, each device gets an inline level dropdown defaulting to `Information` **To show only warnings and above from a specific device**: + 1. Click the **Devices** dropdown 2. Check the device 3. Click its inline level dropdown and select **Warning** 4. Messages from that device below `Warning` are now hidden Multiple devices can each have different thresholds. For example: + - `Display-Room1` → `Error` (only show errors from this noisy device) - `Codec-Main` → `Information` (show all normal activity) - Global → `Warning` (only warnings from system-level messages) @@ -41,15 +44,17 @@ Type keywords in the search box to find messages whose rendered text, template, ### 1. Search by Keywords **Single keywords** (finds messages containing the word): + ``` error - All error-related messages -connection - Connection events and issues +connection - Connection events and issues power - Power-related events button - Button press events display - Display-related messages ``` **Multiple keywords** (finds messages containing ALL words): + ``` display power - Display power events specifically button press - Button press events only @@ -58,6 +63,7 @@ error device - Device-specific errors ``` **Technical terms** (use exact terminology from error messages): + ``` "connection refused" - Exact phrase matching "device not responding" - Specific error conditions @@ -67,16 +73,19 @@ error device - Device-specific errors ### 2. Filter by Device **Global system messages:** + - Select "Global" to see system-wide events - Includes startup, shutdown, and system status messages - Use for overall system health monitoring **Specific device focus:** + - Select one device to trace its complete activity - Useful for device-specific troubleshooting - Shows all messages from that device only **Multiple device comparison:** + - Select 2-3 related devices - Compare behavior between similar devices - Identify which device is behaving differently @@ -84,16 +93,19 @@ error device - Device-specific errors ### 3. Filter by Log Level **Error and Warning only** (recommended for problem identification): + - Focus on actual problems - Reduces noise from normal operations - Best for quick issue identification **Information level** (recommended for normal monitoring): + - Shows normal operations plus issues - Good balance of detail vs. noise - Default setting for most use cases **Debug and Verbose** (use sparingly): + - Extremely detailed technical information - Only use when specifically debugging code issues - Can overwhelm the interface with messages @@ -103,32 +115,37 @@ error device - Device-specific errors ### 4. Combine Multiple Filters **Example: Find display power errors** + 1. Device filter: Select display devices only 2. Log level: Select "Error" and "Warning" 3. Search: Type "power" 4. Result: Only power-related issues from displays **Example: Trace button press handling** + 1. Device filter: Select "Global" and control panel devices 2. Log level: Select "Information" and above 3. Search: Type "button press" 4. Result: Complete button press event chain **Example: Monitor system startup** + 1. Device filter: Select "Global" -2. Log level: Select "Information" and above +2. Log level: Select "Information" and above 3. Search: Type "startup" or "initializing" 4. Result: System startup sequence ### 5. Time-Based Analysis **Clear and restart** for fresh analysis: + 1. Stop the debug session 2. Clear the browser page (refresh) 3. Start a new debug session 4. Apply filters before activity occurs **Historical analysis** (within current session): + - Scroll up to see earlier messages - Use browser's find function (Ctrl+F) for additional searching - Look for patterns in timestamps @@ -140,6 +157,7 @@ error device - Device-specific errors **Goal**: Find why a specific device isn't working **Filtering approach:** + 1. **Device filter**: Select the problematic device only 2. **Log level**: Start with "Warning" and "Error" 3. **Search terms**: Try these in order: @@ -149,6 +167,7 @@ error device - Device-specific errors - `failed` **What to look for:** + - Connection establishment messages (or lack thereof) - Repeated error patterns - Timeout messages @@ -159,6 +178,7 @@ error device - Device-specific errors **Goal**: Identify what's causing system slowdowns **Filtering approach:** + 1. **Device filter**: Start with "Global" messages 2. **Log level**: "Warning" and "Error" to see problems 3. **Search terms**: @@ -168,6 +188,7 @@ error device - Device-specific errors - `performance` **What to look for:** + - High frequency of messages from one device - Timeout errors from multiple devices - Resource allocation warnings @@ -178,6 +199,7 @@ error device - Device-specific errors **Goal**: Follow what happens when a user presses a button **Filtering approach:** + 1. **Device filter**: Include control panels and target devices 2. **Log level**: "Information" and above 3. **Search terms**: @@ -186,6 +208,7 @@ error device - Device-specific errors - `command` **What to look for:** + - Button press detection - Command routing messages - Device response confirmations @@ -196,6 +219,7 @@ error device - Device-specific errors **Goal**: Diagnose network-related problems **Filtering approach:** + 1. **Device filter**: All network-connected devices 2. **Log level**: "Warning" and "Error" 3. **Search terms**: @@ -205,6 +229,7 @@ error device - Device-specific errors - `unreachable` **What to look for:** + - Connection retry attempts - Network timeout messages - IP address resolution issues @@ -215,26 +240,31 @@ error device - Device-specific errors ### Effective Search Terms **For connection issues:** + ``` connection, connect, disconnect, timeout, unreachable, refused ``` **For device control:** + ``` command, response, control, status, state, property ``` **For errors and problems:** + ``` error, exception, failed, timeout, denied, invalid ``` **For user interactions:** + ``` button, press, touch, input, selection, change ``` **For system events:** + ``` startup, shutdown, restart, initialize, load, ready ``` @@ -242,14 +272,17 @@ startup, shutdown, restart, initialize, load, ready ### Search Patterns **Negation** (use carefully): + - Most browsers support Ctrl+F with exclusion - Better to use positive filters in the application **Partial matching**: + - "conn" matches "connection", "connected", "disconnect" - "disp" matches "display", "displayed", "displaying" **Case insensitivity**: + - "ERROR" and "error" produce same results - "Display" and "display" are equivalent @@ -258,6 +291,7 @@ startup, shutdown, restart, initialize, load, ready ### Efficient Filter Workflows **Start broad, narrow down:** + 1. Begin with no filters (see everything) 2. Add device filter to focus area 3. Add log level filter to reduce noise @@ -265,6 +299,7 @@ startup, shutdown, restart, initialize, load, ready 5. Clear and restart when changing focus **Save mental notes** of effective filter combinations: + - Document filter combinations that work well - Remember search terms that find specific issues - Note which devices typically need monitoring together @@ -272,14 +307,16 @@ startup, shutdown, restart, initialize, load, ready ### Clear Filters Strategically **When to clear filters:** + - Switching between different troubleshooting tasks - When filters are too restrictive (no results) - Starting investigation of a new issue - Periodically to see the "big picture" **What gets cleared:** + - Device selections -- Log level selections +- Log level selections - Search text - Filter state resets to defaults @@ -288,11 +325,13 @@ startup, shutdown, restart, initialize, load, ready ### Managing Message Volume **High message rates** (>50 messages/second): + - Use more restrictive log levels - Filter to fewer devices - Consider if system has problems causing excessive logging **Browser performance:** + - Too many messages can slow browser - Refresh page periodically to clear accumulation - Use filters to reduce processing load @@ -300,6 +339,7 @@ startup, shutdown, restart, initialize, load, ready ### Network Considerations **Debug session impact:** + - Each active session uses network bandwidth - Multiple users can impact processor performance - Stop sessions when not actively debugging @@ -307,6 +347,7 @@ startup, shutdown, restart, initialize, load, ready ## Best Practices Summary ### Do's: + - ✅ Start with broader filters, then narrow down - ✅ Use device filters to focus on specific components - ✅ Combine multiple filtering methods for precise results @@ -314,6 +355,7 @@ startup, shutdown, restart, initialize, load, ready - ✅ Use appropriate log levels for your investigation type ### Don'ts: + - ❌ Leave all filters active when switching tasks - ❌ Use "Verbose" log level unless absolutely necessary - ❌ Search for overly generic terms without other filters @@ -325,26 +367,31 @@ startup, shutdown, restart, initialize, load, ready ### Filter Combinations for Common Tasks **Problem identification:** + - Log Level: Warning + Error - Device: All or problematic area - Search: "error" or "failed" **Device troubleshooting:** + - Device: Specific device only - Log Level: Information and above - Search: Related to suspected issue **System monitoring:** + - Device: Global - Log Level: Warning and above - Search: "system" or "startup" **User interaction tracing:** + - Device: Control panels + target devices - Log Level: Information and above - Search: "button" or "command" ### Quick Actions + - **Reset everything**: Click "Clear" button - **Focus device**: Select one device in dropdown - **Problem focus**: Set log level to "Warning" + "Error" diff --git a/docs/how-to/monitor-performance.md b/docs/how-to/monitor-performance.md index 402bf2e..b1d5c65 100644 --- a/docs/how-to/monitor-performance.md +++ b/docs/how-to/monitor-performance.md @@ -7,6 +7,7 @@ ## Quick Performance Check **For immediate system health assessment:** + 1. Start a debug session in the **Debug Console** 2. Set log level to **"Warning"** and **"Error"** only 3. Monitor for 2-3 minutes to see error frequency @@ -18,16 +19,19 @@ ### 1. Message Rate Analysis **Normal message rates** (varies by system size): + - **Small systems** (5-10 devices): 5-20 messages per minute -- **Medium systems** (10-50 devices): 20-100 messages per minute +- **Medium systems** (10-50 devices): 20-100 messages per minute - **Large systems** (50+ devices): 100+ messages per minute **Performance warning signs:** + - **Very high rates** (>200 messages/minute): May indicate device errors or loops - **Message bursts**: Sudden spikes in message volume - **Continuous error streams**: Same error repeating rapidly **How to check:** + 1. Start debug session and note starting message count 2. Wait exactly 1 minute 3. Note ending message count @@ -37,12 +41,14 @@ ### 2. Error Pattern Recognition **Healthy system indicators:** + - Occasional informational messages - Infrequent warnings (less than 1 per minute) - Very rare errors (less than 1 per 10 minutes) - Clean startup sequences **Performance problem indicators:** + - Repeated timeout errors - Connection retry loops - Resource allocation failures @@ -53,6 +59,7 @@ ### 3. Establish Baseline Performance **Initial baseline creation:** + 1. **Choose monitoring period**: 15-30 minutes during normal operation 2. **Record message statistics**: - Total message count @@ -66,6 +73,7 @@ 4. **Save baseline data** for future comparison **Baseline documentation template:** + ``` System: [System Name] Date: [Date] @@ -81,6 +89,7 @@ User Load: [Description] ### 4. Regular Health Checks **Daily monitoring routine:** + 1. **Quick status check** (2-3 minutes): - Start debug session - Set to "Warning" and "Error" levels @@ -102,6 +111,7 @@ User Load: [Description] ### 5. Device-Specific Performance Monitoring **Individual device health:** + 1. **Filter to single device** in debug console 2. **Monitor for 5-10 minutes** 3. **Look for patterns**: @@ -111,6 +121,7 @@ User Load: [Description] - Retry attempts (concerning) **Device performance checklist:** + - [ ] Device responds to commands consistently - [ ] No timeout errors in normal operation - [ ] Status updates occur regularly @@ -118,6 +129,7 @@ User Load: [Description] - [ ] Connection remains stable **Red flags for individual devices:** + - Multiple timeout errors per minute - Connection retry loops - Commands not acknowledged @@ -172,13 +184,16 @@ User Load: [Description] **Network-related performance issues:** **Symptoms to monitor**: + - Frequent "connection timeout" messages - "Device unreachable" errors - Long delays between commands and responses - Intermittent device connectivity **Network performance checks**: + 1. **Search for network-related terms**: + ``` timeout connection @@ -203,12 +218,14 @@ User Load: [Description] ### 9. Memory and Processing Indicators **Signs of resource constraints:** + - Increasing response times over time - "Out of memory" or resource allocation errors - System becoming unresponsive - Debug sessions failing to start **Monitoring approach**: + 1. **Track response times**: - Note delays between commands and responses - Monitor how long operations take @@ -222,12 +239,14 @@ User Load: [Description] ### 10. Database and Storage Performance **Storage-related performance indicators:** + - Slow configuration loading - Delays in log message display - "Disk full" or storage errors - Database connection issues **Monitoring steps**: + 1. **Time configuration loading**: - Note how long Config File section takes to load - Compare loading times over time @@ -243,6 +262,7 @@ User Load: [Description] ### 11. Reducing Debug Session Impact **Minimize monitoring overhead:** + 1. **Use appropriate log levels**: - "Information" for normal monitoring - "Warning"+"Error" for problem identification @@ -261,6 +281,7 @@ User Load: [Description] ### 12. System Configuration for Performance **Configuration best practices:** + 1. **Device polling intervals**: - Don't poll devices more frequently than necessary - Increase intervals for stable devices @@ -281,6 +302,7 @@ User Load: [Description] ### 13. Performance Documentation **Regular performance reports should include:** + - Message rate trends over time - Error frequency and types - Device response time measurements @@ -288,6 +310,7 @@ User Load: [Description] - System resource utilization **Report template:** + ``` Performance Report - [Date Range] ================================ @@ -314,12 +337,14 @@ Recommendations: ### 14. Alerting and Escalation **When to escalate performance issues:** + - Error rates exceed 50% above baseline - System becomes unresponsive - Critical devices fail repeatedly - Performance degrades significantly over time **Escalation information to provide:** + - Current vs. baseline performance metrics - Specific error messages and frequencies - Affected devices and functionality @@ -329,6 +354,7 @@ Recommendations: ## Quick Reference ### Performance Monitoring Checklist + - [ ] Establish baseline performance metrics - [ ] Monitor message rates regularly - [ ] Track error frequencies and types @@ -340,6 +366,7 @@ Recommendations: ### Normal vs. Concerning Indicators **Normal (Healthy System):** + - Steady, predictable message rates - Infrequent errors (< 1 per 10 minutes) - Consistent device response times @@ -347,6 +374,7 @@ Recommendations: - Stable network connectivity **Concerning (Performance Issues):** + - Message rates >200% of baseline - Frequent errors (> 1 per minute) - Increasing response times @@ -354,6 +382,7 @@ Recommendations: - System unresponsiveness ### Key Search Terms for Performance Monitoring + ``` Performance Issues: timeout, delay, slow, performance Network Issues: connection, unreachable, network, ping @@ -362,6 +391,7 @@ Error Patterns: error, failed, exception, retry ``` ### Quick Performance Assessment (5 minutes) + 1. Start debug session with "Warning" + "Error" filters 2. Monitor for 2-3 minutes 3. Note message count and rate diff --git a/docs/how-to/restart-reload-config.md b/docs/how-to/restart-reload-config.md index 5aa2924..802341a 100644 --- a/docs/how-to/restart-reload-config.md +++ b/docs/how-to/restart-reload-config.md @@ -7,12 +7,14 @@ ## Quick Actions **For immediate restart:** + 1. Go to **Debug Console** 2. Click **"Restart Program"** button 3. Confirm the restart in the modal dialog 4. Wait 2-3 minutes for system to fully restart **For configuration reload only:** + 1. Ensure **"Do Not Load Config on Next Boot"** is unchecked 2. Click **"Load Config"** button (if enabled) 3. Monitor debug messages for configuration loading progress @@ -22,11 +24,13 @@ ### 1. Configuration Loading Control **"Do Not Load Config on Next Boot" Checkbox:** + - **Checked**: System will start without loading configuration file - **Unchecked**: System will load configuration on startup (normal operation) - **Use case**: Useful when configuration file has errors that prevent startup **When to use "Do Not Load Config":** + - Configuration file contains errors preventing startup - Testing system behavior without configuration - Troubleshooting startup issues @@ -39,6 +43,7 @@ **What it does**: Loads and applies the current configuration file **Benefits of "Load Config" vs. full restart:** + - Faster than complete system restart - Preserves current system state where possible - Allows testing configuration changes quickly @@ -47,7 +52,8 @@ ### 3. Restart Program Button **Purpose**: Complete restart of the PepperDash Essentials framework -**What happens**: +**What happens**: + 1. All current operations stop 2. All device connections close 3. System reinitializes completely @@ -55,6 +61,7 @@ 5. All devices reconnect **When to use full restart:** + - Major configuration changes that require complete reload - System becomes unresponsive - Memory leaks or resource issues @@ -99,6 +106,7 @@ - Document current issues before restart 2. **Prepare for restart**: + ``` Before restart checklist: - [ ] Users notified of downtime @@ -144,12 +152,14 @@ ### 7. Managing Configuration Loading **Normal configuration loading:** + 1. System starts with "Do Not Load Config on Next Boot" unchecked 2. Configuration file loads automatically during startup 3. All devices initialize based on configuration 4. System becomes fully operational **Controlled configuration loading:** + 1. Check "Do Not Load Config on Next Boot" 2. Restart system (starts without configuration) 3. System runs in minimal state @@ -157,6 +167,7 @@ 5. Configuration loads without full restart **Use cases for controlled loading:** + - Testing new configurations safely - Troubleshooting configuration-related startup issues - Loading configuration after making changes @@ -192,16 +203,18 @@ ### 9. Normal Startup Sequence **Expected startup messages:** + ``` Information: System initializing Information: Loading configuration file -Information: Device [DeviceName] initializing +Information: Device [DeviceName] initializing Information: Device [DeviceName] connection established Information: Device [DeviceName] ready Information: System startup complete ``` **Startup timing expectations:** + - **System initialization**: 30-60 seconds - **Configuration loading**: 10-30 seconds - **Device connections**: 1-5 minutes (depends on device count) @@ -210,12 +223,14 @@ Information: System startup complete ### 10. Identifying Startup Problems **Warning signs during startup:** + - Devices failing to initialize - Repeated connection timeout errors - Configuration loading errors - System taking longer than usual **Common startup error patterns:** + ``` Error: Failed to load configuration file Warning: Device [Name] connection timeout @@ -224,6 +239,7 @@ Warning: Network unreachable for device [Name] ``` **Troubleshooting startup issues:** + 1. **Configuration errors**: Use "Do Not Load Config" mode 2. **Network issues**: Check device connectivity 3. **Device failures**: Investigate specific device problems @@ -234,6 +250,7 @@ Warning: Network unreachable for device [Name] ### 11. Restart Planning **Before performing restarts:** + - ✅ Notify users of planned downtime - ✅ Complete or pause critical operations - ✅ Document current system state @@ -241,12 +258,14 @@ Warning: Network unreachable for device [Name] - ✅ Plan restart during low-usage periods **During restarts:** + - ✅ Monitor progress through debug console - ✅ Be patient - don't interrupt restart process - ✅ Document any errors that occur - ✅ Don't perform other system operations during restart **After restarts:** + - ✅ Verify all devices reconnected properly - ✅ Test critical functionality - ✅ Monitor system for a few minutes @@ -256,6 +275,7 @@ Warning: Network unreachable for device [Name] ### 12. Configuration Change Workflow **Safe configuration update process:** + 1. **Backup current configuration** 2. **Make configuration changes** (externally) 3. **Test configuration** (validation tools if available) @@ -269,51 +289,60 @@ Warning: Network unreachable for device [Name] ## Troubleshooting Common Issues ### Restart Button Not Responding + **Cause**: System may be completely unresponsive **Solution**: Wait 5 minutes, try browser refresh, contact administrator if needed ### Configuration Won't Load + **Cause**: Syntax errors or invalid configuration **Solution**: Use "Do Not Load Config" mode, fix configuration externally, test reload ### Devices Not Reconnecting After Restart + **Cause**: Network issues, device problems, or configuration errors **Solution**: Check debug messages for specific device errors, verify network connectivity ### System Takes Too Long to Restart + **Cause**: Large number of devices, network delays, or system issues **Solution**: Wait up to 10 minutes for large systems, check for specific error messages ### "Load Config" Button Not Available + **Cause**: "Do Not Load Config on Next Boot" is not checked **Solution**: Check the checkbox first, or use full restart instead ## Quick Reference ### Restart Options Quick Guide + - **Load Config**: Quick configuration reload (when checkbox is checked) - **Restart Program**: Complete system restart - **Do Not Load Config**: Start system without configuration (troubleshooting mode) ### When to Use Each Option -| Situation | Recommended Action | -|-----------|-------------------| -| Minor configuration changes | Load Config | -| Major configuration changes | Restart Program | -| System unresponsive | Restart Program | -| Configuration has errors | Check "Do Not Load Config", then Restart | -| Testing new configuration | Use "Do Not Load Config" mode | -| After software updates | Restart Program | +| Situation | Recommended Action | +| --------------------------- | ---------------------------------------- | +| Minor configuration changes | Load Config | +| Major configuration changes | Restart Program | +| System unresponsive | Restart Program | +| Configuration has errors | Check "Do Not Load Config", then Restart | +| Testing new configuration | Use "Do Not Load Config" mode | +| After software updates | Restart Program | ### Normal Timing Expectations + - **Load Config**: 30 seconds - 2 minutes - **Restart Program**: 2-6 minutes total - **Device reconnection**: 1-5 minutes after restart - **System fully operational**: 3-8 minutes after restart initiated ### Emergency Contacts + If restart procedures don't resolve issues: + 1. Check system documentation for emergency procedures 2. Contact system administrator 3. Contact PepperDash support if needed diff --git a/docs/how-to/trace-signal-routes.md b/docs/how-to/trace-signal-routes.md index f77af92..7ca8d44 100644 --- a/docs/how-to/trace-signal-routes.md +++ b/docs/how-to/trace-signal-routes.md @@ -7,26 +7,28 @@ ## Quick Actions **To find where a signal is coming from:** + 1. Open the **Routing** page for the app 2. Click the tie line edge feeding the device you're investigating (or click the device node itself) 3. The full path highlights from source to destination; everything else dims **To declutter a busy diagram:** + 1. Use the **signal type buttons** in the toolbar to hide types you don't need 2. Open the **Devices** filter dropdown and search for/uncheck devices you don't need 3. Turn on **Hide unconnected devices** and/or **Hide unconnected ports** ## Understanding the Toolbar -| Control | What it does | -|---|---| -| Signal type buttons | Click to show/hide all tie lines of that type. Button color matches its edges. | -| Devices dropdown | Search devices, then check/uncheck individual devices, or use Select all / Deselect all | -| Hide unconnected devices | Removes any device with no visible tie line endpoint from the canvas | -| Hide unconnected ports | Shows only the ports on each device that currently have a visible tie line | -| Dark mode | Switches the canvas between dark and light styling | -| Live / Offline badge | Green "Live" means the routing feedback WebSocket is connected and route data is current | -| Refresh button | Reloads the device/tie-line snapshot and reconnects the feedback WebSocket | +| Control | What it does | +| ------------------------ | ---------------------------------------------------------------------------------------- | +| Signal type buttons | Click to show/hide all tie lines of that type. Button color matches its edges. | +| Devices dropdown | Search devices, then check/uncheck individual devices, or use Select all / Deselect all | +| Hide unconnected devices | Removes any device with no visible tie line endpoint from the canvas | +| Hide unconnected ports | Shows only the ports on each device that currently have a visible tie line | +| Dark mode | Switches the canvas between dark and light styling | +| Live / Offline badge | Green "Live" means the routing feedback WebSocket is connected and route data is current | +| Refresh button | Reloads the device/tie-line snapshot and reconnects the feedback WebSocket | **Note**: Signal path tracing and live route curves inside device cards require PepperDashEssentials.dll **3.0 or later**. On earlier versions (2.29–2.x) the diagram still shows devices and static tie lines, but there's no live feedback to trace — see [UI Components Reference](../reference/ui-components.md#routing-diagram) for the full version breakdown. @@ -53,14 +55,17 @@ If a device shows the small tile icon in its card header, it currently has an ac ## Troubleshooting the Live Feedback Connection ### Badge stuck on "Offline" + **Cause**: The feedback WebSocket hasn't connected, isn't supported on this Essentials version, or the connection dropped. **Solution**: Confirm PepperDashEssentials.dll is 3.0+ on the app's **Versions** page, then click the **Refresh** button to reconnect. ### Yellow certificate warning banner + **Cause**: The routing feedback server is using a certificate your browser doesn't trust (common with self-signed certificates on internal networks). **Solution**: Click the link in the banner to open that URL directly in a new tab, accept/proceed past the certificate warning there, then reload the Routing page. ### Route curves or live data never appear + **Cause**: Either the Essentials version is below 3.0 (no live feedback exists), or the WebSocket never connected. **Solution**: Check the Live/Offline badge — if it's stuck Offline, use Refresh; if the version is below 3.0, live tracing isn't available and only the static diagram applies. diff --git a/docs/how-to/troubleshoot-connection.md b/docs/how-to/troubleshoot-connection.md index 906d508..55767ca 100644 --- a/docs/how-to/troubleshoot-connection.md +++ b/docs/how-to/troubleshoot-connection.md @@ -17,13 +17,16 @@ Try these quick checks first: ### 1. Verify Basic Network Connectivity **Check network connectivity:** + ```bash ping [processor-ip] ``` + - ✅ **Success**: You get replies → Network connectivity is working - ❌ **Failure**: Request timeout or unreachable → Network issue **If ping fails:** + - Verify you're on the same network/VLAN as the processor - Check your IP configuration and subnet mask - Confirm the processor IP address is correct @@ -32,12 +35,15 @@ ping [processor-ip] ### 2. Verify the Web Service is Running **Test HTTPS connectivity:** + ```bash telnet [processor-ip] 443 ``` + Or try the base URL in your browser: `https://[processor-ip]` **Expected results:** + - ✅ **Connection successful**: Port 443 is open and accepting connections - ❌ **Connection refused**: Web service may not be running - ❌ **Timeout**: Firewall blocking or service not responding @@ -45,10 +51,12 @@ Or try the base URL in your browser: `https://[processor-ip]` ### 3. Check Browser-Specific Issues **Try a different browser:** + - Chrome, Firefox, Safari, or Edge - Use incognito/private mode to avoid cache issues **Clear browser data:** + 1. Clear cookies and cache for the processor's IP 2. Disable browser extensions temporarily 3. Check if popup blockers are interfering @@ -56,11 +64,13 @@ Or try the base URL in your browser: `https://[processor-ip]` ### 4. Handle Certificate Issues **Common certificate warnings:** + - "Your connection is not private" - "NET::ERR_CERT_AUTHORITY_INVALID" - "This site can't provide a secure connection" **How to proceed safely:** + 1. Click "Advanced" or "Show details" 2. Click "Proceed to [IP] (unsafe)" or "Accept the risk" 3. This is safe on your internal network @@ -70,17 +80,20 @@ Or try the base URL in your browser: `https://[processor-ip]` ### 5. Verify Correct URL Format **Correct URL format:** + ``` https://[processor-ip]/debug/ ``` **Common mistakes:** + - ❌ `http://` instead of `https://` - ❌ Missing `/debug/` path - ❌ Wrong IP address - ❌ Extra characters or typos **Examples of correct URLs:** + - `https://192.168.1.100/debug/` - `https://10.0.0.50/debug/` - `https://processor.local/debug/` (if DNS is configured) @@ -88,11 +101,13 @@ https://[processor-ip]/debug/ ### 6. Check Processor Status **Physical indicators:** + - Power LED should be solid (not blinking) - Network LED should show activity - Any error displays on the processor **If processor seems unresponsive:** + - Try power cycling (unplug for 30 seconds, reconnect) - Check for overheating or physical damage - Verify all network cables are secure @@ -100,11 +115,13 @@ https://[processor-ip]/debug/ ### 7. Test from Different Locations **Try connecting from:** + - Different computer on same network - Different network location (if processor accessible) - Mobile device on same WiFi network **This helps identify:** + - Whether the issue is device-specific - Network routing problems - Firewall or access control issues @@ -112,26 +129,32 @@ https://[processor-ip]/debug/ ## Common Error Messages and Solutions ### "This site can't be reached" + **Cause**: Network connectivity issue **Solution**: Check network configuration, IP address, and physical connections ### "Your connection is not private" / "Certificate error" + **Cause**: Self-signed certificate (normal for internal devices) **Solution**: Click "Advanced" → "Proceed to [IP] (unsafe)" ### "404 Not Found" + **Cause**: Wrong URL path **Solution**: Ensure URL ends with `/debug/` (include the trailing slash) ### "500 Internal Server Error" + **Cause**: Web service error on processor **Solution**: Try power cycling the processor, check processor logs ### "Connection timed out" + **Cause**: Firewall blocking connection or service not running **Solution**: Check firewall rules, verify processor is running properly -### Page loads but shows "Loading..." indefinitely +### Page loads but shows "Loading..." indefinitely + **Cause**: JavaScript errors or API connectivity issues **Solution**: Check browser console for errors, try different browser @@ -145,6 +168,7 @@ https://[processor-ip]/debug/ 4. **Check Network tab** for failed requests **Common console errors:** + - CORS errors: May indicate proxy configuration issues - Network errors: API endpoints not responding - JavaScript errors: Browser compatibility issues @@ -154,6 +178,7 @@ https://[processor-ip]/debug/ If you have access to the development setup: **Check required environment variables:** + ```bash # Should be set to processor IP echo $PROGRAM_HOST @@ -165,6 +190,7 @@ echo $PROGRAM_ID ### Test API Endpoints Directly Try accessing API endpoints directly: + ``` https://[processor-ip]/cws/app01/api/versions ``` @@ -174,16 +200,19 @@ Should return JSON data if the API is working. ## Network Configuration Issues ### Subnet and VLAN Issues + - Ensure your device and processor are on the same network segment - Check VLAN configuration if using managed switches - Verify subnet masks allow communication ### Firewall and Security + - Corporate firewalls may block HTTPS to internal devices - Some networks block self-signed certificates - Guest networks may restrict device-to-device communication ### DNS Resolution + - If using hostnames instead of IP addresses - Check DNS configuration and host entries - Try IP address directly to bypass DNS issues @@ -191,11 +220,13 @@ Should return JSON data if the API is working. ## Prevention and Monitoring ### Regular Health Checks + - Test connectivity periodically - Monitor processor uptime and performance - Keep browser bookmarks updated with correct URLs ### Documentation + - Document working IP addresses and URLs - Note any special network configuration requirements - Keep contact information for network administrators @@ -203,11 +234,13 @@ Should return JSON data if the API is working. ## When to Escalate **Contact your network administrator if:** + - Multiple users report the same connectivity issues - Network infrastructure changes preceded the problems - Firewall or security policy changes are suspected **Contact PepperDash support if:** + - Processor hardware appears to be failing - Software updates may have caused issues - Configuration changes are needed @@ -215,6 +248,7 @@ Should return JSON data if the API is working. ## Quick Reference ### Connection Checklist + - [ ] Correct URL format: `https://[ip]/debug/` - [ ] Network connectivity (ping works) - [ ] HTTPS port 443 accessible @@ -223,11 +257,13 @@ Should return JSON data if the API is working. - [ ] No firewall blocking access ### URLs to Test + 1. `https://[processor-ip]/debug/` - Main application 2. `https://[processor-ip]/` - Base web service 3. `https://[processor-ip]/cws/app01/api/versions` - API test ### Browser Settings + - Allow self-signed certificates for internal networks - Disable popup blockers for the processor IP - Clear cache/cookies if problems persist diff --git a/docs/reference/README.md b/docs/reference/README.md index d96531f..69df4f7 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -7,9 +7,11 @@ This section provides complete technical information about all features, APIs, a ## 📱 User Interface Reference ### [UI Components Reference](./ui-components.md) + **Complete technical specification for all user interface elements** **Coverage**: + - Navigation components and behavior - Debug console interface elements - Configuration display components @@ -19,6 +21,7 @@ This section provides complete technical information about all features, APIs, a - Accessibility features and browser compatibility **Use when you need**: + - Detailed information about specific UI elements - Technical specifications for interface behavior - Accessibility and compatibility requirements @@ -29,9 +32,11 @@ This section provides complete technical information about all features, APIs, a ## 🔌 API and Integration Reference ### [API Endpoints Reference](./api-endpoints.md) + **Complete technical specification for all REST API endpoints** **Coverage**: + - All available REST endpoints with request/response formats - WebSocket debug protocol specification - Authentication and security requirements @@ -40,6 +45,7 @@ This section provides complete technical information about all features, APIs, a - Integration examples and best practices **Use when you need**: + - Complete API endpoint documentation - Request and response format specifications - WebSocket protocol implementation details @@ -50,9 +56,11 @@ This section provides complete technical information about all features, APIs, a ## 📊 Data and Filtering Reference ### [Log Levels and Filters Reference](./log-levels.md) + **Complete technical specification for logging system and filtering mechanisms** **Coverage**: + - Log level hierarchy and severity classification - Message structure and property definitions - Filtering mechanisms and combination logic @@ -61,6 +69,7 @@ This section provides complete technical information about all features, APIs, a - Advanced filtering strategies **Use when you need**: + - Understanding log level semantics - Implementing custom filtering logic - Analyzing message patterns and volumes @@ -71,9 +80,11 @@ This section provides complete technical information about all features, APIs, a ## 🔧 Configuration Reference ### [Configuration Schema Reference](./configuration-schema.md) + **Complete technical specification for system configuration structure** **Coverage**: + - Complete JSON schema for configuration files - Device configuration patterns by type - Room and routing configuration structures @@ -82,6 +93,7 @@ This section provides complete technical information about all features, APIs, a - Migration and compatibility information **Use when you need**: + - Understanding configuration file structure - Validating configuration syntax - Creating or modifying configurations @@ -92,9 +104,11 @@ This section provides complete technical information about all features, APIs, a ## 📦 Device and Types Reference ### [Device Types Reference](./device-types.md) + **Complete catalog of supported device types and their properties** **Coverage**: + - All supported device types with descriptions - Required and optional properties for each type - Available methods and commands by device type @@ -103,6 +117,7 @@ This section provides complete technical information about all features, APIs, a - Compatibility and version requirements **Use when you need**: + - Understanding what device types are available - Configuring specific device types - Troubleshooting device-specific issues @@ -113,11 +128,13 @@ This section provides complete technical information about all features, APIs, a ## 📋 Quick Reference Sections ### API Quick Reference + ``` Base URL: https://[processor-ip]/cws/app01/api ``` **Common Endpoints**: + - `GET /versions` - System version information - `GET /devices` - All configured devices - `GET /config` - Complete configuration @@ -125,11 +142,13 @@ Base URL: https://[processor-ip]/cws/app01/api - `POST /restartProgram` - Restart system ### Log Levels Quick Reference + ``` Fatal (5) > Error (4) > Warning (3) > Information (2) > Debug (1) > Verbose (0) ``` **Common Filters**: + - **Problem identification**: Error + Warning levels - **Normal monitoring**: Information + Warning + Error levels - **Device troubleshooting**: Single device + Information+ levels @@ -137,6 +156,7 @@ Fatal (5) > Error (4) > Warning (3) > Information (2) > Debug (1) > Verbose (0) ### UI Components Quick Reference **Main Navigation**: + - Home (`/home`) - Welcome and starting point - Debug Console (`/console`) - Real-time monitoring - Versions (`/versions`) - Assembly information @@ -145,6 +165,7 @@ Fatal (5) > Error (4) > Warning (3) > Information (2) > Debug (1) > Verbose (0) - Types (`/types`) - Available device types **Debug Console Controls**: + - Start/Stop Debug Session - Session management - Device Filter - Filter by device - Log Level Filter - Filter by severity @@ -156,16 +177,19 @@ Fatal (5) > Error (4) > Warning (3) > Information (2) > Debug (1) > Verbose (0) ## 🎯 How to Use Reference Documentation ### Quick Lookup + - **Use the search function** (Ctrl+F) to find specific information - **Check the table of contents** for the section you need - **Reference the quick reference sections** for common information ### Comprehensive Research + - **Start with the relevant section** based on your area of interest - **Cross-reference between sections** for complete understanding - **Use examples and specifications** to understand implementation details ### Development and Integration + - **API Reference** for building integrations or understanding data flows - **Configuration Schema** for system setup and validation - **UI Components** for understanding interface behavior and capabilities @@ -175,21 +199,25 @@ Fatal (5) > Error (4) > Warning (3) > Information (2) > Debug (1) > Verbose (0) ## 📖 Reference vs. Other Documentation Types ### Reference (This Section) + - **Purpose**: Complete technical facts and specifications - **Organization**: By topic and feature area - **Use**: When you need specific technical information ### Tutorials (Learning) + - **Purpose**: Step-by-step learning experiences - **Organization**: By learning progression - **Use**: When you're new to the system ### How-to Guides (Problem-solving) + - **Purpose**: Solutions to specific problems - **Organization**: By problem type - **Use**: When you need to solve a specific issue ### Explanation (Understanding) + - **Purpose**: Background concepts and design rationale - **Organization**: By concept and system area - **Use**: When you want to understand why and how things work @@ -199,16 +227,19 @@ Fatal (5) > Error (4) > Warning (3) > Information (2) > Debug (1) > Verbose (0) ## 🔄 Reference Maintenance ### Accuracy Commitment + - **Verified Information**: All specifications tested against actual system behavior - **Version Alignment**: Documentation matches current application version - **Regular Updates**: Reference updated with application changes ### Completeness Goals + - **Comprehensive Coverage**: All public APIs, UI elements, and features documented - **Technical Depth**: Sufficient detail for implementation and troubleshooting - **Practical Examples**: Real-world examples for complex specifications ### User Feedback Integration + - **Missing Information**: Gaps identified through user feedback are addressed - **Clarity Improvements**: Technical explanations refined based on user questions - **Example Requests**: Additional examples added based on common use cases @@ -218,20 +249,23 @@ Fatal (5) > Error (4) > Warning (3) > Information (2) > Debug (1) > Verbose (0) ## 💡 Tips for Effective Reference Use ### Search Strategies + - **Use specific terms**: Search for exact API endpoints, component names, or property names - **Try variations**: Search for both technical terms and common descriptions - **Cross-reference**: Use information from one section to find related details in other sections ### Bookmarking Recommendations + - **Bookmark frequently used sections** for quick access - **Save links to specific endpoints or components** you work with regularly - **Create personal quick-reference notes** combining information from multiple sections ### Integration with Other Tools + - **Use with development tools**: Reference API specifications while building integrations - **Combine with system documentation**: Use alongside your specific system configuration details - **Reference during troubleshooting**: Cross-reference with debug console output and system behavior --- -*Reference documentation is designed to be comprehensive and authoritative. When you need facts, specifications, or technical details, this is your primary resource. For learning and problem-solving, consider the other documentation types as well.* +_Reference documentation is designed to be comprehensive and authoritative. When you need facts, specifications, or technical details, this is your primary resource. For learning and problem-solving, consider the other documentation types as well._ diff --git a/docs/reference/api-endpoints.md b/docs/reference/api-endpoints.md index c0a711d..bd9b61a 100644 --- a/docs/reference/api-endpoints.md +++ b/docs/reference/api-endpoints.md @@ -15,6 +15,7 @@ All API endpoints are accessed through the base path `/cws/:appId/api` where `:a ## Authentication Endpoints ### Set Login Credentials + **Purpose**: Authenticate with the processor. The backend uses a single shared authentication mechanism for all program slots. ```http @@ -22,6 +23,7 @@ POST /loginCredentials ``` **Request Body**: + ```json { "username": "admin", @@ -32,6 +34,7 @@ POST /loginCredentials **Response**: `200 OK` (empty body) on success **Notes**: + - A successful response with any `appId` authenticates the session for all running slots - The app probes all 10 slots in parallel after initial auth to discover which are running - A `4xx` or network error indicates invalid credentials or that the slot is not running @@ -41,6 +44,7 @@ POST /loginCredentials ## System Information Endpoints ### Get Versions + **Purpose**: Retrieve all loaded assemblies and their versions ```http @@ -48,6 +52,7 @@ GET /versions ``` **Response**: + ```json [ { @@ -62,17 +67,20 @@ GET /versions ``` **Response Fields**: + - `Name` (string): Full assembly name - `Version` (string): Version number in dotted format **Usage**: Displayed on Versions page for system documentation and troubleshooting **Error Conditions**: + - `500`: Server error if version information cannot be retrieved --- ### Get API Paths + **Purpose**: Retrieve all available REST API routes registered on the processor ```http @@ -80,6 +88,7 @@ GET /apiPaths ``` **Response**: + ```json { "url": "https://192.168.1.100/cws/app01", @@ -95,6 +104,7 @@ GET /apiPaths ``` **Response Fields**: + - `url` (string): Base URL of the processor web server for this app slot - `routes` (array): List of route objects - `Name` (string): Route name @@ -104,11 +114,13 @@ GET /apiPaths **Usage**: Displayed on the API Paths page; routes are sorted alphabetically and shown with clickable URLs **Error Conditions**: + - `500`: Server error if route information cannot be retrieved --- ### Get Device Types + **Purpose**: Retrieve all available device types supported by current plugins ```http @@ -116,6 +128,7 @@ GET /types ``` **Response**: + ```json [ { @@ -132,6 +145,7 @@ GET /types ``` **Response Fields**: + - `Type` (string): Configuration identifier used in device configuration - `Description` (string): Human-readable description of device purpose - `CType` (string): Full .NET class name that implements the device @@ -139,6 +153,7 @@ GET /types **Usage**: Displayed on Types page for configuration reference and development **Error Conditions**: + - `500`: Server error if type information cannot be retrieved --- @@ -146,6 +161,7 @@ GET /types ## Device Management Endpoints ### Get Devices + **Purpose**: Retrieve all configured devices in the system ```http @@ -153,6 +169,7 @@ GET /devices ``` **Response**: + ```json [ { @@ -160,24 +177,27 @@ GET /devices "Name": "Conference Room Display" }, { - "Key": "Codec-Main", + "Key": "Codec-Main", "Name": "Main Video Codec" } ] ``` **Response Fields**: + - `Key` (string): Unique device identifier used in configuration and debug messages - `Name` (string): Human-readable device name for user interfaces **Usage**: Device list display and debug message filtering **Error Conditions**: + - `500`: Server error if device information cannot be retrieved --- ### Get Device Properties + **Purpose**: Retrieve current properties and values for a specific device ```http @@ -185,9 +205,11 @@ GET /deviceProperties/{deviceKey} ``` **Path Parameters**: + - `deviceKey` (string): The unique Key of the device **Response**: + ```json [ { @@ -199,7 +221,7 @@ GET /deviceProperties/{deviceKey} }, { "Name": "CurrentInput", - "Type": "String", + "Type": "String", "Value": "HDMI1", "CanRead": true, "CanWrite": false @@ -208,6 +230,7 @@ GET /deviceProperties/{deviceKey} ``` **Response Fields**: + - `Name` (string): Property name - `Type` (string): Data type of the property value - `Value` (string): Current property value (always string representation) @@ -217,22 +240,26 @@ GET /deviceProperties/{deviceKey} **Usage**: Device detail inspection and monitoring **Error Conditions**: + - `404`: Device with specified key not found - `500`: Server error retrieving device properties --- ### Get Device Methods -**Purpose**: Retrieve available methods (commands) for a specific device + +**Purpose**: Retrieve available methods (commands) for a specific device ```http GET /deviceMethods/{deviceKey} ``` **Path Parameters**: + - `deviceKey` (string): The unique Key of the device **Response**: + ```json [ { @@ -252,6 +279,7 @@ GET /deviceMethods/{deviceKey} ``` **Response Fields**: + - `Name` (string): Method name - `Params` (array): Array of parameter definitions - `Name` (string): Parameter name @@ -260,6 +288,7 @@ GET /deviceMethods/{deviceKey} **Usage**: Device control interface and method execution **Error Conditions**: + - `404`: Device with specified key not found - `500`: Server error retrieving device methods @@ -268,6 +297,7 @@ GET /deviceMethods/{deviceKey} ## Configuration Endpoints ### Get Configuration + **Purpose**: Retrieve the complete merged system configuration ```http @@ -277,6 +307,7 @@ GET /config **Response**: Complete JSON configuration object (structure varies by system) **Example Response Structure**: + ```json { "devices": { @@ -308,6 +339,7 @@ GET /config **Response Size**: Can be very large (10KB - 1MB+) depending on system complexity **Error Conditions**: + - `500`: Server error if configuration cannot be retrieved or merged --- @@ -315,6 +347,7 @@ GET /config ## Debug and Monitoring Endpoints ### Start Debug Session + **Purpose**: Initiate a WebSocket debug session for real-time message monitoring ```http @@ -322,6 +355,7 @@ GET /debugSession ``` **Response**: + ```json { "url": "wss://192.168.1.100/cws/app01/api/debug-websocket" @@ -329,16 +363,19 @@ GET /debugSession ``` **Response Fields**: + - `url` (string): WebSocket URL for establishing debug connection **Usage**: Real-time debug message monitoring in Debug Console **WebSocket Protocol**: + - **Connection**: Use returned URL to establish WebSocket connection - **Messages**: Server sends JSON-formatted log messages - **Client**: Client receives messages, no need to send data to server **WebSocket Message Format**: + ```json { "Timestamp": "2024-01-15T10:30:45.123Z", @@ -353,12 +390,14 @@ GET /debugSession ``` **Error Conditions**: + - `500`: Server error if debug session cannot be started - WebSocket connection errors handled by client WebSocket implementation --- ### Stop Debug Session + **Purpose**: Stop an active debug session and close WebSocket connections ```http @@ -372,6 +411,7 @@ POST /debugSession **Usage**: Clean termination of debug sessions **Error Conditions**: + - `500`: Server error stopping debug session --- @@ -379,6 +419,7 @@ POST /debugSession ## System Control Endpoints ### Get Minimum Log Level + **Purpose**: Retrieve the current minimum log level for debug output ```http @@ -386,6 +427,7 @@ GET /appdebug ``` **Response**: + ```json { "minimumLevel": "Information" @@ -393,9 +435,11 @@ GET /appdebug ``` **Response Fields**: + - `minimumLevel` (string): Current minimum log level setting **Valid Log Levels** (in order of severity): + - `Verbose`: Most detailed logging - `Debug`: Detailed technical information - `Information`: General informational messages @@ -406,11 +450,13 @@ GET /appdebug **Usage**: Display current log level setting and provide options for changes **Error Conditions**: + - `500`: Server error retrieving log level setting --- ### Set Minimum Log Level + **Purpose**: Change the minimum log level for debug output ```http @@ -418,6 +464,7 @@ POST /appdebug ``` **Request Body**: + ```json { "minimumLevel": "Warning" @@ -425,6 +472,7 @@ POST /appdebug ``` **Request Fields**: + - `minimumLevel` (string): New minimum log level (must be valid level) **Response**: Empty (204 No Content on success) @@ -432,12 +480,14 @@ POST /appdebug **Usage**: Adjust debug verbosity from Debug Console interface **Error Conditions**: + - `400`: Invalid log level specified - `500`: Server error setting log level --- ### Get Configuration Loading Setting + **Purpose**: Check if configuration loading on boot is disabled ```http @@ -445,6 +495,7 @@ GET /doNotLoadConfigOnNextBoot ``` **Response**: + ```json { "doNotLoadConfigOnNextBoot": false @@ -452,16 +503,19 @@ GET /doNotLoadConfigOnNextBoot ``` **Response Fields**: + - `doNotLoadConfigOnNextBoot` (boolean): Whether config loading is disabled **Usage**: Display current setting and allow user control **Error Conditions**: + - `500`: Server error retrieving setting --- ### Set Configuration Loading Setting + **Purpose**: Enable or disable configuration loading on next boot ```http @@ -469,6 +523,7 @@ POST /doNotLoadConfigOnNextBoot ``` **Request Body**: + ```json { "doNotLoadConfigOnNextBoot": true @@ -476,6 +531,7 @@ POST /doNotLoadConfigOnNextBoot ``` **Request Fields**: + - `doNotLoadConfigOnNextBoot` (boolean): New setting value **Response**: Empty (204 No Content on success) @@ -483,12 +539,14 @@ POST /doNotLoadConfigOnNextBoot **Usage**: Control configuration loading behavior for troubleshooting **Error Conditions**: + - `400`: Invalid boolean value specified - `500`: Server error setting configuration --- ### Restart Program + **Purpose**: Restart the entire PepperDash Essentials framework ```http @@ -502,17 +560,20 @@ POST /restartProgram **Usage**: Complete system restart from web interface **Behavior**: + - System begins restart immediately - All connections will be closed - Response may not be received due to restart timing - System will be unavailable for 2-5 minutes during restart **Error Conditions**: + - `500`: Server error initiating restart (system may still restart) --- ### Load Configuration + **Purpose**: Manually reload system configuration without full restart ```http @@ -528,6 +589,7 @@ POST /loadConfig **Prerequisites**: Usually used when "doNotLoadConfigOnNextBoot" is true **Error Conditions**: + - `400`: Configuration cannot be loaded (syntax errors, etc.) - `500`: Server error during configuration loading @@ -538,11 +600,13 @@ POST /loadConfig All endpoints return errors in consistent format: **HTTP Status Codes**: + - `400`: Bad Request - Invalid parameters or request format - `404`: Not Found - Requested resource does not exist - `500`: Internal Server Error - Server-side processing error **Error Response Body**: + ```json { "error": "Description of the error condition", @@ -555,11 +619,13 @@ All endpoints return errors in consistent format: **Rate Limits**: No explicit rate limiting implemented **Performance Considerations**: + - `/config` endpoint may take several seconds for large configurations - `/debugSession` WebSocket can generate high message volumes - Multiple simultaneous debug sessions impact processor performance **Best Practices**: + - Cache version and type information (changes infrequently) - Close debug sessions when not actively monitoring - Use appropriate minimum log levels to reduce debug message volume @@ -575,6 +641,7 @@ All endpoints return errors in consistent format: **CORS**: Configured to allow requests from the web application origin **Sensitive Data**: + - Configuration may contain IP addresses, usernames, and network topology - Debug messages may contain sensitive operational information - No automatic filtering of sensitive information in responses @@ -582,20 +649,24 @@ All endpoints return errors in consistent format: ## WebSocket Debug Protocol ### Connection Establishment + 1. Call `GET /debugSession` to get WebSocket URL 2. Establish WebSocket connection using returned URL 3. Connection remains open until explicitly closed or system restart ### Message Flow + - **Server to Client**: Continuous stream of debug messages in JSON format - **Client to Server**: No messages required (read-only protocol) ### Connection Management + - **Keep-alive**: WebSocket handles connection keep-alive automatically - **Reconnection**: Client must handle reconnection logic if connection drops - **Cleanup**: Call `POST /debugSession` to cleanly stop session ### Message Volume Management + - **High Volume**: Systems may generate >100 messages per second - **Filtering**: Use minimum log level to reduce message volume - **Browser Limits**: Very high message rates may impact browser performance @@ -603,28 +674,30 @@ All endpoints return errors in consistent format: ## Integration Examples ### Basic Configuration Retrieval + ```javascript fetch('https://192.168.1.100/cws/app01/api/config') - .then(response => response.json()) - .then(config => { + .then((response) => response.json()) + .then((config) => { console.log('System configuration:', config); }); ``` ### Starting Debug Session + ```javascript // Get WebSocket URL fetch('https://192.168.1.100/cws/app01/api/debugSession') - .then(response => response.json()) - .then(data => { + .then((response) => response.json()) + .then((data) => { // Connect to WebSocket const ws = new WebSocket(data.url); - + ws.onmessage = (event) => { const message = JSON.parse(event.data); console.log('Debug message:', message); }; - + ws.onclose = () => { console.log('Debug session closed'); }; @@ -632,15 +705,16 @@ fetch('https://192.168.1.100/cws/app01/api/debugSession') ``` ### Setting Log Level + ```javascript fetch('https://192.168.1.100/cws/app01/api/appdebug', { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, body: JSON.stringify({ - minimumLevel: 'Warning' - }) + minimumLevel: 'Warning', + }), }); ``` diff --git a/docs/reference/configuration-schema.md b/docs/reference/configuration-schema.md index 801d45d..4a1f648 100644 --- a/docs/reference/configuration-schema.md +++ b/docs/reference/configuration-schema.md @@ -17,7 +17,7 @@ This document provides complete reference information about the configuration da "devices": { "deviceKey": { "key": "string", - "name": "string", + "name": "string", "type": "string", "group": "string", "properties": {}, @@ -27,7 +27,7 @@ This document provides complete reference information about the configuration da "tieLines": [ { "sourceDevice": "string", - "destinationDevice": "string", + "destinationDevice": "string", "type": "string" } ], @@ -50,20 +50,21 @@ This document provides complete reference information about the configuration da All devices share these common configuration properties: -| Property | Type | Required | Description | -|----------|------|----------|-------------| -| `key` | string | Yes | Unique identifier for the device | -| `name` | string | Yes | Human-readable display name | -| `type` | string | Yes | Device type identifier | -| `group` | string | No | Logical grouping for organization | -| `enabled` | boolean | No | Whether device is active (default: true) | -| `description` | string | No | Additional device description | +| Property | Type | Required | Description | +| ------------- | ------- | -------- | ---------------------------------------- | +| `key` | string | Yes | Unique identifier for the device | +| `name` | string | Yes | Human-readable display name | +| `type` | string | Yes | Device type identifier | +| `group` | string | No | Logical grouping for organization | +| `enabled` | boolean | No | Whether device is active (default: true) | +| `description` | string | No | Additional device description | ### Device-Specific Properties Device properties vary by type. Common property categories include: #### Connection Properties + ```json { "control": { @@ -79,6 +80,7 @@ Device properties vary by type. Common property categories include: ``` #### Communication Properties + ```json { "communicationMonitorProperties": { @@ -95,6 +97,7 @@ Device properties vary by type. Common property categories include: ### Display Devices #### Generic Display + ```json { "type": "genericDisplay", @@ -113,6 +116,7 @@ Device properties vary by type. Common property categories include: ``` #### Sony Display + ```json { "type": "sonyDisplay", @@ -131,7 +135,8 @@ Device properties vary by type. Common property categories include: ### Audio Devices -#### Generic Audio DSP +#### Generic Audio DSP + ```json { "type": "genericAudioDsp", @@ -157,6 +162,7 @@ Device properties vary by type. Common property categories include: ``` #### Cisco Codec + ```json { "type": "ciscoCodec", @@ -178,15 +184,16 @@ Device properties vary by type. Common property categories include: ### Control System Devices #### Crestron Processor + ```json { - "type": "crestron3Series", + "type": "crestron3Series", "properties": { "control": { "method": "crestronCom", "comParams": { "hardwareHandshake": "None", - "parity": "None", + "parity": "None", "baudRate": 38400, "dataBits": 8, "stopBits": 1 @@ -202,6 +209,7 @@ Device properties vary by type. Common property categories include: ## Room Configuration Schema ### Basic Room Structure + ```json { "roomKey": { @@ -226,18 +234,19 @@ Device properties vary by type. Common property categories include: ### Room Properties -| Property | Type | Required | Description | -|----------|------|----------|-------------| -| `key` | string | Yes | Unique room identifier | -| `name` | string | Yes | Display name for the room | -| `description` | string | No | Additional room information | -| `sourceListKey` | string | No | Reference to source list configuration | -| `defaultSourceItem` | string | No | Default active source | -| `devices` | array | No | List of device keys in this room | +| Property | Type | Required | Description | +| ------------------- | ------ | -------- | -------------------------------------- | +| `key` | string | Yes | Unique room identifier | +| `name` | string | Yes | Display name for the room | +| `description` | string | No | Additional room information | +| `sourceListKey` | string | No | Reference to source list configuration | +| `defaultSourceItem` | string | No | Default active source | +| `devices` | array | No | List of device keys in this room | ## Source List Configuration ### Source List Structure + ```json { "sourceListKey": { @@ -254,7 +263,7 @@ Device properties vary by type. Common property categories include: }, "routingOutputs": { "videoOutputs": ["output1"], - "audioOutputs": ["output1"] + "audioOutputs": ["output1"] } } } @@ -267,22 +276,24 @@ Device properties vary by type. Common property categories include: ### Tie Line Types #### Audio Tie Lines + ```json { "sourceDevice": "dsp1", - "destinationDevice": "codec1", + "destinationDevice": "codec1", "type": "audio", "sourceOutput": "programOut", "destinationInput": "micIn" } ``` -#### Video Tie Lines +#### Video Tie Lines + ```json { "sourceDevice": "switcher1", "destinationDevice": "display1", - "type": "video", + "type": "video", "sourceOutput": "output1", "destinationInput": "hdmi1" } @@ -293,13 +304,15 @@ Device properties vary by type. Common property categories include: ### Required Fields Validation The system validates that all required fields are present: + - Device `key` and `type` are mandatory -- Room `key` and `name` are mandatory +- Room `key` and `name` are mandatory - Tie line `sourceDevice` and `destinationDevice` must reference existing devices ### Type Validation Device types must match registered factory types: + - Unknown device types will generate warnings - Missing required properties for device types will cause errors - Invalid property values will be flagged during validation @@ -307,6 +320,7 @@ Device types must match registered factory types: ### Reference Validation Cross-references between configuration objects are validated: + - Device keys referenced in rooms must exist - Source list references must point to valid source lists - Tie line device references must point to existing devices @@ -316,8 +330,9 @@ Cross-references between configuration objects are validated: ### Merge Priority Order When multiple configuration files are present, they are merged in this order: + 1. Base system configuration -2. Template configurations +2. Template configurations 3. User configuration files 4. Environment-specific overrides @@ -329,6 +344,7 @@ When multiple configuration files are present, they are merged in this order: - **Null/Undefined**: Explicit null values remove properties ### Example Merge Behavior + ```json // Base config { @@ -343,11 +359,11 @@ When multiple configuration files are present, they are merged in this order: } } -// Override config +// Override config { "devices": { "display1": { - "name": "Main Display", + "name": "Main Display", "properties": { "volume": 75 } @@ -374,6 +390,7 @@ When multiple configuration files are present, they are merged in this order: ### Read-Only Access The web config app provides read-only access to merged configuration: + - Cannot modify configuration through the web interface - Configuration changes require file system access to the processor - Changes take effect after configuration reload @@ -381,6 +398,7 @@ The web config app provides read-only access to merged configuration: ### Configuration Refresh Configuration can be refreshed without restarting: + - Use the "Reload Configuration" function in the web app - Configuration is re-read and merged from files - Active devices maintain state where possible @@ -389,6 +407,7 @@ Configuration can be refreshed without restarting: ## Common Configuration Patterns ### Multi-Room Systems + ```json { "devices": { @@ -409,7 +428,7 @@ Configuration can be refreshed without restarting: "volumeControlKey": "room1Volume" }, "room2": { - "devices": ["mainDsp"], + "devices": ["mainDsp"], "volumeControlKey": "room2Volume" } } @@ -417,6 +436,7 @@ Configuration can be refreshed without restarting: ``` ### Video Switching Systems + ```json { "devices": { @@ -444,24 +464,29 @@ Configuration can be refreshed without restarting: ### Common Problems **Missing Device References**: + - Symptoms: Warnings in debug console about unknown devices - Solution: Verify device keys match exactly between references **Invalid Device Types**: + - Symptoms: Errors during system startup - Solution: Check device type names against factory registrations **Circular References**: + - Symptoms: System fails to start or infinite loops - Solution: Review tie line configurations for circular routing **Property Type Mismatches**: + - Symptoms: Device properties not working as expected - Solution: Verify property types match device expectations ### Configuration Debugging Use the debug console to identify configuration issues: + 1. Look for configuration validation messages during startup 2. Check device initialization messages for failures 3. Monitor property change messages to verify configuration application @@ -469,4 +494,4 @@ Use the debug console to identify configuration issues: --- -*This reference provides complete information about configuration structure and validation. Use it to understand how configuration files are structured and how to interpret configuration data displayed in the web app.* +_This reference provides complete information about configuration structure and validation. Use it to understand how configuration files are structured and how to interpret configuration data displayed in the web app._ diff --git a/docs/reference/device-types.md b/docs/reference/device-types.md index 2735bd6..9699843 100644 --- a/docs/reference/device-types.md +++ b/docs/reference/device-types.md @@ -7,9 +7,11 @@ This document provides comprehensive reference information about all supported d ### Display Devices #### Generic Display (`genericDisplay`) + **Purpose**: Universal display control for most display devices using standard protocols. **Key Properties**: + - `supportsDiscretePower`: boolean - Whether device supports separate on/off commands - `supportsVolumeControl`: boolean - Whether display has volume control - `warmupTimeMs`: number - Time in milliseconds for display warmup @@ -18,6 +20,7 @@ This document provides comprehensive reference information about all supported d **Control Methods**: TCP/IP, RS-232, IR **Example Configuration**: + ```json { "type": "genericDisplay", @@ -31,9 +34,11 @@ This document provides comprehensive reference information about all supported d ``` #### Sony Professional Display (`sonyDisplay`) + **Purpose**: Enhanced control for Sony professional displays with advanced features. **Key Properties**: + - `id`: string - Display ID for multi-display setups (01-99) - `supportsAdvancedPicture`: boolean - Advanced picture control support - `inputCount`: number - Number of available inputs @@ -41,9 +46,10 @@ This document provides comprehensive reference information about all supported d **Control Methods**: TCP/IP (port 20060), RS-232 **Example Configuration**: + ```json { - "type": "sonyDisplay", + "type": "sonyDisplay", "properties": { "id": "01", "supportsAdvancedPicture": true, @@ -53,9 +59,11 @@ This document provides comprehensive reference information about all supported d ``` #### Samsung Commercial Display (`samsungDisplay`) + **Purpose**: Control for Samsung commercial display series with MDC protocol. **Key Properties**: + - `displayId`: number - Display ID for daisy-chained displays (0-254) - `supportsNetworkStandby`: boolean - Network wake-on-LAN support - `maxVolumeLevel`: number - Maximum volume level (default: 100) @@ -65,14 +73,17 @@ This document provides comprehensive reference information about all supported d ### Audio DSP Devices #### Generic Audio DSP (`genericAudioDsp`) + **Purpose**: Universal audio processor control with configurable level and routing blocks. **Key Properties**: + - `levelControlBlocks`: object - Named level control configurations - `presetCount`: number - Number of available presets - `supportsAdvancedRouting`: boolean - Matrix routing capabilities **Level Control Block Properties**: + - `enabled`: boolean - Whether this control is active - `hasLevel`: boolean - Volume level control available - `hasMute`: boolean - Mute control available @@ -83,6 +94,7 @@ This document provides comprehensive reference information about all supported d **Control Methods**: TCP/IP, RS-232 **Example Configuration**: + ```json { "type": "genericAudioDsp", @@ -109,9 +121,11 @@ This document provides comprehensive reference information about all supported d ``` #### Biamp Tesira DSP (`biampTesiraDsp`) + **Purpose**: Advanced control for Biamp Tesira series audio processors. **Key Properties**: + - `instanceTag`: string - Tesira instance identifier - `controlBlocks`: object - Named control block configurations - `supportsSubscriptions`: boolean - Real-time property subscriptions @@ -119,9 +133,11 @@ This document provides comprehensive reference information about all supported d **Control Methods**: TCP/IP (port 23) #### QSC Q-SYS Core (`qscQSysCore`) + **Purpose**: Control for QSC Q-SYS platform processors and components. **Key Properties**: + - `coreId`: string - Q-SYS Core identifier - `namedControls`: object - Named control configurations - `supportsExternalControl`: boolean - External control script support @@ -131,9 +147,11 @@ This document provides comprehensive reference information about all supported d ### Video Switching Devices #### Extron Video Switcher (`extronVideoSwitcher`) + **Purpose**: Control for Extron matrix switchers and presentation systems. **Key Properties**: + - `inputCount`: number - Number of inputs available - `outputCount`: number - Number of outputs available - `supportsAudioSwitching`: boolean - Audio switching capabilities @@ -142,6 +160,7 @@ This document provides comprehensive reference information about all supported d **Control Methods**: TCP/IP (port 23), RS-232 **Example Configuration**: + ```json { "type": "extronVideoSwitcher", @@ -155,9 +174,11 @@ This document provides comprehensive reference information about all supported d ``` #### Crestron DmMd Series (`crestronDmMd`) + **Purpose**: Control for Crestron DigitalMedia switcher series. **Key Properties**: + - `dmChassisId`: number - DM chassis ID for larger systems - `inputSlots`: array - Available input slot configurations - `outputSlots`: array - Available output slot configurations @@ -167,9 +188,11 @@ This document provides comprehensive reference information about all supported d ### Codec and Communication Devices #### Cisco Video Codec (`ciscoCodec`) + **Purpose**: Control for Cisco video conferencing systems (SX, MX, Room series). **Key Properties**: + - `sipPhoneLineKeys`: array - Available SIP line identifiers - `supportsContacts`: boolean - Contact directory integration - `maxCallCount`: number - Maximum simultaneous calls @@ -178,6 +201,7 @@ This document provides comprehensive reference information about all supported d **Control Methods**: SSH (port 22), HTTP API **Example Configuration**: + ```json { "type": "ciscoCodec", @@ -191,9 +215,11 @@ This document provides comprehensive reference information about all supported d ``` #### Polycom Group Series (`polycomGroupSeries`) + **Purpose**: Control for Polycom Group series video systems. **Key Properties**: + - `apiVersion`: string - Polycom API version (v1, v2) - `supportsDirectoryServices`: boolean - Directory integration - `audioInputCount`: number - Number of audio inputs @@ -201,9 +227,11 @@ This document provides comprehensive reference information about all supported d **Control Methods**: HTTP API (port 80/443) #### Generic VoIP Phone (`genericVoipPhone`) + **Purpose**: Basic control for SIP-based VoIP phones. **Key Properties**: + - `lineCount`: number - Number of phone lines - `supportsCallControl`: boolean - Call control capabilities - `registrarAddress`: string - SIP registrar server @@ -213,9 +241,11 @@ This document provides comprehensive reference information about all supported d ### Lighting Control Devices #### Lutron Quantum (`lutronQuantum`) + **Purpose**: Integration with Lutron Quantum lighting systems. **Key Properties**: + - `integrationId`: number - Quantum integration ID (1-100) - `zoneCount`: number - Number of lighting zones - `supportsShades`: boolean - Motorized shade control @@ -223,9 +253,11 @@ This document provides comprehensive reference information about all supported d **Control Methods**: TCP/IP (port 23) #### Generic Lighting Controller (`genericLighting`) + **Purpose**: Universal lighting control for various protocols. **Key Properties**: + - `channelCount`: number - Number of lighting channels - `supportsScenes`: boolean - Lighting scene recall - `dimmingCurve`: string - Dimming curve type (linear, logarithmic) @@ -235,9 +267,11 @@ This document provides comprehensive reference information about all supported d ### Environmental Control Devices #### Generic Climate Control (`genericClimate`) + **Purpose**: HVAC and environmental control integration. **Key Properties**: + - `supportsHeating`: boolean - Heating control available - `supportsCooling`: boolean - Cooling control available - `tempRange`: object - Temperature control range @@ -246,9 +280,11 @@ This document provides comprehensive reference information about all supported d **Control Methods**: TCP/IP, RS-232, BACnet #### Generic Relay Controller (`genericRelay`) + **Purpose**: Control for relay-based switching systems. **Key Properties**: + - `relayCount`: number - Number of available relays - `relayType`: string - Relay type (NO, NC, SPDT) - `pulseDurationMs`: number - Default pulse duration @@ -258,9 +294,11 @@ This document provides comprehensive reference information about all supported d ### Control System Devices #### Crestron 3-Series Processor (`crestron3Series`) + **Purpose**: Integration with Crestron 3-Series control processors. **Key Properties**: + - `eiscp`: object - EISCP server configuration - `cip`: object - CIP communication settings - `roomId`: number - Room ID for multi-room systems @@ -268,6 +306,7 @@ This document provides comprehensive reference information about all supported d **Control Methods**: CresNet, Ethernet (CIP) **Example Configuration**: + ```json { "type": "crestron3Series", @@ -281,9 +320,11 @@ This document provides comprehensive reference information about all supported d ``` #### Generic IR Controller (`genericIr`) + **Purpose**: Infrared control device integration. **Key Properties**: + - `irPorts`: array - Available IR port configurations - `supportsLearning`: boolean - IR learning capability - `carrierFrequency`: number - IR carrier frequency (Hz) @@ -293,9 +334,11 @@ This document provides comprehensive reference information about all supported d ### Camera and PTZ Devices #### Generic PTZ Camera (`genericPtzCamera`) + **Purpose**: Pan-tilt-zoom camera control. **Key Properties**: + - `presetCount`: number - Number of camera presets - `supportsAutoFocus`: boolean - Auto-focus capability - `zoomRange`: object - Optical zoom range @@ -304,6 +347,7 @@ This document provides comprehensive reference information about all supported d **Control Methods**: TCP/IP, RS-232, VISCA **Example Configuration**: + ```json { "type": "genericPtzCamera", @@ -326,6 +370,7 @@ This document provides comprehensive reference information about all supported d All network-connected devices support these communication properties: #### TCP/IP Properties (`tcpSshProperties`) + ```json { "address": "192.168.1.100", @@ -338,6 +383,7 @@ All network-connected devices support these communication properties: ``` #### Serial Properties (`comParams`) + ```json { "baudRate": 9600, @@ -352,6 +398,7 @@ All network-connected devices support these communication properties: ### Monitoring Properties #### Communication Monitor (`communicationMonitorProperties`) + ```json { "pollString": "?", @@ -365,6 +412,7 @@ All network-connected devices support these communication properties: ### Device Status Properties All devices provide these status indicators: + - **CommunicationMonitor**: Connection health (OK, Warning, Error) - **PowerIsOn**: Device power state (when applicable) - **IsOnline**: Network connectivity status @@ -377,13 +425,14 @@ All devices provide these status indicators: Each device type must be registered with a factory class: ```csharp -DeviceFactory.RegisterDeviceFactory("genericDisplay", +DeviceFactory.RegisterDeviceFactory("genericDisplay", typeof(GenericDisplayFactory)); ``` ### Properties Schema Validation Device factories define property schemas for validation: + - Required properties are enforced during configuration load - Property types are validated against expected types - Unknown properties generate warnings but don't prevent loading @@ -391,6 +440,7 @@ Device factories define property schemas for validation: ### Device Capabilities Devices expose capabilities through interfaces: + - `IBasicVolumeControls`: Volume and mute control - `IPower`: Power control with discrete on/off - `IRoutingInputsOutputs`: Signal routing capabilities @@ -415,6 +465,7 @@ Devices expose capabilities through interfaces: ### Property Validation Custom device types can implement property validation: + - Override `ValidateProperties()` method - Return validation messages for invalid configurations - Support both warnings and errors @@ -422,6 +473,7 @@ Custom device types can implement property validation: ### Device Communication Implement communication patterns: + - Override communication methods for device-specific protocols - Implement heartbeat and monitoring patterns - Handle connection state changes appropriately @@ -431,16 +483,19 @@ Implement communication patterns: ### Common Issues **Device Type Not Found**: + - Verify device type name matches factory registration exactly - Check that required assemblies are loaded - Review plugin loading and factory registration logs **Property Validation Errors**: + - Compare device properties against schema requirements - Check property data types and value ranges - Verify required properties are present **Communication Failures**: + - Verify network connectivity and device addresses - Check protocol-specific settings (ports, credentials) - Review device-specific communication requirements @@ -448,6 +503,7 @@ Implement communication patterns: ### Debugging Device Behavior Use the debug console to troubleshoot device issues: + 1. Monitor device initialization messages 2. Check communication monitor status changes 3. Review property change notifications @@ -455,4 +511,4 @@ Use the debug console to troubleshoot device issues: --- -*This reference provides complete information about all supported device types and their configuration requirements. Use it to understand device capabilities and configure devices properly in your system.* +_This reference provides complete information about all supported device types and their configuration requirements. Use it to understand device capabilities and configure devices properly in your system._ diff --git a/docs/reference/log-levels.md b/docs/reference/log-levels.md index 758a1f7..fe14066 100644 --- a/docs/reference/log-levels.md +++ b/docs/reference/log-levels.md @@ -6,33 +6,37 @@ ### Severity Levels (Most to Least Critical) -| Level | Numeric Value | Purpose | Usage Guidelines | -|-------|---------------|---------|------------------| -| Fatal | 5 | System cannot continue | Application crashes, critical failures | -| Error | 4 | Error conditions | Device failures, communication errors | -| Warning | 3 | Warning conditions | Potential issues, deprecated usage | -| Information | 2 | General information | Normal operations, status changes | -| Debug | 1 | Detailed debug info | Technical details for developers | -| Verbose | 0 | Trace information | Extremely detailed execution traces | +| Level | Numeric Value | Purpose | Usage Guidelines | +| ----------- | ------------- | ---------------------- | -------------------------------------- | +| Fatal | 5 | System cannot continue | Application crashes, critical failures | +| Error | 4 | Error conditions | Device failures, communication errors | +| Warning | 3 | Warning conditions | Potential issues, deprecated usage | +| Information | 2 | General information | Normal operations, status changes | +| Debug | 1 | Detailed debug info | Technical details for developers | +| Verbose | 0 | Trace information | Extremely detailed execution traces | ### Level Selection Impact **When setting minimum log level to "Warning":** + - **Captured**: Fatal, Error, Warning messages - **Filtered out**: Information, Debug, Verbose messages - **Use case**: Problem identification, production monitoring **When setting minimum log level to "Information":** -- **Captured**: Fatal, Error, Warning, Information messages + +- **Captured**: Fatal, Error, Warning, Information messages - **Filtered out**: Debug, Verbose messages - **Use case**: Normal system monitoring, general troubleshooting **When setting minimum log level to "Debug":** + - **Captured**: All messages except Verbose - **Filtered out**: Only Verbose messages - **Use case**: Detailed troubleshooting, development **When setting minimum log level to "Verbose":** + - **Captured**: All messages - **Filtered out**: None - **Use case**: Deep debugging, code-level analysis @@ -49,14 +53,14 @@ Each device checked in the Debug Console Devices dropdown has its own minimum lo where `LOG_LEVEL_ORDER` is: -| Level | Order Value | -|-------|-------------| -| Verbose | 0 | -| Debug | 1 | -| Information | 2 | -| Warning | 3 | -| Error | 4 | -| Fatal | 5 | +| Level | Order Value | +| ----------- | ----------- | +| Verbose | 0 | +| Debug | 1 | +| Information | 2 | +| Warning | 3 | +| Error | 4 | +| Fatal | 5 | **Example**: Device set to `Warning` — shows Warning, Error, Fatal; hides Information, Debug, Verbose @@ -65,6 +69,7 @@ where `LOG_LEVEL_ORDER` is: ### Filter Combination Logic All client-side filters use AND logic: + - **Device filter**: Message key must match a checked device (or `Global`) - **Per-device minimum level**: Message severity must meet the device's threshold - **Text search**: All search terms must appear somewhere in the message fields @@ -76,12 +81,14 @@ The **Minimum Log Level** dropdown in the Debug Console session panel sets the s ### System-Level Messages **Global Messages** (Key: "global" or empty): + - System startup and shutdown events - Framework-level operations - Cross-device operations - Resource allocation and management **Example Global Messages**: + ``` Information: System startup complete Warning: High memory usage detected @@ -92,12 +99,14 @@ Information: Device initialization sequence started ### Device-Specific Messages **Device Messages** (Key: Device identifier): + - Individual device operations - Communication events - Status changes - Error conditions **Example Device Messages**: + ``` Information: Device [Display-Room1] connection established Warning: Device [Display-Room1] response timeout @@ -110,6 +119,7 @@ Debug: Device [Display-Room1] sending command: Power On ### Standard Message Format **Core Fields** (Present in all messages): + ```json { "Timestamp": "ISO 8601 formatted timestamp", @@ -123,29 +133,34 @@ Debug: Device [Display-Room1] sending command: Power On **Field Descriptions**: **Timestamp**: + - Format: ISO 8601 with milliseconds - Example: `"2024-01-15T10:30:45.123Z"` - Timezone: UTC - Precision: Millisecond accuracy **MessageTemplate**: + - Format: String with placeholder syntax - Example: `"Device {Key} power state changed to {State}"` - Placeholders: Use curly brace syntax `{PropertyName}` - Purpose: Allows structured logging and analysis **RenderedMessage**: + - Format: Final human-readable message - Example: `"Device Display-Room1 power state changed to On"` - Content: Template with placeholders replaced by actual values - Purpose: Direct display to users **Level**: + - Values: One of the defined log levels (Fatal, Error, Warning, Information, Debug, Verbose) - Case: Exact case as defined in hierarchy - Purpose: Message classification and filtering **Properties**: + - Format: JSON object with key-value pairs - Content: Structured data related to the message - Optional: May be null or empty for simple messages @@ -154,15 +169,17 @@ Debug: Device [Display-Room1] sending command: Power On ### Common Property Fields **Device-Related Properties**: + ```json { "Key": "Display-Room1", - "DeviceType": "samsungMDC", + "DeviceType": "samsungMDC", "DeviceName": "Conference Room Display" } ``` **Command-Related Properties**: + ```json { "CommandType": "PowerOn", @@ -172,6 +189,7 @@ Debug: Device [Display-Room1] sending command: Power On ``` **Error-Related Properties**: + ```json { "ErrorCode": "ConnectionTimeout", @@ -181,6 +199,7 @@ Debug: Device [Display-Room1] sending command: Power On ``` **System-Related Properties**: + ```json { "SourceContext": "PepperDash.Essentials.Core.DeviceManager", @@ -194,16 +213,19 @@ Debug: Device [Display-Room1] sending command: Power On ### Device Filtering **Global Filter**: + - **Matches**: Messages with no Key property or Key = null - **Content**: System-wide events, framework operations - **Usage**: System health monitoring, startup/shutdown events **Device-Specific Filters**: + - **Matches**: Messages where Properties.Key matches selected device key - **Content**: All messages from that specific device - **Usage**: Device-specific troubleshooting **Multiple Device Filters**: + - **Logic**: OR operation (matches any selected device) - **Behavior**: Shows messages from any of the selected devices - **Usage**: Comparing behavior between related devices @@ -211,10 +233,12 @@ Debug: Device [Display-Room1] sending command: Power On ### Log Level Filtering **Single Level Selection**: + - Shows only messages at the selected severity level - Example: Selecting only "Error" shows error messages only **Multiple Level Selection**: + - **Logic**: OR operation (matches any selected level) - **Common combinations**: - Error + Warning: Problem identification @@ -224,32 +248,37 @@ Debug: Device [Display-Room1] sending command: Power On ### Text Search Filtering **Search Behavior**: + - **Case insensitive**: "ERROR" matches "error" and "Error" - **Partial matching**: "conn" matches "connection", "connected", "disconnect" - **Multiple terms**: Space-separated terms use AND logic - **Target fields**: MessageTemplate and RenderedMessage **Search Targets**: + - **MessageTemplate**: Raw template text with placeholders - **RenderedMessage**: Final formatted message text - **Not searched**: Properties object, Timestamp, Level **Search Examples**: -| Search Term | Matches | Usage | -|-------------|---------|-------| -| `power` | Any message containing "power" | Power-related events | -| `timeout` | Any message containing "timeout" | Communication timeouts | -| `display power` | Messages containing both "display" AND "power" | Display power events | -| `button press` | Messages containing both "button" AND "press" | Button interactions | + +| Search Term | Matches | Usage | +| --------------- | ---------------------------------------------- | ---------------------- | +| `power` | Any message containing "power" | Power-related events | +| `timeout` | Any message containing "timeout" | Communication timeouts | +| `display power` | Messages containing both "display" AND "power" | Display power events | +| `button press` | Messages containing both "button" AND "press" | Button interactions | ### Filter Combination Logic **Multiple Filters Applied**: + - **Logic**: AND operation (all conditions must match) - **Example**: Device="Display-Room1" AND Level="Error" AND Search="power" - **Result**: Only error-level power-related messages from Display-Room1 **Filter Priority**: + 1. **Minimum log level**: Applied first (server-side) 2. **Device filter**: Applied to client-side message list 3. **Log level filter**: Applied to remaining messages @@ -260,6 +289,7 @@ Debug: Device [Display-Room1] sending command: Power On ### Normal Message Rates by Level **Production System** (per minute): + - **Fatal**: 0 (should never occur in normal operation) - **Error**: 0-2 (occasional errors acceptable) - **Warning**: 1-10 (depends on system configuration) @@ -268,6 +298,7 @@ Debug: Device [Display-Room1] sending command: Power On - **Verbose**: 100-1000+ (if enabled, very high volume) **Development/Testing System** (per minute): + - Higher rates acceptable across all levels - Debug and Verbose levels commonly used - Error rates may be higher during testing @@ -275,17 +306,20 @@ Debug: Device [Display-Room1] sending command: Power On ### Volume Impact on Performance **Browser Performance**: + - **<100 messages/minute**: No noticeable impact - **100-500 messages/minute**: Slight impact on scrolling - **500+ messages/minute**: May cause browser lag - **1000+ messages/minute**: Significant performance impact **Network Impact**: + - **Average message size**: 200-500 bytes - **High volume impact**: Can consume significant bandwidth - **Multiple sessions**: Multiplies network load on processor **Processor Impact**: + - **Debug sessions**: Consume processor resources - **Multiple sessions**: Significant impact on system performance - **High log levels**: Verbose/Debug logging impacts all operations @@ -295,6 +329,7 @@ Debug: Device [Display-Room1] sending command: Power On ### Common Filter Combinations **Problem Identification**: + ``` Log Levels: Error + Warning Device: All or problematic area @@ -302,6 +337,7 @@ Search: (none initially, add specific terms as needed) ``` **Device Troubleshooting**: + ``` Log Levels: Information + Warning + Error Device: Specific device only @@ -309,6 +345,7 @@ Search: Terms related to suspected issue ``` **System Health Monitoring**: + ``` Log Levels: Warning + Error + Fatal Device: Global + critical devices @@ -316,13 +353,15 @@ Search: "timeout", "failed", "error" ``` **User Interaction Tracing**: + ``` Log Levels: Information + Warning + Error Device: Control panels + target devices Search: "button", "press", "command" ``` -**Network Issue Investigation**: +**Network Issue Investigation**: + ``` Log Levels: Warning + Error Device: All network-connected devices @@ -332,6 +371,7 @@ Search: "connection", "timeout", "network" ### Performance Optimization Filters **High-Traffic Monitoring**: + ``` Minimum Log Level: Warning (server-side) Log Levels: Warning + Error (client-side) @@ -340,9 +380,10 @@ Search: Specific error terms ``` **Baseline Performance Monitoring**: + ``` Minimum Log Level: Information (server-side) -Log Levels: Information + Warning + Error (client-side) +Log Levels: Information + Warning + Error (client-side) Device: Global only Search: (none) ``` @@ -352,6 +393,7 @@ Search: (none) ### Healthy System Patterns **Startup Sequence**: + ``` Information: System initializing Information: Loading configuration @@ -362,14 +404,16 @@ Information: System startup complete ``` **Normal Operation**: + ``` Information: Button [ButtonName] pressed -Information: Command sent to [DeviceKey]: [Command] +Information: Command sent to [DeviceKey]: [Command] Information: Device [DeviceKey] acknowledged command Information: Device [DeviceKey] status updated ``` **Clean Shutdown**: + ``` Information: System shutdown initiated Information: Device [DeviceKey] disconnecting @@ -380,6 +424,7 @@ Information: System shutdown complete ### Problem Patterns **Connection Issues**: + ``` Warning: Device [DeviceKey] connection timeout Warning: Device [DeviceKey] attempting reconnection @@ -388,6 +433,7 @@ Warning: Device [DeviceKey] attempting reconnection ``` **Command Failures**: + ``` Information: Command sent to [DeviceKey]: [Command] Warning: Device [DeviceKey] no response to command @@ -396,6 +442,7 @@ Warning: Device [DeviceKey] retrying command ``` **System Resource Issues**: + ``` Warning: High memory usage detected Warning: Thread pool exhaustion @@ -408,12 +455,14 @@ Fatal: System cannot continue ### RTK Query Integration **Log Level Filter Hook**: + ```typescript const { data: logLevels } = useGetMinimumLogLevelQuery(); const [setLogLevel] = useSetMinimumLogLevelMutation(); ``` **Filter State Management**: + ```typescript const [searchParams, setSearchParams] = useSearchParams(); const deviceFilters = searchParams.getAll('device'); @@ -422,23 +471,26 @@ const searchTerms = searchParams.getAll('searchText'); ``` **Message Filtering Logic**: + ```typescript const filteredMessages = useMemo(() => { - return messages.filter(message => { + return messages.filter((message) => { // Device filter - const deviceMatch = !deviceFilters.length || + const deviceMatch = + !deviceFilters.length || deviceFilters.includes(message.Properties?.Key || 'global'); - - // Log level filter - const levelMatch = !logLevelFilters.length || - logLevelFilters.includes(message.Level); - + + // Log level filter + const levelMatch = + !logLevelFilters.length || logLevelFilters.includes(message.Level); + // Text search - const textMatch = !searchTerms.length || - searchTerms.every(term => + const textMatch = + !searchTerms.length || + searchTerms.every((term) => message.RenderedMessage.toLowerCase().includes(term.toLowerCase()) ); - + return deviceMatch && levelMatch && textMatch; }); }, [messages, deviceFilters, logLevelFilters, searchTerms]); diff --git a/docs/reference/ui-components.md b/docs/reference/ui-components.md index 72d76e5..211cfd1 100644 --- a/docs/reference/ui-components.md +++ b/docs/reference/ui-components.md @@ -13,25 +13,29 @@ This document provides detailed information about every UI element, its purpose, **Purpose**: Primary navigation between application sections **Elements**: + - **Brand**: "Essentials Debugger" - Always visible, non-clickable - **Navigation Links**: Six main sections accessible via top menu **Navigation Links**: -| Link | Route | Purpose | -|------|-------|---------| -| Home | `/home` | Welcome page and application starting point | -| Debug Console | `/console` | Real-time system monitoring and debugging | -| Versions | `/versions` | View loaded assemblies and version information | -| Config File | `/config` | View complete merged configuration | -| Devices | `/devices` | Browse and inspect configured devices | -| Types | `/types` | View available device types and descriptions | + +| Link | Route | Purpose | +| ------------- | ----------- | ---------------------------------------------- | +| Home | `/home` | Welcome page and application starting point | +| Debug Console | `/console` | Real-time system monitoring and debugging | +| Versions | `/versions` | View loaded assemblies and version information | +| Config File | `/config` | View complete merged configuration | +| Devices | `/devices` | Browse and inspect configured devices | +| Types | `/types` | View available device types and descriptions | **Visual States**: + - **Active**: Link text shows in secondary color when on that page - **Inactive**: Standard link appearance - **Hover**: Standard link hover effect **Responsive Behavior**: + - Collapses to hamburger menu on mobile devices - Maintains horizontal layout on desktop and tablet @@ -45,25 +49,30 @@ This document provides detailed information about every UI element, its purpose, **Purpose**: Control debug session state and system operations #### Start/Stop Session Buttons + - **Start Debug Session**: Initiates WebSocket connection for real-time messages - **Stop Debug Session**: Closes WebSocket connection and stops message flow - **Visual State**: Blue primary buttons, disabled when appropriate #### System Control Buttons + - **Load Config**: Manually reload configuration (only available when "Do Not Load Config" is checked) - **Restart Program**: Complete system restart with confirmation modal #### Configuration Controls + - **Do Not Load Config on Next Boot**: Checkbox to control configuration loading behavior - **State**: Checked = don't load config, Unchecked = load config normally #### Minimum Log Level Dropdown + - **Purpose**: Set minimum severity level for captured messages - **Options**: Verbose, Debug, Information, Warning, Error, Fatal - **Default**: Information - **Behavior**: Dropdown updates immediately, affects new messages only #### Message Counter + - **Display**: "Message Count: [number]" - **Purpose**: Shows total messages received in current session - **Updates**: Real-time during active debug session @@ -71,31 +80,37 @@ This document provides detailed information about every UI element, its purpose, ### Filtering Components #### Search Box + **Component**: `FilterSearchText` **Purpose**: Free-text search within debug messages **Behavior**: + - **Debounce**: 1-second delay before applying search - **Multiple terms**: Space-separated terms use AND logic - **Case insensitive**: Searches are not case-sensitive - **Partial matching**: Finds partial word matches **Search targets**: + - Message template text - Rendered message text - Device keys and names #### Device Filter Dropdown + **Component**: `DeviceFilterDropdown` **Purpose**: Filter messages by source device and set a per-device minimum log level **Options**: + - **Global**: System-wide messages not tied to specific devices - **Device entries**: All configured devices, sorted alphabetically by name (or key when no name is set) - **Multiple selection**: Checkbox interface allows multiple devices - **Badge indicator**: Shows count of checked devices **Per-Device Minimum Log Level**: + - When a device is checked, a level dropdown appears inline next to its name - Default level when first checked: `Information` - Available levels: Fatal, Error, Warning, Information, Debug, Verbose @@ -107,9 +122,11 @@ This document provides detailed information about every UI element, its purpose, **State**: Stored in Redux `debugConsole` slice (`checkedDevices` and `deviceLevels`); persists across route navigation **Filter Combined With**: + - Text search (AND logic: both conditions must be satisfied) #### Clear Filters Button + **Purpose**: Reset all debug console filters (checked devices, per-device levels, and search text) to their initial empty state **Trigger**: "Clear Filters" button in the debug filters toolbar @@ -120,19 +137,23 @@ This document provides detailed information about every UI element, its purpose, ## API Paths Components ### API Paths Table + **Location**: API Paths page (`/:appId/apiPaths`) **Purpose**: Display all available REST API routes exposed by the processor **Layout**: + - **Two columns**: Name and URL - **Sortable**: Alphabetically sorted by route name - **Striped rows**: Bootstrap `table-striped` styling **Interaction**: + - **Click row**: Selects the route and opens the detail drawer - **Selected row**: Highlighted with `table-primary` ### API Path Detail Drawer + **Component**: `ApiPathDetailDrawer` **Purpose**: Show complete detail for a selected API route @@ -140,11 +161,13 @@ This document provides detailed information about every UI element, its purpose, **Trigger**: Click on any route row **Content Sections**: + 1. **Name**: Route name 2. **URL**: Full URL as a clickable link (opens in new tab) 3. **Data Token Name**: Shown only when present **Behavior**: + - No backdrop (main content remains interactive) - Close button dismisses the drawer @@ -153,6 +176,7 @@ This document provides detailed information about every UI element, its purpose, ## Routing Components ### Routing Diagram + **Component**: `Routing` **Location**: Routing page (`/:appId/routing`) **Purpose**: Interactive, auto-laid-out signal routing diagram showing devices, ports, tie lines, and (on supported systems) live current-source feedback @@ -160,13 +184,15 @@ This document provides detailed information about every UI element, its purpose, **Technology**: React Flow (`@xyflow/react`) canvas with Dagre auto-layout (left-to-right column layout, recomputed whenever the device/filter set changes; manually dragged node positions are preserved across live feedback updates) **Version requirements**: -| PepperDashEssentials.dll version | Behavior | -|-----------------------------------|----------| -| < 2.29 | Routing page shows "Routing feature is not available for this version." | -| 2.29 – 2.x | Static diagram only: devices, ports, and tie lines render, but there is no live current-source feedback, no internal route curves, no Live/Offline badge activity, and no multiview layout panels | -| 3.0+ | Full functionality: live WebSocket feedback, signal path tracing, and multiview layout panels (all described below) | + +| PepperDashEssentials.dll version | Behavior | +| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| < 2.29 | Routing page shows "Routing feature is not available for this version." | +| 2.29 – 2.x | Static diagram only: devices, ports, and tie lines render, but there is no live current-source feedback, no internal route curves, no Live/Offline badge activity, and no multiview layout panels | +| 3.0+ | Full functionality: live WebSocket feedback, signal path tracing, and multiview layout panels (all described below) | **Elements**: + - **Device Nodes**: Each routing device shown as a card with input ports listed on the left and output ports on the right (see **Device Node Card** below) - **Tie Line Edges**: Connections between device ports, color-coded by signal type (see **Tie Line Edges** below) - **MiniMap**: Overview map (bottom-right) for orientation in large diagrams @@ -174,13 +200,14 @@ This document provides detailed information about every UI element, its purpose, - **Multiview Layout Panels**: Optional floating windows showing a device's current tile layout (see below) **Signal Type Colors**: -| Signal Type | Color | -|-------------|-------| -| AudioVideo | Purple (#6f42c1) | -| Video | Blue (#0d6efd) | -| Audio / Audio, SecondaryAudio | Red (#dc3545) | -| UsbOutput / UsbInput / UsbOutput, UsbInput | Orange (#fd7e14) | -| Any other signal type | Gray (#adb5bd) fallback | + +| Signal Type | Color | +| ------------------------------------------ | ----------------------- | +| AudioVideo | Purple (#6f42c1) | +| Video | Blue (#0d6efd) | +| Audio / Audio, SecondaryAudio | Red (#dc3545) | +| UsbOutput / UsbInput / UsbOutput, UsbInput | Orange (#fd7e14) | +| Any other signal type | Gray (#adb5bd) fallback | ### Toolbar @@ -203,6 +230,7 @@ A single toolbar strip above the diagram canvas holds all filtering and connecti ### Device Node Card Each device is drawn as a card with: + - **Header**: The device's display name (falls back to its key if unnamed), with the key shown as a smaller subtitle when a name is present. Hovering shows the key as a tooltip. - **Layout toggle button** (small tile icon, header, only shown for devices with an active multiview canvas): Opens/closes a floating **Multiview Layout Panel** for that device (see below) - **Hide button** (`×`, header): Hides just this one device from the canvas (equivalent to unchecking it in the Devices filter dropdown) @@ -241,47 +269,56 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ### Message Display Components #### Message List Container + **Component**: `ConsoleWindow` **Purpose**: Display filtered debug messages in tabular format **Layout**: + - **Header row**: Fixed column headers (Timestamp, Key, Level, Message) - **Message rows**: Scrollable list of debug messages - **Responsive**: Columns adjust for different screen sizes **Column Details**: -| Column | Width | Content | Behavior | -|--------|-------|---------|----------| -| Timestamp | 6 units | Full timestamp with milliseconds | Fixed width, truncated if needed | -| Key | 3 units | Device key or "global" | Fixed width | -| Level | 2 units | Log severity level | Fixed width | -| Message | 13 units | Rendered message text | Truncated with ellipsis, expandable on click | + +| Column | Width | Content | Behavior | +| --------- | -------- | -------------------------------- | -------------------------------------------- | +| Timestamp | 6 units | Full timestamp with milliseconds | Fixed width, truncated if needed | +| Key | 3 units | Device key or "global" | Fixed width | +| Level | 2 units | Log severity level | Fixed width | +| Message | 13 units | Rendered message text | Truncated with ellipsis, expandable on click | #### Individual Message Rows + **Visual States**: + - **Default**: Standard row appearance - **Hover**: Subtle background highlight - **Selected**: Primary color background with white text - **Clickable**: Cursor changes to pointer **Interaction**: + - **Click**: Opens message detail drawer - **Selection**: Only one message can be selected at a time - **Keyboard**: Not currently supported #### Scroll Container + **Component**: `ScrollToBottom` **Purpose**: Auto-scroll to newest messages **Features**: + - **Auto-follow**: Automatically scrolls to bottom for new messages -- **Manual control**: User can scroll up to view history +- **Manual control**: User can scroll up to view history - **Follow button**: Appears when user scrolls up, click to resume auto-follow - **Performance**: Optimized for high message volumes ### Message Detail Components #### Message Detail Drawer + **Component**: `LogMessageDetailDrawer` **Purpose**: Show complete information for selected message @@ -289,18 +326,21 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), **Trigger**: Click on any message row **Content Sections**: + 1. **Timestamp**: Full timestamp with timezone information 2. **Rendered Message**: Complete formatted message text 3. **Message Template**: Raw message template with placeholders 4. **Properties**: JSON-formatted structured data **Behavior**: + - **Overlay**: Appears over main content, does not push content aside - **Backdrop**: No backdrop (can interact with main content) - **Close methods**: Close button (X) or programmatic close - **Responsive**: Adjusts width on mobile devices **Properties Display**: + - **Format**: JSON with syntax highlighting and indentation - **Content**: All structured data associated with the message - **Common fields**: Key, SourceContext, CommandType, etc. @@ -310,21 +350,25 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ## Configuration Display Components ### Configuration Viewer + **Location**: Config File page **Purpose**: Display complete merged configuration **Display Format**: + - **JSON**: Pretty-printed with proper indentation - **Monospace font**: Fixed-width font for code readability - **Scrollable**: Full height scrolling for large configurations - **Selectable**: Text can be selected and copied **Loading States**: + - **Loading**: Shows "Loading..." text while fetching configuration - **Loaded**: Full configuration display - **Error**: Error message if configuration cannot be loaded **Performance**: + - **Large files**: Handles configurations with thousands of lines - **Memory efficient**: Uses browser's native text rendering - **Search**: Browser's built-in search (Ctrl+F) works within configuration @@ -334,30 +378,36 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ## Device Management Components ### Device List + **Location**: Left side of Devices page **Purpose**: Display all configured devices for selection **Layout**: + - **Header row**: "Key" and "Name" column headers - **Device rows**: All configured devices with Key and Name - **Fixed width**: Consistent column widths **Interaction**: + - **Click**: Select device to show details - **Hover**: Visual feedback on hover - **Selection**: Single selection only **Content**: + - **Key**: Technical identifier used in configuration - **Name**: Human-readable device name - **Sorting**: Devices appear in configuration order ### Device Detail Panel + **Location**: Right side of Devices page **Purpose**: Display detailed information about selected device **Current State**: Placeholder implementation **Planned Content**: + - Device status and connection state - Real-time property values - Available methods and commands @@ -369,29 +419,35 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ## Information Display Components ### Versions List + **Location**: Versions page **Purpose**: Display all loaded software assemblies and versions **Layout**: + - **Sticky header**: Column headers remain visible during scroll - **Sortable**: Alphabetically sorted by assembly name - **Two columns**: Name and Version **Content**: + - **Name**: Full assembly name including namespace - **Version**: Complete version string with build information - **Filtering**: No built-in filtering (use browser search) -### Types List +### Types List + **Location**: Types page **Purpose**: Display all available device types and descriptions **Layout**: + - **Three columns**: Type Name, Class Type, Description - **Sticky header**: Headers remain visible during scroll - **Sortable**: Alphabetically sorted by type name **Content**: + - **Type Name**: Configuration identifier for device type - **Class Type**: .NET class that implements the device - **Description**: Human-readable description of device purpose @@ -401,16 +457,19 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ## Modal Components ### Restart Confirmation Modal + **Component**: `RestartConfirmModal` **Trigger**: Click "Restart Program" button **Purpose**: Confirm system restart action **Content**: + - **Title**: "Restart Program" - **Message**: "Are you sure you want to restart the program?" - **Actions**: Cancel (light button) and Restart (danger button) **Behavior**: + - **Modal backdrop**: Prevents interaction with background - **Keyboard**: ESC key closes modal - **Focus management**: Focus moves to modal when opened @@ -420,16 +479,19 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ## Form Components ### Checkboxes + **Usage**: Configuration options like "Do Not Load Config on Next Boot" **Style**: Bootstrap form-check styling **States**: Checked, unchecked, disabled (when appropriate) ### Dropdowns + **Usage**: Filters, log level selection, minimum log level **Style**: Bootstrap dropdown with custom styling **Features**: Badge indicators for active selections, scrollable menus ### Search Inputs + **Usage**: Message filtering and search **Features**: Debounced input, placeholder text, clear functionality **Styling**: Form control with border styling @@ -439,10 +501,12 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ## Layout Components ### Header-Scroller-Footer Pattern + **Component**: `HeaderScrollerFooter` **Purpose**: Consistent layout with fixed header/footer and scrollable content **Usage**: + - **Header**: Fixed elements like page titles and controls - **Scroller**: Main content area that scrolls when content overflows - **Footer**: Fixed elements like status bars or action buttons @@ -450,10 +514,12 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), **Responsive**: Adapts to different screen sizes and orientations ### Filter Headers + **Component**: `ListFiltersHeader` **Purpose**: Consistent layout for filter controls across different sections **Elements**: + - **Search box**: Text-based filtering - **Filter dropdowns**: Categorical filtering - **Clear button**: Reset all filters @@ -464,7 +530,9 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ## Visual Design System ### Color Scheme + **Primary Colors**: + - Primary: #4466a2 (Blue) - Secondary: #7f7f7f (Gray) - Success: #00b5aa (Teal) @@ -472,22 +540,26 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), - Danger: #d90169 (Red) **Background Colors**: + - Body: #e9edf3 (Light Gray) - White: #ffffff - Very Light: #f5f5f5 ### Typography + **Base Font**: Roboto, 'Helvetica Neue', sans-serif **Base Size**: 0.875rem (14px) **Line Height**: Default browser settings **Monospace**: For code/configuration display ### Spacing + **Grid System**: 24-column Bootstrap grid **Standard Spacing**: Bootstrap spacing utilities (mb-2, p-2, etc.) **Component Gaps**: Consistent spacing between related elements ### Interactive States + **Buttons**: Hover, focus, active, and disabled states **Links**: Hover and active states with underline **Form Controls**: Focus states with border color changes @@ -498,16 +570,19 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ## Accessibility Features ### Keyboard Navigation + - **Tab order**: Logical tab sequence through interactive elements - **Focus indicators**: Visible focus states on all interactive elements - **Modal management**: Focus traps and restoration ### Screen Reader Support + - **Semantic HTML**: Proper use of headings, lists, and form labels - **ARIA labels**: Where needed for complex interactions - **Status announcements**: For dynamic content updates ### Visual Accessibility + - **Color contrast**: Meets WCAG guidelines for text and background contrast - **Focus indicators**: High contrast focus outlines - **Text scaling**: Responsive to browser zoom and text size preferences @@ -517,16 +592,19 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ## Performance Characteristics ### Rendering Performance + - **Virtual scrolling**: Not implemented (could benefit large message lists) - **Debounced interactions**: Search and filter inputs use appropriate delays - **Efficient updates**: React optimizations for frequent message updates ### Memory Management + - **Message accumulation**: Messages accumulate in browser memory during session - **Clear mechanism**: Page refresh clears accumulated messages - **Large datasets**: May require manual session management for very high message volumes ### Network Efficiency + - **WebSocket connection**: Single persistent connection for debug messages - **API calls**: Minimal API calls for configuration and device data - **Caching**: Browser caching for static resources @@ -536,18 +614,21 @@ For devices that implement a multiview/window layout (e.g. a multiview decoder), ## Browser Compatibility ### Supported Browsers + - **Chrome**: Version 70+ - **Firefox**: Version 65+ - **Safari**: Version 12+ - **Edge**: Version 79+ ### Required Features + - **WebSocket support**: For real-time debug messages - **ES6 support**: Modern JavaScript features - **CSS Grid/Flexbox**: For responsive layouts - **JSON support**: For configuration display ### Mobile Support + - **Responsive design**: Adapts to mobile screen sizes - **Touch interactions**: Touch-friendly button and link sizes - **Mobile browsers**: Same browser version requirements as desktop diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md index fe078fd..4aeb2d3 100644 --- a/docs/tutorials/README.md +++ b/docs/tutorials/README.md @@ -7,11 +7,13 @@ These tutorials are designed to take you from beginner to competent user through ## 🚀 Getting Started ### [Getting Started Tutorial](./getting-started.md) + **Time**: 15-20 minutes | **Level**: Beginner Your first steps with the PepperDash Essentials Web Config App. Learn to access the application, navigate the interface, and perform basic operations. **You'll learn**: + - How to access the web application securely - Navigate through all main sections - Start your first debug session @@ -25,11 +27,13 @@ Your first steps with the PepperDash Essentials Web Config App. Learn to access ## 🔍 Core Features ### [Debug Console Tutorial](./debug-console-basics.md) + **Time**: 25-30 minutes | **Level**: Intermediate Master the Debug Console - the most powerful feature for system monitoring and troubleshooting. Learn advanced filtering, message interpretation, and systematic troubleshooting approaches. **You'll learn**: + - Advanced filtering and search techniques - How to interpret different log levels and message types - Managing debug sessions effectively @@ -39,11 +43,13 @@ Master the Debug Console - the most powerful feature for system monitoring and t **Prerequisites**: Completed Getting Started Tutorial ### [Device Management Tutorial](./device-management-basics.md) + **Time**: 20-25 minutes | **Level**: Intermediate Learn to effectively browse, understand, and work with devices in your PepperDash Essentials system. Understand device types, relationships, and how to use device information for troubleshooting. **You'll learn**: + - How to browse and identify devices - Understanding device properties and capabilities - Interpreting device types and their purposes @@ -62,7 +68,7 @@ We recommend following this sequence for the best learning experience: 1. Getting Started Tutorial (Required) ↓ 2. Debug Console Tutorial (Recommended) - ↓ + ↓ 3. Device Management Tutorial (Recommended) ``` @@ -104,12 +110,15 @@ Our tutorials follow these principles: Once you've completed the tutorials: ### For Specific Problems + Head to **[How-to Guides](../how-to/)** for step-by-step solutions to common issues ### For Technical Details + Consult the **[Reference](../reference/)** documentation for complete technical information ### For Deeper Understanding + Read **[Explanation](../explanation/)** articles to understand system design and concepts --- @@ -117,18 +126,21 @@ Read **[Explanation](../explanation/)** articles to understand system design and ## 📞 Getting Help **Stuck on a tutorial?** + - Re-read the prerequisites to ensure you have everything needed - Check that your system is running and accessible - Try the troubleshooting section at the end of each tutorial **Want to suggest improvements?** + - These tutorials are designed to be practical and helpful - Your feedback helps us improve the learning experience **Need more advanced training?** + - The tutorials cover essential skills for most users - For specialized or advanced use cases, consult the reference documentation --- -*Remember: Tutorials are for learning, not quick problem-solving. Take your time to understand each concept before moving on. The investment in foundational knowledge will pay off in your daily work!* +_Remember: Tutorials are for learning, not quick problem-solving. Take your time to understand each concept before moving on. The investment in foundational knowledge will pay off in your daily work!_ diff --git a/docs/tutorials/debug-console-basics.md b/docs/tutorials/debug-console-basics.md index ea370df..6a0f8d3 100644 --- a/docs/tutorials/debug-console-basics.md +++ b/docs/tutorials/debug-console-basics.md @@ -4,7 +4,8 @@ **Time required**: 25-30 minutes -**Prerequisites**: +**Prerequisites**: + - Completed the [Getting Started Tutorial](./getting-started.md) - Access to a running PepperDash Essentials system - Basic familiarity with the web app interface @@ -26,8 +27,9 @@ 3. **Generate various activities** on your system to see different message types **Log levels you'll encounter** (from most to least critical): + - **Error**: System failures, connection problems, critical issues -- **Warning**: Potential issues, deprecated features, recoverable problems +- **Warning**: Potential issues, deprecated features, recoverable problems - **Information**: Normal operations, status changes, confirmations - **Debug**: Detailed technical information for developers - **Verbose**: Extremely detailed trace information @@ -53,7 +55,8 @@ 4. **Set a per-device minimum level**: Once a device is checked, an inline level dropdown appears next to its name. Change it to `Warning` to suppress that device's `Information` and `Debug` messages while keeping other devices at a lower threshold 5. **Combine multiple devices** each with their own levels -**Practical example**: +**Practical example**: + - If one display is flooding the console with `Information` messages, check it and set its level to `Warning` - Keep other devices at `Information` so you see their normal activity @@ -68,6 +71,7 @@ ### Step 5: Understand Filter State Persistence Filter selections are stored in Redux state: + - **Persists across navigation**: Switching to Versions and back preserves your filters - **Resets on page reload**: Refreshing the browser clears all filter state (along with the login session) - **Clear Filters button**: Resets device selections, per-device levels, and search text in one click @@ -79,6 +83,7 @@ Filter selections are stored in Redux state: Real systems generate patterns of messages. Learn to recognize them: 1. **Normal startup sequence**: + ``` Information: Device [DisplayRoom1] initializing Information: Device [DisplayRoom1] connection established @@ -86,6 +91,7 @@ Real systems generate patterns of messages. Learn to recognize them: ``` 2. **Error patterns**: + ``` Warning: Device [DisplayRoom1] connection timeout Error: Device [DisplayRoom1] failed to respond @@ -110,6 +116,7 @@ Real systems generate patterns of messages. Learn to recognize them: - Timing information **Common properties you'll see**: + - `Key`: The device that generated the message - `SourceContext`: Which part of the code generated the message - `CommandType`: What type of command was executed @@ -159,11 +166,12 @@ Real systems generate patterns of messages. Learn to recognize them: 4. **Check message timestamps** to see when problems started **Expected findings**: + - Connection timeout errors - Power command confirmations (or lack thereof) - Network connectivity issues -### Scenario 2: System Running Slowly +### Scenario 2: System Running Slowly **Goal**: Identify performance bottlenecks @@ -188,6 +196,7 @@ Real systems generate patterns of messages. Learn to recognize them: ## Best Practices Summary ### Do's: + - ✅ Start with broad filters, then narrow down - ✅ Use appropriate log levels for your task - ✅ Stop sessions when not actively debugging @@ -195,6 +204,7 @@ Real systems generate patterns of messages. Learn to recognize them: - ✅ Use search terms related to your specific problem ### Don'ts: + - ❌ Leave debug sessions running indefinitely - ❌ Use "Verbose" level unless absolutely necessary - ❌ Ignore the message count - it indicates system load @@ -227,16 +237,19 @@ You now have advanced skills in using the Debug Console: ## Troubleshooting This Tutorial **Not seeing expected message types?** + - Your system may be configured with a higher minimum log level - Try generating more system activity - Check if your devices are actually connected and functioning **Too many messages to follow?** + - Use more restrictive filtering - Increase the minimum log level temporarily - Focus on one device or message type at a time **Messages seem delayed?** + - This can indicate network latency or system load - Check your network connection - Consider if other users are also connected diff --git a/docs/tutorials/device-management-basics.md b/docs/tutorials/device-management-basics.md index 1767204..1d4359c 100644 --- a/docs/tutorials/device-management-basics.md +++ b/docs/tutorials/device-management-basics.md @@ -4,7 +4,8 @@ **Time required**: 20-25 minutes -**Prerequisites**: +**Prerequisites**: + - Completed the [Getting Started Tutorial](./getting-started.md) - Access to a system with configured devices - Basic understanding of the web app interface @@ -30,12 +31,14 @@ Each device has two important identifiers: -**Key**: +**Key**: + - Unique technical identifier used in configuration - Often follows naming conventions like "Display-01" or "Codec-Main" - Used internally by the system for routing commands **Name**: + - Human-friendly display name - What users typically see in interfaces - Often describes location or function like "Conference Room Display" @@ -81,9 +84,10 @@ Each device has two important identifiers: - Currently shows basic "Device Detail" header - This is where detailed device information would appear -*Note: The current implementation shows a placeholder. In a fully implemented system, you would see:* +_Note: The current implementation shows a placeholder. In a fully implemented system, you would see:_ **Expected device details**: + - Current status and connection state - Device properties (power state, input selection, volume, etc.) - Available methods (commands you can send) @@ -99,6 +103,7 @@ Even with the current interface, you can gather valuable information: 3. **Key format**: Indicates how the system organizes devices **Troubleshooting workflow**: + 1. Check if the problematic device appears in the device list 2. Note its Key and Name for reference in debug messages 3. Use the Key to filter debug console messages for that specific device @@ -144,15 +149,17 @@ Even with the current interface, you can gather valuable information: Real systems have devices that work together: **Common relationships**: + - **Display + Audio**: TV with sound system - **Touch Panel + Devices**: Control interface managing multiple devices - **Switcher + Endpoints**: Video routing with sources and destinations - **Codec + Peripherals**: Video conferencing system with cameras and microphones **Look for these patterns** in your device list: + - Similar names with different suffixes (-01, -02, etc.) - Hierarchical naming (Room1-Display, Room1-Audio) -- Functional grouping (Boardroom-*, Training-*) +- Functional grouping (Boardroom-_, Training-_) ### Step 8: Configuration Insights @@ -164,6 +171,7 @@ The device list reveals configuration decisions: 4. **Missing devices**: Are expected devices configured? **Use this information to**: + - Understand system complexity - Identify potential configuration issues - Plan troubleshooting approaches @@ -174,19 +182,22 @@ The device list reveals configuration decisions: ## Best Practices for Device Management ### Investigation Workflow: + 1. ✅ **Start broad**: Review the complete device list -2. ✅ **Identify patterns**: Look for naming conventions and groupings +2. ✅ **Identify patterns**: Look for naming conventions and groupings 3. ✅ **Focus specific**: Select devices related to your current task 4. ✅ **Cross-reference**: Use device Keys in debug console for detailed analysis 5. ✅ **Document findings**: Note device relationships and issues ### Troubleshooting Tips: + - ✅ Use device Keys (not Names) when filtering debug messages - ✅ Look for similar devices to compare expected vs. actual behavior - ✅ Check device types to understand what functionality should be available - ✅ Note device naming patterns to find related components ### Don'ts: + - ❌ Assume device Names match debug message identifiers (use Keys) - ❌ Ignore devices that seem unrelated to your current problem - ❌ Forget to check if expected devices are actually configured @@ -195,12 +206,14 @@ The device list reveals configuration decisions: ## Integration with Other Features ### Connecting Device Management to Debug Console: + 1. **Identify problem device** in device list 2. **Note the device Key** 3. **Filter debug console** to that specific device 4. **Analyze messages** for that device's behavior ### Using Configuration Data: + 1. **Check device list** for what's configured 2. **View config file** to see detailed device settings 3. **Compare types list** to understand available capabilities @@ -222,11 +235,13 @@ You now understand device management fundamentals: ## Current Limitations and Future Enhancements **Current interface limitations**: + - Device detail panel shows placeholder content - No real-time device status information - Limited interaction capabilities **In enhanced versions, you might see**: + - Live device status and properties - Command sending capabilities - Device method execution @@ -242,16 +257,19 @@ You now understand device management fundamentals: ## Troubleshooting This Tutorial **No devices showing?** + - Check that your system is properly configured - Verify you're connected to the right processor - Confirm the Essentials framework is running **Device names don't make sense?** + - This reflects how your system was configured - Contact your system administrator for naming conventions - Use Keys for technical references, Names for user communication **Can't find expected devices?** + - They may not be configured in the system - Check the configuration file for more details - Verify physical device connections and power diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md index cee8566..e37a4e5 100644 --- a/docs/tutorials/getting-started.md +++ b/docs/tutorials/getting-started.md @@ -4,7 +4,8 @@ **Time required**: 15-20 minutes -**Prerequisites**: +**Prerequisites**: + - Access to a PepperDash Essentials processor on your network - Valid credentials for the processor - Basic understanding of network connectivity @@ -57,39 +58,48 @@ The application has several main sections accessible from the top navigation: ### Versions + - Lists all loaded software assemblies and their versions - Useful for verifying what software is running ### API Paths + - Shows all REST API routes available on the processor - Click a route row to see its full URL and details ### Initialization Exceptions + - Only visible when PepperDashEssentials.dll ≥ 3.0 - Lists any exceptions from system startup ### Debug Console + - Real-time log messages from your system - The most powerful feature for troubleshooting ### Config File + - Shows the complete merged configuration - Displays the JSON structure of your system setup ### Devices + - Lists all configured devices in your system - Allows inspection of device properties and methods ### Types + - Shows all supported device types - Useful for understanding what devices can be configured ### Routing + - Visual diagram of signal routing between devices and tie lines, color-coded by signal type - Click a tie line, device, or multiview tile to trace and highlight its full signal path - Shows live current-source feedback on systems running PepperDashEssentials.dll 3.0+ ### Mobile Control + - Management interface for connected mobile control clients **Try this**: Click through each navigation item to see the different sections. @@ -153,12 +163,12 @@ Let’s learn to filter messages: - Click **Clear Filters** to reset the device selections and search text - Filter selections are saved in memory — navigating to another page and returning preserves them -3. **Filter by log level** +4. **Filter by log level** - Click the "Log Level" dropdown - Try selecting only "Error" and "Warning" to see problems - This helps focus on issues that need attention -4. **Clear filters** +5. **Clear filters** - Click the "Clear" button to remove all filters - All messages will be visible again @@ -202,16 +212,19 @@ Now that you understand the basics, you can: ## Troubleshooting **Can't access the web app?** + - Verify the processor IP address - Check network connectivity - Ensure the processor is powered on and running **No debug messages appearing?** + - Verify the debug session started successfully - Check if your system is generating activity - Try reloading the page and starting a new session **Browser security warnings?** + - This is normal for internal devices with self-signed certificates - Safe to proceed on your internal network - Don't ignore these warnings on public networks diff --git a/index.html b/index.html index 8a4d1a6..4954474 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/App.test.tsx b/src/App.test.tsx index 37136d0..2bf7adc 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -1,21 +1,21 @@ -import { render, screen } from "@testing-library/react"; -import { Provider } from "react-redux"; -import { MemoryRouter } from "react-router-dom"; -import { expect, it } from "vitest"; -import App from "./App"; -import { store } from "./store/store"; +import { render, screen } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { MemoryRouter } from 'react-router-dom'; +import { expect, it } from 'vitest'; +import App from './App'; +import { store } from './store/store'; -it("renders the help page inside the app shell", () => { +it('renders the help page inside the app shell', () => { render( - + - , + ); expect( - screen.getByRole("heading", { + screen.getByRole('heading', { name: /PepperDash Essentials Web Config App Documentation/i, - }), + }) ).toBeInTheDocument(); }); diff --git a/src/App.tsx b/src/App.tsx index 20f4cc3..ff83e01 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,30 +1,36 @@ -import { Suspense, useRef } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { Navigate, Route, Routes } from "react-router-dom"; +import { Suspense, useRef } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Navigate, Route, Routes } from 'react-router-dom'; import { ApiPaths } from './features/ApiPaths'; -import ConfigFile from "./features/ConfigFile"; -import DebugConsole from "./features/DebugConsole/DebugConsole"; -import DeviceList from "./features/DeviceList"; -import ErrorBoundary from "./features/ErrorBoundary"; -import Help from "./features/Help/Help"; -import InitializationExceptions from "./features/InitializationExceptions"; -import LoginForm from "./features/LoginForm"; -import MainLayout from "./features/MainLayout"; +import ConfigFile from './features/ConfigFile'; +import DebugConsole from './features/DebugConsole/DebugConsole'; +import DeviceList from './features/DeviceList'; +import ErrorBoundary from './features/ErrorBoundary'; +import Help from './features/Help/Help'; +import InitializationExceptions from './features/InitializationExceptions'; +import LoginForm from './features/LoginForm'; +import MainLayout from './features/MainLayout'; import MobileControl from './features/MobileControl'; -import RequireAuth from "./features/RequireAuth"; +import RequireAuth from './features/RequireAuth'; import Routing from './features/Routing'; -import Types from "./features/Types"; -import Versions from "./features/Versions"; +import Types from './features/Types'; +import Versions from './features/Versions'; import { useGetDebugSessionMutation, useStopDebugSessionMutation, -} from "./store/apiSlice"; -import { AppDispatch, RootState } from "./store/store"; -import { messagesCleared, WS_CONNECT, WS_DISCONNECT } from "./store/websocketSlice"; +} from './store/apiSlice'; +import { AppDispatch, RootState } from './store/store'; +import { + messagesCleared, + WS_CONNECT, + WS_DISCONNECT, +} from './store/websocketSlice'; function App() { const dispatch = useDispatch(); - const isConnected = useSelector((state: RootState) => state.websocket.isConnected); + const isConnected = useSelector( + (state: RootState) => state.websocket.isConnected + ); const [startSession] = useGetDebugSessionMutation(); const [stopSession] = useStopDebugSessionMutation(); @@ -39,7 +45,11 @@ function App() { const res = await startSession({ appId }).unwrap(); // The server already picks the URL on the browser's side of the network const { url, fallbackUrl } = res; - console.log("Joining debug session at " + url + (fallbackUrl ? " (fallback: " + fallbackUrl + ")" : "")); + console.log( + 'Joining debug session at ' + + url + + (fallbackUrl ? ' (fallback: ' + fallbackUrl + ')' : '') + ); dispatch({ type: WS_CONNECT, payload: { url, fallbackUrl } }); } finally { joiningRef.current = false; @@ -47,7 +57,7 @@ function App() { }; const stop = (appId: string) => { - console.log("Stopping debug session"); + console.log('Stopping debug session'); dispatch({ type: WS_DISCONNECT }); if (!appId) return; stopSession({ appId }); @@ -61,34 +71,40 @@ function App() { - } /> - } /> - } /> - - } /> - }> - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - } - /> + } /> + } /> + } /> + + } /> + } + > + }> + } /> + } /> + } + /> + } /> + } /> + } /> + } /> + } /> + + } + /> + - diff --git a/src/features/ApiPathDetailDrawer.tsx b/src/features/ApiPathDetailDrawer.tsx index 51fd591..8001029 100644 --- a/src/features/ApiPathDetailDrawer.tsx +++ b/src/features/ApiPathDetailDrawer.tsx @@ -1,5 +1,5 @@ -import { Offcanvas } from "react-bootstrap"; -import { Route } from "../store/apiSlice"; +import { Offcanvas } from 'react-bootstrap'; +import { Route } from '../store/apiSlice'; const ApiPathDetailDrawer = ({ show, @@ -28,7 +28,11 @@ const ApiPathDetailDrawer = ({ diff --git a/src/features/ApiPaths.tsx b/src/features/ApiPaths.tsx index 4fc88d1..99156d3 100644 --- a/src/features/ApiPaths.tsx +++ b/src/features/ApiPaths.tsx @@ -4,10 +4,11 @@ import useAppParams from '../shared/hooks/useAppParams'; import { Route, useGetPathsQuery } from '../store/apiSlice'; import ApiPathDetailDrawer from './ApiPathDetailDrawer'; - export const ApiPaths = () => { const { appId } = useAppParams(); - const { data: apiPathData, isLoading } = useGetPathsQuery(appId ? { appId } : skipToken); + const { data: apiPathData, isLoading } = useGetPathsQuery( + appId ? { appId } : skipToken + ); const [showDrawer, setShowDrawer] = useState(false); const [selectedRoute, setSelectedRoute] = useState(); @@ -15,7 +16,9 @@ export const ApiPaths = () => { if (!apiPathData?.routes) return
No paths available
; - const sorted = [...apiPathData.routes].sort((a, b) => a.Name.localeCompare(b.Name)); + const sorted = [...apiPathData.routes].sort((a, b) => + a.Name.localeCompare(b.Name) + ); function clickRow(route: Route) { setSelectedRoute(route); @@ -29,7 +32,7 @@ export const ApiPaths = () => { return (
-

Available API Paths

+

Available API Paths

@@ -42,7 +45,10 @@ export const ApiPaths = () => { clickRow(path)} - className={'cursor-pointer hover' + (selectedRoute === path ? ' table-primary' : '')} + className={ + 'cursor-pointer hover' + + (selectedRoute === path ? ' table-primary' : '') + } > @@ -59,4 +65,4 @@ export const ApiPaths = () => { /> ); -} \ No newline at end of file +}; diff --git a/src/features/ConfigFile.tsx b/src/features/ConfigFile.tsx index e2980bb..a5ade39 100644 --- a/src/features/ConfigFile.tsx +++ b/src/features/ConfigFile.tsx @@ -9,7 +9,11 @@ type IConfigViewer = Parameters[0]; const ConfigFile = () => { const { appId } = useAppParams(); - const { data: config, refetch, isFetching } = useGetConfigQuery(appId ? { appId } : skipToken); + const { + data: config, + refetch, + isFetching, + } = useGetConfigQuery(appId ? { appId } : skipToken); if (!config) { return
Config Data Loading or Not Available
; @@ -18,7 +22,12 @@ const ConfigFile = () => { return (
-
@@ -32,7 +41,7 @@ const ConfigFile = () => { export default ConfigFile; const ConfigFileRender = ({ config }: { config: any }) => { - console.log("ConfigFileRender == ", config); + console.log('ConfigFileRender == ', config); const monaco = useMonaco(); const editorRef = useRef(null); diff --git a/src/features/DebugConsole/ConsoleWindow.tsx b/src/features/DebugConsole/ConsoleWindow.tsx index 516e0f7..5bb2c73 100644 --- a/src/features/DebugConsole/ConsoleWindow.tsx +++ b/src/features/DebugConsole/ConsoleWindow.tsx @@ -1,8 +1,8 @@ -import { useState } from "react"; -import { Col, Container, Row } from "react-bootstrap"; -import ScrollToBottom from "react-scroll-to-bottom"; -import { LogMessage } from "../../shared/types/LogMessage"; -import LogMessageDetailDrawer from "./LogMessageDetailDrawer"; +import { useState } from 'react'; +import { Col, Container, Row } from 'react-bootstrap'; +import ScrollToBottom from 'react-scroll-to-bottom'; +import { LogMessage } from '../../shared/types/LogMessage'; +import LogMessageDetailDrawer from './LogMessageDetailDrawer'; const Content = ({ filteredItems }: ConsoleWindowProps) => { const [showDrawer, setShowDrawer] = useState(false); @@ -20,15 +20,22 @@ const Content = ({ filteredItems }: ConsoleWindowProps) => { return ( <> - + {filteredItems.map((message, index) => ( clickItem(message)} - className={"cursor-pointer hover " + (selectedItem === message ? "bg-primary text-white" : (index % 2 === 0 ? "bg-light" : "bg-white"))} + className={ + 'cursor-pointer hover ' + + (selectedItem === message + ? 'bg-primary text-white' + : index % 2 === 0 + ? 'bg-light' + : 'bg-white') + } >
{message.Timestamp} - {message.Properties?.Key || "global"} + {message.Properties?.Key || 'global'}{message.Level}{message.RenderedMessage} @@ -62,7 +69,7 @@ const ConsoleWindow = ({ filteredItems }: ConsoleWindowProps) => { className="overflow-auto flex-grow-1" followButtonClassName="btn btn-sm btn-outline-secondary" mode="bottom" - initialScrollBehavior='auto' + initialScrollBehavior="auto" > diff --git a/src/features/DebugConsole/DebugConsole.tsx b/src/features/DebugConsole/DebugConsole.tsx index 86ad70f..5a007d5 100644 --- a/src/features/DebugConsole/DebugConsole.tsx +++ b/src/features/DebugConsole/DebugConsole.tsx @@ -7,7 +7,7 @@ import { useGetDoNotLoadConfigOnNextBootQuery, useSetDoNotLoadConfigOnNextBootMutation, useSetLoadConfigMutation, - useSetRestartMutation + useSetRestartMutation, } from '../../store/apiSlice'; import { selectSearchText } from '../../store/debugConsole/debugConsoleSelectors'; import { debugConsoleActions } from '../../store/debugConsole/debugConsoleSlice'; @@ -19,16 +19,27 @@ import MinimumLogLevelDropdown from './MinimumLogLevelDropdown'; import RestartConfirmModal from './RestartConfirmModal'; import { useFilteredMessages } from './hooks/useFilteredMessages'; -const DebugConsole = ({isConnected, join, stop, clear}: DebugConsoleProps) => { +const DebugConsole = ({ + isConnected, + join, + stop, + clear, +}: DebugConsoleProps) => { //* HOOKS ***********************************************************/ const [showModal, setShowModal] = useState(false); const { appId } = useAppParams(); const dispatch = useAppDispatch(); - const messages = useAppSelector((state: RootState) => state.websocket.messages); - const failedUrls = useAppSelector((state: RootState) => state.websocket.failedUrls); + const messages = useAppSelector( + (state: RootState) => state.websocket.messages + ); + const failedUrls = useAppSelector( + (state: RootState) => state.websocket.failedUrls + ); const searchText = useAppSelector(selectSearchText); const certUrls = failedUrls - ? failedUrls.map((u: string) => new URL(u).origin.replace(/^wss:/, 'https:').replace(/^ws:/, 'http:')) + ? failedUrls.map((u: string) => + new URL(u).origin.replace(/^wss:/, 'https:').replace(/^ws:/, 'http:') + ) : null; const { data: doNotLoadConfigOnNextBoot } = @@ -43,7 +54,10 @@ const DebugConsole = ({isConnected, join, stop, clear}: DebugConsoleProps) => { const exportFilteredItems = () => { const content = filteredItems - .map((item) => `${item.Timestamp} [${item.Level}]${item.Properties?.Key ? ` [${item.Properties.Key}]` : ''} ${item.RenderedMessage}`) + .map( + (item) => + `${item.Timestamp} [${item.Level}]${item.Properties?.Key ? ` [${item.Properties.Key}]` : ''} ${item.RenderedMessage}` + ) .join('\n'); const blob = new Blob([content], { type: 'text/plain' }); const url = URL.createObjectURL(blob); @@ -63,8 +77,8 @@ const DebugConsole = ({isConnected, join, stop, clear}: DebugConsoleProps) => { }; const clickLoadConfig = () => { - if(!appId) return; - console.log("Loading config"); + if (!appId) return; + console.log('Loading config'); loadConfig({ appId }); }; @@ -79,14 +93,23 @@ const DebugConsole = ({isConnected, join, stop, clear}: DebugConsoleProps) => {
{!isConnected ? ( - - ) - : ( - + + ) : ( + )} { id="doNotLoadConfig" checked={doNotLoadConfigOnNextBoot?.doNotLoadConfigOnNextBoot} onChange={() => { - if(!appId) return; - setDoNotLoadConfig( - { appId, doNotLoadConfigOnNextBoot: !doNotLoadConfigOnNextBoot?.doNotLoadConfigOnNextBoot } - ) + if (!appId) return; + setDoNotLoadConfig({ + appId, + doNotLoadConfigOnNextBoot: + !doNotLoadConfigOnNextBoot?.doNotLoadConfigOnNextBoot, + }); }} /> {doNotLoadConfigOnNextBoot?.doNotLoadConfigOnNextBoot && ( - )} - + )} +
{certUrls && certUrls.length > 0 && ( - - Connection failed. The debug server may have an untrusted certificate.{' '} + + Connection failed. The debug server may have an + untrusted certificate.{' '} {certUrls.map((certUrl: string, i: number) => ( {i > 0 && ' or '} @@ -157,17 +183,19 @@ const DebugConsole = ({isConnected, join, stop, clear}: DebugConsoleProps) => { dispatch(debugConsoleActions.setSearchText(val))} + onSearchChange={(val) => + dispatch(debugConsoleActions.setSearchText(val)) + } filters={} /> - + setShowModal(false)} handleConfirm={() => { - if(!appId) return; + if (!appId) return; restart({ appId }); setShowModal(false); }} @@ -178,11 +206,9 @@ const DebugConsole = ({isConnected, join, stop, clear}: DebugConsoleProps) => { export default DebugConsole; - interface DebugConsoleProps { isConnected: boolean; join: (appId: string) => void; stop: (appId: string) => void; clear: () => void; } - diff --git a/src/features/DebugConsole/DebugFilters.tsx b/src/features/DebugConsole/DebugFilters.tsx index 90ede37..cb7eede 100644 --- a/src/features/DebugConsole/DebugFilters.tsx +++ b/src/features/DebugConsole/DebugFilters.tsx @@ -1,4 +1,3 @@ - import { skipToken } from '@reduxjs/toolkit/query'; import { useMemo } from 'react'; import { Button } from 'react-bootstrap'; @@ -10,7 +9,6 @@ import { useAppDispatch } from '../../store/hooks'; import { debugConsts } from './debugConsts'; import { DeviceFilterDropdown } from './DeviceFilterDropdown'; - export const DebugFilters = () => { const { appId } = useAppParams(); const { data: devices } = useGetDevicesQuery(appId ? { appId } : skipToken); diff --git a/src/features/DebugConsole/DeviceFilterDropdown.tsx b/src/features/DebugConsole/DeviceFilterDropdown.tsx index 99a325c..ca640fd 100644 --- a/src/features/DebugConsole/DeviceFilterDropdown.tsx +++ b/src/features/DebugConsole/DeviceFilterDropdown.tsx @@ -20,7 +20,9 @@ export const DeviceFilterDropdown = ({ items }: DeviceFilterDropdownProps) => { const dispatch = useAppDispatch(); const checkedDevices = useAppSelector(selectCheckedDevices); const deviceLevels = useAppSelector(selectDeviceLevels); - const [openLevelDropdowns, setOpenLevelDropdowns] = useState>({}); + const [openLevelDropdowns, setOpenLevelDropdowns] = useState< + Record + >({}); function handleCheckChange( event: ChangeEvent, @@ -40,7 +42,11 @@ export const DeviceFilterDropdown = ({ items }: DeviceFilterDropdownProps) => { return ( - + Devices {checkedDevices.length > 0 && ( @@ -75,7 +81,10 @@ export const DeviceFilterDropdown = ({ items }: DeviceFilterDropdownProps) => { - setOpenLevelDropdowns((prev) => ({ ...prev, [stringId]: isOpen })) + setOpenLevelDropdowns((prev) => ({ + ...prev, + [stringId]: isOpen, + })) } className="ms-auto" > @@ -99,7 +108,8 @@ export const DeviceFilterDropdown = ({ items }: DeviceFilterDropdownProps) => { > {opt.label} - ))} + ))}{' '} + )} diff --git a/src/features/DebugConsole/LogMessageDetailDrawer.tsx b/src/features/DebugConsole/LogMessageDetailDrawer.tsx index 5ac179b..f3c5ac4 100644 --- a/src/features/DebugConsole/LogMessageDetailDrawer.tsx +++ b/src/features/DebugConsole/LogMessageDetailDrawer.tsx @@ -1,5 +1,5 @@ -import { Offcanvas } from "react-bootstrap"; -import { LogMessage } from "../../shared/types/LogMessage"; +import { Offcanvas } from 'react-bootstrap'; +import { LogMessage } from '../../shared/types/LogMessage'; const LogMessageDetailDrawer = ({ show, diff --git a/src/features/DebugConsole/MinimumLogLevelDropdown.tsx b/src/features/DebugConsole/MinimumLogLevelDropdown.tsx index 333894b..38c6c30 100644 --- a/src/features/DebugConsole/MinimumLogLevelDropdown.tsx +++ b/src/features/DebugConsole/MinimumLogLevelDropdown.tsx @@ -1,15 +1,17 @@ import { skipToken } from '@reduxjs/toolkit/query'; -import { Dropdown } from "react-bootstrap"; +import { Dropdown } from 'react-bootstrap'; import useAppParams from '../../shared/hooks/useAppParams'; import { IconDarkChevronDown } from '../../shared/icons'; import { useGetMinimumLogLevelQuery, useSetMinimumLogLevelMutation, -} from "../../store/apiSlice"; +} from '../../store/apiSlice'; const MinimumLogLevelDropdown = () => { const { appId } = useAppParams(); - const { data: currentLogLevel } = useGetMinimumLogLevelQuery(appId ? { appId } : skipToken); + const { data: currentLogLevel } = useGetMinimumLogLevelQuery( + appId ? { appId } : skipToken + ); const [setLogLevel] = useSetMinimumLogLevelMutation(); @@ -28,42 +30,42 @@ const MinimumLogLevelDropdown = () => { { - setLogLevel({ appId, minimumLevel: "Information" }); + setLogLevel({ appId, minimumLevel: 'Information' }); }} > Information { - setLogLevel({ appId, minimumLevel: "Warning" }); + setLogLevel({ appId, minimumLevel: 'Warning' }); }} > Warning { - setLogLevel({ appId, minimumLevel: "Error" }); + setLogLevel({ appId, minimumLevel: 'Error' }); }} > Error { - setLogLevel({ appId, minimumLevel: "Fatal" }); + setLogLevel({ appId, minimumLevel: 'Fatal' }); }} > Fatal { - setLogLevel({ appId, minimumLevel: "Debug" }); + setLogLevel({ appId, minimumLevel: 'Debug' }); }} > Debug { - setLogLevel({ appId, minimumLevel: "Verbose" }); + setLogLevel({ appId, minimumLevel: 'Verbose' }); }} > Verbose diff --git a/src/features/DebugConsole/RestartConfirmModal.tsx b/src/features/DebugConsole/RestartConfirmModal.tsx index 25e2e18..050c33d 100644 --- a/src/features/DebugConsole/RestartConfirmModal.tsx +++ b/src/features/DebugConsole/RestartConfirmModal.tsx @@ -1,27 +1,27 @@ import { Button, Modal } from 'react-bootstrap'; -const RestartConfirmModal = ({show, handleClose, handleConfirm}: RestartConfirmModalProps) => { +const RestartConfirmModal = ({ + show, + handleClose, + handleConfirm, +}: RestartConfirmModalProps) => { return ( - - Restart Program - - Are you sure you want to restart the program? - - - - - - - ); -} + + Restart Program + + Are you sure you want to restart the program? + + + + + + ); +}; export default RestartConfirmModal; @@ -29,4 +29,4 @@ interface RestartConfirmModalProps { show: boolean; handleClose: () => void; handleConfirm: () => void; -} \ No newline at end of file +} diff --git a/src/features/DebugConsole/debugConsts.ts b/src/features/DebugConsole/debugConsts.ts index 4241db7..9ab43cb 100644 --- a/src/features/DebugConsole/debugConsts.ts +++ b/src/features/DebugConsole/debugConsts.ts @@ -1,19 +1,19 @@ -import { IdLabel } from "../../shared/types/IdLabel"; +import { IdLabel } from '../../shared/types/IdLabel'; -export const DEVICE = "device"; -export const SEARCH_TEXT = "searchText"; -export const AFTER = "after"; -export const BEFORE = "before"; -export const LOG_LEVEL = "logLevel"; +export const DEVICE = 'device'; +export const SEARCH_TEXT = 'searchText'; +export const AFTER = 'after'; +export const BEFORE = 'before'; +export const LOG_LEVEL = 'logLevel'; -export const GLOBAL = "global"; +export const GLOBAL = 'global'; -const ERROR = "Error"; -const INFORMATION = "Information"; -const WARNING = "Warning"; -const FATAL = "Fatal"; -const VERBOSE = "Verbose"; -const DEBUG = "Debug"; +const ERROR = 'Error'; +const INFORMATION = 'Information'; +const WARNING = 'Warning'; +const FATAL = 'Fatal'; +const VERBOSE = 'Verbose'; +const DEBUG = 'Debug'; const LOG_LEVELS = [ERROR, WARNING, INFORMATION, FATAL, VERBOSE, DEBUG]; @@ -27,12 +27,12 @@ export const LOG_LEVEL_ORDER: Record = { }; export const logLevelOpts: IdLabel[] = [ - { id: FATAL, label: "Fatal" }, - { id: ERROR, label: "Error" }, - { id: WARNING, label: "Warning" }, - { id: INFORMATION, label: "Information" }, - { id: DEBUG, label: "Debug" }, - { id: VERBOSE, label: "Verbose" }, + { id: FATAL, label: 'Fatal' }, + { id: ERROR, label: 'Error' }, + { id: WARNING, label: 'Warning' }, + { id: INFORMATION, label: 'Information' }, + { id: DEBUG, label: 'Debug' }, + { id: VERBOSE, label: 'Verbose' }, ]; export const debugSearchParams = { diff --git a/src/features/DeviceDetail.tsx b/src/features/DeviceDetail.tsx index 13ffd09..bb710d7 100644 --- a/src/features/DeviceDetail.tsx +++ b/src/features/DeviceDetail.tsx @@ -1,6 +1,6 @@ import { skipToken } from '@reduxjs/toolkit/query'; -import { useState } from "react"; -import { Button, Form, Modal } from "react-bootstrap"; +import { useState } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; import useAppParams from '../shared/hooks/useAppParams'; import { DeviceFeedbacks, @@ -11,16 +11,21 @@ import { useGetDeviceMethodsQuery, useGetDevicePropertiesQuery, useSetDeviceJsonCommandMutation, -} from "../store/apiSlice"; +} from '../store/apiSlice'; const DeviceDetail = ({ item }: DeviceDetailProps) => { const { appId } = useAppParams(); - const { data: properties } = useGetDevicePropertiesQuery(appId && item?.Key ? { appId, key: item.Key } : skipToken + const { data: properties } = useGetDevicePropertiesQuery( + appId && item?.Key ? { appId, key: item.Key } : skipToken + ); + const { data: methods } = useGetDeviceMethodsQuery( + appId && item?.Key ? { appId, key: item.Key } : skipToken + ); + const { data: feedbacks } = useGetDeviceFeedbacksQuery( + appId && item?.Key ? { appId, key: item.Key } : skipToken ); - const { data: methods } = useGetDeviceMethodsQuery(appId && item?.Key ? { appId, key: item.Key } : skipToken); - const { data: feedbacks } = useGetDeviceFeedbacksQuery(appId && item?.Key ? { appId, key: item.Key } : skipToken); - console.log("DeviceDetail == ", { item, properties, methods, feedbacks }); + console.log('DeviceDetail == ', { item, properties, methods, feedbacks }); if (!properties || !methods) { return
Loading...
; @@ -49,13 +54,16 @@ const DeviceDetailRender = ({ deviceKey, }: DeviceDetailRenderProps) => { const { appId } = useAppParams(); - const [selectedMethod, setSelectedMethod] = useState(null); + const [selectedMethod, setSelectedMethod] = useState( + null + ); const [paramValues, setParamValues] = useState>({}); - const [executeMethod, { isLoading: isExecuting }] = useSetDeviceJsonCommandMutation(); + const [executeMethod, { isLoading: isExecuting }] = + useSetDeviceJsonCommandMutation(); const handleOpen = (method: DeviceMethods) => { setSelectedMethod(method); - setParamValues(Object.fromEntries(method.Params.map((p) => [p.Name, ""]))); + setParamValues(Object.fromEntries(method.Params.map((p) => [p.Name, '']))); }; const handleClose = () => { @@ -65,7 +73,12 @@ const DeviceDetailRender = ({ const handleExecute = async () => { if (!selectedMethod || !appId) return; - await executeMethod({ appId, deviceKey, methodName: selectedMethod.Name, params: Object.values(paramValues) }); + await executeMethod({ + appId, + deviceKey, + methodName: selectedMethod.Name, + params: Object.values(paramValues), + }); handleClose(); }; @@ -90,8 +103,8 @@ const DeviceDetailRender = ({
- - + + ))} @@ -111,10 +124,17 @@ const DeviceDetailRender = ({ ))} @@ -133,14 +153,18 @@ const DeviceDetailRender = ({ {selectedMethod?.Params.map((param) => ( - {param.Name} ({param.Type}) + {param.Name}{' '} + ({param.Type}) - setParamValues((prev) => ({ ...prev, [param.Name]: e.target.value })) + setParamValues((prev) => ({ + ...prev, + [param.Name]: e.target.value, + })) } /> @@ -149,9 +173,15 @@ const DeviceDetailRender = ({ )} - - + @@ -176,7 +206,9 @@ const DeviceDetailRender = ({ )) ) : ( - + + + )}
{path.Name} {path.Url}
{p.Name} {p.Type} {p.Value}{p.CanRead ? "Yes" : "No"}{p.canWrite ? "Yes" : "No"}{p.CanRead ? 'Yes' : 'No'}{p.canWrite ? 'Yes' : 'No'}
{m.Name} - {m.Params.map((param) => `${param.Name}: ${param.Type}`).join(", ")} + {m.Params.map((param) => `${param.Name}: ${param.Type}`).join( + ', ' + )} - +
None
None
@@ -198,7 +230,9 @@ const DeviceDetailRender = ({ )) ) : ( - None + + None + )} @@ -220,7 +254,9 @@ const DeviceDetailRender = ({ )) ) : ( - None + + None + )} diff --git a/src/features/DeviceList.tsx b/src/features/DeviceList.tsx index ca75af8..896c27e 100644 --- a/src/features/DeviceList.tsx +++ b/src/features/DeviceList.tsx @@ -1,8 +1,8 @@ import { skipToken } from '@reduxjs/toolkit/query'; -import { useState } from "react"; +import { useState } from 'react'; import useAppParams from '../shared/hooks/useAppParams'; -import { IKeyed, useGetDevicesQuery } from "../store/apiSlice"; -import DeviceDetail from "./DeviceDetail"; +import { IKeyed, useGetDevicesQuery } from '../store/apiSlice'; +import DeviceDetail from './DeviceDetail'; const DeviceList = () => { const [selectedDevice, setSelectedDevice] = useState(); @@ -29,7 +29,7 @@ const DeviceList = () => { {devices.map((i) => ( setSelectedDevice(i)} > {i.Key} diff --git a/src/features/ErrorBoundary.tsx b/src/features/ErrorBoundary.tsx index 46087e6..e9b17b3 100644 --- a/src/features/ErrorBoundary.tsx +++ b/src/features/ErrorBoundary.tsx @@ -1,5 +1,5 @@ -import { Component, ErrorInfo, ReactNode } from "react"; -import ErrorBox from "./ErrorBox"; +import { Component, ErrorInfo, ReactNode } from 'react'; +import ErrorBox from './ErrorBox'; interface Props { children: ReactNode; @@ -17,7 +17,7 @@ class ErrorBoundary extends Component { } componentDidCatch(error: Error, info: ErrorInfo) { - console.error("ErrorBoundary caught an error:", error, info.componentStack); + console.error('ErrorBoundary caught an error:', error, info.componentStack); } render() { diff --git a/src/features/Help/Help.test.tsx b/src/features/Help/Help.test.tsx index 02830ee..17cb615 100644 --- a/src/features/Help/Help.test.tsx +++ b/src/features/Help/Help.test.tsx @@ -1,7 +1,7 @@ -import { fireEvent, render, screen, within } from "@testing-library/react"; -import { describe, expect, it } from "vitest"; -import { MemoryRouter, Route, Routes } from "react-router-dom"; -import Help from "./Help"; +import { fireEvent, render, screen, within } from '@testing-library/react'; +import { describe, expect, it } from 'vitest'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import Help from './Help'; const renderHelp = (initialPath: string) => render( @@ -9,66 +9,68 @@ const renderHelp = (initialPath: string) => } /> - , + ); -const getSidebar = () => screen.getByRole("navigation"); +const getSidebar = () => screen.getByRole('navigation'); -describe("Help", () => { - it("renders the docs home page with sidebar navigation at /help", () => { - renderHelp("/help"); +describe('Help', () => { + it('renders the docs home page with sidebar navigation at /help', () => { + renderHelp('/help'); expect( - screen.getByRole("heading", { + screen.getByRole('heading', { name: /PepperDash Essentials Web Config App Documentation/i, - }), + }) ).toBeInTheDocument(); const sidebar = getSidebar(); expect( - within(sidebar).getByRole("link", { name: "Tutorials" }), + within(sidebar).getByRole('link', { name: 'Tutorials' }) ).toBeInTheDocument(); expect( - within(sidebar).getByRole("link", { name: "How-to Guides" }), + within(sidebar).getByRole('link', { name: 'How-to Guides' }) ).toBeInTheDocument(); }); - it("navigates client-side when following an internal doc link", async () => { - renderHelp("/help/tutorials/debug-console-basics"); + it('navigates client-side when following an internal doc link', async () => { + renderHelp('/help/tutorials/debug-console-basics'); - const howToLink = within(getSidebar()).getByRole("link", { - name: "How-to Guides", + const howToLink = within(getSidebar()).getByRole('link', { + name: 'How-to Guides', }); fireEvent.click(howToLink); expect( - await screen.findByRole("heading", { + await screen.findByRole('heading', { name: /How-to Guides - Problem-Oriented Solutions/i, - }), + }) ).toBeInTheDocument(); }); - it("opens external links in a new tab instead of routing internally", () => { - renderHelp("/help"); - const externalLink = screen.getAllByRole("link", { - name: "Diataxis framework", + it('opens external links in a new tab instead of routing internally', () => { + renderHelp('/help'); + const externalLink = screen.getAllByRole('link', { + name: 'Diataxis framework', })[0]; - expect(externalLink).toHaveAttribute("href", "https://diataxis.fr/"); - expect(externalLink).toHaveAttribute("target", "_blank"); + expect(externalLink).toHaveAttribute('href', 'https://diataxis.fr/'); + expect(externalLink).toHaveAttribute('target', '_blank'); }); - it("renders GFM tables from reference docs as styled Bootstrap tables", () => { - renderHelp("/help/reference/log-levels"); - const tables = screen.getAllByRole("table"); + it('renders GFM tables from reference docs as styled Bootstrap tables', () => { + renderHelp('/help/reference/log-levels'); + const tables = screen.getAllByRole('table'); expect(tables.length).toBeGreaterThan(0); - tables.forEach((table) => expect(table).toHaveClass("table", "table-striped")); - expect(screen.getAllByText("Fatal").length).toBeGreaterThan(0); + tables.forEach((table) => + expect(table).toHaveClass('table', 'table-striped') + ); + expect(screen.getAllByText('Fatal').length).toBeGreaterThan(0); }); - it("shows a not-found message with a way back for an unknown slug", () => { - renderHelp("/help/does/not/exist"); + it('shows a not-found message with a way back for an unknown slug', () => { + renderHelp('/help/does/not/exist'); expect(screen.getByText(/page not found/i)).toBeInTheDocument(); expect( - screen.getByRole("link", { name: /back to help/i }), + screen.getByRole('link', { name: /back to help/i }) ).toBeInTheDocument(); }); }); diff --git a/src/features/Help/Help.tsx b/src/features/Help/Help.tsx index d4ce869..76f7d07 100644 --- a/src/features/Help/Help.tsx +++ b/src/features/Help/Help.tsx @@ -1,11 +1,11 @@ -import { Link, useParams } from "react-router-dom"; -import HelpArticle from "./HelpArticle"; -import HelpSidebar from "./HelpSidebar"; -import { getDocBySlug } from "./docsContent"; +import { Link, useParams } from 'react-router-dom'; +import HelpArticle from './HelpArticle'; +import HelpSidebar from './HelpSidebar'; +import { getDocBySlug } from './docsContent'; const Help = () => { const params = useParams(); - const slug = params["*"] ?? ""; + const slug = params['*'] ?? ''; const doc = getDocBySlug(slug); return ( diff --git a/src/features/Help/HelpArticle.tsx b/src/features/Help/HelpArticle.tsx index ffb394f..73301e0 100644 --- a/src/features/Help/HelpArticle.tsx +++ b/src/features/Help/HelpArticle.tsx @@ -1,8 +1,8 @@ -import { Link } from "react-router-dom"; -import ReactMarkdown from "react-markdown"; -import type { Components } from "react-markdown"; -import remarkGfm from "remark-gfm"; -import { DocEntry, resolveRelativeLink } from "./docsContent"; +import { Link } from 'react-router-dom'; +import ReactMarkdown from 'react-markdown'; +import type { Components } from 'react-markdown'; +import remarkGfm from 'remark-gfm'; +import { DocEntry, resolveRelativeLink } from './docsContent'; const DocLink = ({ currentSlug, diff --git a/src/features/Help/HelpSidebar.tsx b/src/features/Help/HelpSidebar.tsx index d1209ab..f8d3956 100644 --- a/src/features/Help/HelpSidebar.tsx +++ b/src/features/Help/HelpSidebar.tsx @@ -1,5 +1,5 @@ -import { NavLink } from "react-router-dom"; -import { docsNavTree } from "./docsContent"; +import { NavLink } from 'react-router-dom'; +import { docsNavTree } from './docsContent'; const HelpSidebar = () => { return ( @@ -8,7 +8,7 @@ const HelpSidebar = () => { to="/help" end className={({ isActive }) => - `d-block mb-2 ${isActive ? "text-secondary" : ""}` + `d-block mb-2 ${isActive ? 'text-secondary' : ''}` } > Documentation Home @@ -19,7 +19,7 @@ const HelpSidebar = () => { to={`/help/${category.indexSlug}`} end className={({ isActive }) => - `d-block fw-semibold ${isActive ? "text-secondary" : ""}` + `d-block fw-semibold ${isActive ? 'text-secondary' : ''}` } > {category.label} @@ -30,7 +30,7 @@ const HelpSidebar = () => { - isActive ? "text-secondary" : "" + isActive ? 'text-secondary' : '' } > {page.title} diff --git a/src/features/Help/docsContent.test.ts b/src/features/Help/docsContent.test.ts index dac2c23..21b8324 100644 --- a/src/features/Help/docsContent.test.ts +++ b/src/features/Help/docsContent.test.ts @@ -1,75 +1,80 @@ -import { describe, expect, it } from "vitest"; -import { docsMap, docsNavTree, getDocBySlug, resolveRelativeLink } from "./docsContent"; +import { describe, expect, it } from 'vitest'; +import { + docsMap, + docsNavTree, + getDocBySlug, + resolveRelativeLink, +} from './docsContent'; -describe("docsContent", () => { - it("indexes the root docs README under the empty slug", () => { - const root = getDocBySlug(""); +describe('docsContent', () => { + it('indexes the root docs README under the empty slug', () => { + const root = getDocBySlug(''); expect(root).toBeDefined(); expect(root?.isIndex).toBe(true); expect(root?.title).toMatch(/Documentation/i); }); - it("indexes category READMEs and leaf docs", () => { - expect(getDocBySlug("tutorials")?.isIndex).toBe(true); - expect(getDocBySlug("tutorials/getting-started")?.isIndex).toBe(false); - expect(getDocBySlug("tutorials/getting-started")?.category).toBe( - "tutorials", + it('indexes category READMEs and leaf docs', () => { + expect(getDocBySlug('tutorials')?.isIndex).toBe(true); + expect(getDocBySlug('tutorials/getting-started')?.isIndex).toBe(false); + expect(getDocBySlug('tutorials/getting-started')?.category).toBe( + 'tutorials' ); }); - it("orders tutorial pages the way tutorials/README.md links them, not alphabetically", () => { - const tutorials = docsNavTree.find((c) => c.category === "tutorials"); + it('orders tutorial pages the way tutorials/README.md links them, not alphabetically', () => { + const tutorials = docsNavTree.find((c) => c.category === 'tutorials'); expect(tutorials?.pages.map((p) => p.slug)).toEqual([ - "tutorials/getting-started", - "tutorials/debug-console-basics", - "tutorials/device-management-basics", + 'tutorials/getting-started', + 'tutorials/debug-console-basics', + 'tutorials/device-management-basics', ]); }); - it("resolves a same-directory relative link", () => { + it('resolves a same-directory relative link', () => { expect( resolveRelativeLink( - "tutorials/debug-console-basics", - "./getting-started.md", - ), - ).toBe("/help/tutorials/getting-started"); + 'tutorials/debug-console-basics', + './getting-started.md' + ) + ).toBe('/help/tutorials/getting-started'); }); - it("resolves a parent-directory folder link to a category index", () => { + it('resolves a parent-directory folder link to a category index', () => { expect( - resolveRelativeLink("tutorials/debug-console-basics", "../how-to/"), - ).toBe("/help/how-to"); + resolveRelativeLink('tutorials/debug-console-basics', '../how-to/') + ).toBe('/help/how-to'); }); - it("resolves a root-relative README link to the docs home", () => { + it('resolves a root-relative README link to the docs home', () => { expect( - resolveRelativeLink("tutorials/getting-started", "../README.md"), - ).toBe("/help"); + resolveRelativeLink('tutorials/getting-started', '../README.md') + ).toBe('/help'); }); - it("returns null for external and anchor links", () => { - expect(resolveRelativeLink("", "https://diataxis.fr/")).toBeNull(); - expect(resolveRelativeLink("", "mailto:test@example.com")).toBeNull(); - expect(resolveRelativeLink("tutorials", "#some-heading")).toBeNull(); + it('returns null for external and anchor links', () => { + expect(resolveRelativeLink('', 'https://diataxis.fr/')).toBeNull(); + expect(resolveRelativeLink('', 'mailto:test@example.com')).toBeNull(); + expect(resolveRelativeLink('tutorials', '#some-heading')).toBeNull(); }); - it("resolves a relative link with a trailing heading fragment, preserving the fragment", () => { + it('resolves a relative link with a trailing heading fragment, preserving the fragment', () => { expect( resolveRelativeLink( - "how-to/trace-signal-routes", - "../reference/ui-components.md#routing-diagram", - ), - ).toBe("/help/reference/ui-components#routing-diagram"); + 'how-to/trace-signal-routes', + '../reference/ui-components.md#routing-diagram' + ) + ).toBe('/help/reference/ui-components#routing-diagram'); }); - it("has every doc reachable from docsMap for links found across the docs", () => { + it('has every doc reachable from docsMap for links found across the docs', () => { expect(docsMap.size).toBeGreaterThan(0); }); - it("includes the new routing how-to guide in the how-to nav category", () => { - const howTo = docsNavTree.find((c) => c.category === "how-to"); + it('includes the new routing how-to guide in the how-to nav category', () => { + const howTo = docsNavTree.find((c) => c.category === 'how-to'); expect(howTo?.pages.map((p) => p.slug)).toContain( - "how-to/trace-signal-routes", + 'how-to/trace-signal-routes' ); }); }); diff --git a/src/features/Help/docsContent.ts b/src/features/Help/docsContent.ts index 649a9e6..903780f 100644 --- a/src/features/Help/docsContent.ts +++ b/src/features/Help/docsContent.ts @@ -1,4 +1,4 @@ -export type DocCategory = "tutorials" | "how-to" | "reference" | "explanation"; +export type DocCategory = 'tutorials' | 'how-to' | 'reference' | 'explanation'; export interface DocEntry { slug: string; @@ -16,26 +16,26 @@ interface CategoryNav { } const CATEGORY_LABELS: Record = { - tutorials: "Tutorials", - "how-to": "How-to Guides", - reference: "Reference", - explanation: "Explanation", + tutorials: 'Tutorials', + 'how-to': 'How-to Guides', + reference: 'Reference', + explanation: 'Explanation', }; const CATEGORY_ORDER: DocCategory[] = [ - "tutorials", - "how-to", - "reference", - "explanation", + 'tutorials', + 'how-to', + 'reference', + 'explanation', ]; function normalizePath(raw: string): { slug: string; isIndex: boolean } { - const trimmed = raw.replace(/^\/docs\//, "").replace(/\.md$/, ""); - if (trimmed === "README") { - return { slug: "", isIndex: true }; + const trimmed = raw.replace(/^\/docs\//, '').replace(/\.md$/, ''); + if (trimmed === 'README') { + return { slug: '', isIndex: true }; } - if (trimmed.endsWith("/README")) { - return { slug: trimmed.slice(0, -"/README".length), isIndex: true }; + if (trimmed.endsWith('/README')) { + return { slug: trimmed.slice(0, -'/README'.length), isIndex: true }; } return { slug: trimmed, isIndex: false }; } @@ -43,37 +43,37 @@ function normalizePath(raw: string): { slug: string; isIndex: boolean } { function deriveTitle(content: string, slug: string): string { const match = content.match(/^#\s+(.+)$/m); if (match) return match[1].trim(); - const last = slug.split("/").pop() || slug; + const last = slug.split('/').pop() || slug; return last - .split("-") + .split('-') .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(" "); + .join(' '); } // Joins a markdown-relative href against the directory of the doc that // contains it, collapsing "." and ".." segments manually (no Node `path` // module available in the browser bundle). function joinRelative(baseDir: string, href: string): string { - const baseSegments = baseDir ? baseDir.split("/") : []; - const hrefSegments = href.split("/"); + const baseSegments = baseDir ? baseDir.split('/') : []; + const hrefSegments = href.split('/'); const stack = [...baseSegments]; for (const segment of hrefSegments) { - if (segment === "" || segment === ".") continue; - if (segment === "..") { + if (segment === '' || segment === '.') continue; + if (segment === '..') { stack.pop(); } else { stack.push(segment); } } - return stack.join("/"); + return stack.join('/'); } function buildDocsMap(): Map { - const rawModules = import.meta.glob("/docs/**/*.md", { - query: "?raw", - import: "default", + const rawModules = import.meta.glob('/docs/**/*.md', { + query: '?raw', + import: 'default', eager: true, }) as Record; @@ -82,7 +82,7 @@ function buildDocsMap(): Map { for (const [path, content] of Object.entries(rawModules)) { const { slug, isIndex } = normalizePath(path); const category = slug - ? ((slug.split("/")[0] as DocCategory) ?? null) + ? ((slug.split('/')[0] as DocCategory) ?? null) : null; map.set(slug, { @@ -121,8 +121,8 @@ function buildNavTree(docsMap: Map): CategoryNav[] { const pages = Array.from(docsMap.values()) .filter((doc) => doc.category === category && !doc.isIndex) .sort((a, b) => { - const aName = a.slug.split("/").pop() ?? a.slug; - const bName = b.slug.split("/").pop() ?? b.slug; + const aName = a.slug.split('/').pop() ?? a.slug; + const bName = b.slug.split('/').pop() ?? b.slug; const aIndex = linkOrder.indexOf(aName); const bIndex = linkOrder.indexOf(bName); if (aIndex === -1 && bIndex === -1) return aName.localeCompare(bName); @@ -154,23 +154,23 @@ export function getDocBySlug(slug: string): DocEntry | undefined { // doc link (callers should render those as plain external anchors). export function resolveRelativeLink( currentSlug: string, - href: string, + href: string ): string | null { if (/^([a-z][a-z0-9+.-]*:|#)/i.test(href)) return null; - const hashIndex = href.indexOf("#"); + const hashIndex = href.indexOf('#'); const path = hashIndex === -1 ? href : href.slice(0, hashIndex); - const hash = hashIndex === -1 ? "" : href.slice(hashIndex); + const hash = hashIndex === -1 ? '' : href.slice(hashIndex); - const currentDir = currentSlug.includes("/") - ? currentSlug.slice(0, currentSlug.lastIndexOf("/")) - : ""; + const currentDir = currentSlug.includes('/') + ? currentSlug.slice(0, currentSlug.lastIndexOf('/')) + : ''; const joined = joinRelative(currentDir, path) - .replace(/\.md$/, "") - .replace(/\/$/, ""); + .replace(/\.md$/, '') + .replace(/\/$/, ''); const { slug } = normalizePath(`/docs/${joined}.md`); if (!docsMap.has(slug)) return null; - return (slug === "" ? "/help" : `/help/${slug}`) + hash; + return (slug === '' ? '/help' : `/help/${slug}`) + hash; } diff --git a/src/features/InitializationExceptions.tsx b/src/features/InitializationExceptions.tsx index b14e77a..aa87326 100644 --- a/src/features/InitializationExceptions.tsx +++ b/src/features/InitializationExceptions.tsx @@ -1,15 +1,15 @@ -import { skipToken } from "@reduxjs/toolkit/query"; -import { Fragment, useState } from "react"; -import useAppParams from "../shared/hooks/useAppParams"; +import { skipToken } from '@reduxjs/toolkit/query'; +import { Fragment, useState } from 'react'; +import useAppParams from '../shared/hooks/useAppParams'; import { EssentialsException, useGetInitializationExceptionsQuery, -} from "../store/apiSlice"; +} from '../store/apiSlice'; const InitializationExceptions = () => { const { appId } = useAppParams(); const { data, isLoading, isError } = useGetInitializationExceptionsQuery( - appId ? { appId } : skipToken, + appId ? { appId } : skipToken ); const [expandedIndex, setExpandedIndex] = useState(null); @@ -37,9 +37,9 @@ const InitializationExceptions = () => { - + - + @@ -62,7 +62,7 @@ const InitializationExceptions = () => { setExpandedIndex(isExpanded ? null : idx) } > - {isExpanded ? "Hide" : "Show"} + {isExpanded ? 'Hide' : 'Show'} )} @@ -72,7 +72,10 @@ const InitializationExceptions = () => { - +
## MessageStack traceStack trace
                           {ex.StackTrace}
                         
diff --git a/src/features/LoginForm.tsx b/src/features/LoginForm.tsx index 21daa19..dc0146c 100644 --- a/src/features/LoginForm.tsx +++ b/src/features/LoginForm.tsx @@ -12,16 +12,16 @@ import { authActions } from '../store/auth/authSlice'; import { useAppDispatch, useAppSelector } from '../store/hooks'; const ALL_APP_IDS = [ - "app01", - "app02", - "app03", - "app04", - "app05", - "app06", - "app07", - "app08", - "app09", - "app10", + 'app01', + 'app02', + 'app03', + 'app04', + 'app05', + 'app06', + 'app07', + 'app08', + 'app09', + 'app10', ]; const LoginForm = () => { @@ -32,8 +32,8 @@ const LoginForm = () => { const navigate = useNavigate(); const location = useLocation(); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); const [showPassword, setShowPassword] = useState(false); const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(false); @@ -58,18 +58,18 @@ const LoginForm = () => { // Send login to all program slots in parallel const results = await Promise.allSettled( ALL_APP_IDS.map((id) => - setLoginCredentials({ appId: id, username, password }).unwrap(), - ), + setLoginCredentials({ appId: id, username, password }).unwrap() + ) ); const availableApps = ALL_APP_IDS.filter( - (_, i) => results[i].status === "fulfilled", + (_, i) => results[i].status === 'fulfilled' ); setIsLoading(false); if (availableApps.length === 0) { - setError("Invalid credentials. Please try again."); + setError('Invalid credentials. Please try again.'); return; } @@ -90,7 +90,7 @@ const LoginForm = () => {

PepperDash Essentials Developer Tools

-
+

Sign In

{error && {error}}
@@ -109,7 +109,7 @@ const LoginForm = () => { Password setPassword(e.target.value)} @@ -121,7 +121,7 @@ const LoginForm = () => { variant="outline-secondary" onClick={() => setShowPassword((prev) => !prev)} disabled={isLoading} - aria-label={showPassword ? "Hide password" : "Show password"} + aria-label={showPassword ? 'Hide password' : 'Show password'} aria-pressed={showPassword} > @@ -135,7 +135,7 @@ const LoginForm = () => { Signing in… ) : ( - "Sign In" + 'Sign In' )} diff --git a/src/features/MainLayout.tsx b/src/features/MainLayout.tsx index 7225aa6..e632d4b 100644 --- a/src/features/MainLayout.tsx +++ b/src/features/MainLayout.tsx @@ -1,16 +1,15 @@ -import { Outlet } from 'react-router-dom' -import TopNav from './TopNav' - +import { Outlet } from 'react-router-dom'; +import TopNav from './TopNav'; const MainLayout = ({ isConnected }: { isConnected: boolean }) => { return (
-
+
- ) -} + ); +}; -export default MainLayout \ No newline at end of file +export default MainLayout; diff --git a/src/features/MobileControl.tsx b/src/features/MobileControl.tsx index 2bfdb2b..8907228 100644 --- a/src/features/MobileControl.tsx +++ b/src/features/MobileControl.tsx @@ -1,7 +1,7 @@ -import { skipToken } from "@reduxjs/toolkit/query"; -import { useState } from "react"; -import { Button, Modal } from "react-bootstrap"; -import useAppParams from "../shared/hooks/useAppParams"; +import { skipToken } from '@reduxjs/toolkit/query'; +import { useState } from 'react'; +import { Button, Modal } from 'react-bootstrap'; +import useAppParams from '../shared/hooks/useAppParams'; import { ActionPath, ClientRequest, @@ -12,16 +12,16 @@ import { useDeleteMobileControlUiClientMutation, useGetMobileControlActionPathsQuery, useGetMobileControlInfoQuery, -} from "../store/apiSlice"; +} from '../store/apiSlice'; const MobileControl = () => { const { appId } = useAppParams(); const { data: info } = useGetMobileControlInfoQuery( - appId ? { appId, deviceKey: "appServer" } : skipToken, + appId ? { appId, deviceKey: 'appServer' } : skipToken ); const { data: actionPaths } = useGetMobileControlActionPathsQuery( - appId ? { appId, deviceKey: "appServer" } : skipToken, + appId ? { appId, deviceKey: 'appServer' } : skipToken ); const [deleteClient] = useDeleteMobileControlUiClientMutation(); @@ -31,19 +31,19 @@ const MobileControl = () => { useState(null); const [confirmDeleteAll, setConfirmDeleteAll] = useState(false); const [showCreateModal, setShowCreateModal] = useState(false); - const [newRoomKey, setNewRoomKey] = useState(""); - const [newGrantCode, setNewGrantCode] = useState(""); + const [newRoomKey, setNewRoomKey] = useState(''); + const [newGrantCode, setNewGrantCode] = useState(''); const handleConfirmDelete = async () => { if (!appId || !pendingDelete) return; const clientPayload: ClientResponse = { - error: "", + error: '', token: pendingDelete.token, - path: "", + path: '', }; await deleteClient({ appId, - deviceKey: "appServer-directServer", + deviceKey: 'appServer-directServer', client: clientPayload, }); setPendingDelete(null); @@ -51,7 +51,7 @@ const MobileControl = () => { const handleConfirmDeleteAll = async () => { if (!appId) return; - await deleteAllClients({ appId, deviceKey: "appServer-directServer" }); + await deleteAllClients({ appId, deviceKey: 'appServer-directServer' }); setConfirmDeleteAll(false); }; @@ -60,12 +60,12 @@ const MobileControl = () => { const request: ClientRequest = { roomKey: newRoomKey.trim(), grantCode: newGrantCode.trim(), - token: "", + token: '', }; - await createClient({ appId, deviceKey: "appServer-directServer", request }); + await createClient({ appId, deviceKey: 'appServer-directServer', request }); setShowCreateModal(false); - setNewRoomKey(""); - setNewGrantCode(""); + setNewRoomKey(''); + setNewGrantCode(''); }; if (!info || !actionPaths) { @@ -115,9 +115,7 @@ const MobileControl = () => {
# Room Key Touchpanel Key - Token - Token URL
@@ -155,7 +153,7 @@ const MobileControl = () => { {client.url} -
+