From a74ce063ec788fa0961d748cd197883daf570345 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 21 Aug 2025 12:39:15 -0400 Subject: [PATCH 01/26] feature/IO-3255-simplified-parts-management - Checkoint --- .../validateFirebaseIdTokenLiteMiddleware.js | 42 +++++++++++++++++++ server/routes/renderRoutes.js | 9 ++-- 2 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 server/middleware/validateFirebaseIdTokenLiteMiddleware.js diff --git a/server/middleware/validateFirebaseIdTokenLiteMiddleware.js b/server/middleware/validateFirebaseIdTokenLiteMiddleware.js new file mode 100644 index 000000000..3da2d0871 --- /dev/null +++ b/server/middleware/validateFirebaseIdTokenLiteMiddleware.js @@ -0,0 +1,42 @@ +const logger = require("../utils/logger"); +const admin = require("firebase-admin"); + +/** + * Lite Firebase ID token validator. + * - Only accepts Authorization: Bearer + * - Sets req.user to the decoded token on success + */ +const validateFirebaseIdTokenLite = async (req, res, next) => { + const authHeader = req.headers.authorization || ""; + const match = authHeader.match(/^Bearer\s+(.+)$/i); + + if (!match) { + logger.log("api-authorization-call", "warn", null, null, { + type: "unauthorized", + reason: "missing Bearer token", + path: req.path, + body: req.body + }); + return res.status(401).send("Unauthorized"); + } + + const idToken = match[1].trim(); + + try { + const decodedIdToken = await admin.auth().verifyIdToken(idToken); + req.user = decodedIdToken; + return next(); + } catch (error) { + logger.log("api-unauthorized-call", "warn", null, null, { + type: "unauthorized", + reason: "invalid or expired token", + path: req.path, + body: req.body, + code: error?.errorInfo?.code || error?.code, + message: error?.message + }); + return res.status(401).send("Unauthorized"); + } +}; + +module.exports = validateFirebaseIdTokenLite; diff --git a/server/routes/renderRoutes.js b/server/routes/renderRoutes.js index 41b6cf6aa..5bf651a34 100644 --- a/server/routes/renderRoutes.js +++ b/server/routes/renderRoutes.js @@ -1,13 +1,14 @@ const express = require("express"); const router = express.Router(); const { inlineCSS } = require("../render/inlinecss"); -const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware"); +const validateFirebaseIdTokenLite = require("../middleware/validateFirebaseIdTokenLiteMiddleware"); const { canvas } = require("../render/canvas-handler"); const validateCanvasInputMiddleware = require("../middleware/validateCanvasInputMiddleware"); // Define the route for inline CSS rendering -router.post("/inlinecss", validateFirebaseIdTokenMiddleware, inlineCSS); -router.post("/canvas-skia", validateFirebaseIdTokenMiddleware, validateCanvasInputMiddleware, canvas); -router.post("/canvas", validateFirebaseIdTokenMiddleware, validateCanvasInputMiddleware, canvas); +router.post("/inlinecss", validateFirebaseIdTokenLite, inlineCSS); + +router.post("/canvas-skia", validateFirebaseIdTokenLite, validateCanvasInputMiddleware, canvas); +router.post("/canvas", validateFirebaseIdTokenLite, validateCanvasInputMiddleware, canvas); module.exports = router; From 43d5a77d602657a19b30778a9f7e74fbb5a2ee88 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 21 Aug 2025 12:51:14 -0400 Subject: [PATCH 02/26] feature/IO-3255-simplified-parts-management - Checkoint --- .../validateFirebaseIdTokenLiteMiddleware.js | 42 ------------------- server/routes/renderRoutes.js | 9 ++-- 2 files changed, 4 insertions(+), 47 deletions(-) delete mode 100644 server/middleware/validateFirebaseIdTokenLiteMiddleware.js diff --git a/server/middleware/validateFirebaseIdTokenLiteMiddleware.js b/server/middleware/validateFirebaseIdTokenLiteMiddleware.js deleted file mode 100644 index 3da2d0871..000000000 --- a/server/middleware/validateFirebaseIdTokenLiteMiddleware.js +++ /dev/null @@ -1,42 +0,0 @@ -const logger = require("../utils/logger"); -const admin = require("firebase-admin"); - -/** - * Lite Firebase ID token validator. - * - Only accepts Authorization: Bearer - * - Sets req.user to the decoded token on success - */ -const validateFirebaseIdTokenLite = async (req, res, next) => { - const authHeader = req.headers.authorization || ""; - const match = authHeader.match(/^Bearer\s+(.+)$/i); - - if (!match) { - logger.log("api-authorization-call", "warn", null, null, { - type: "unauthorized", - reason: "missing Bearer token", - path: req.path, - body: req.body - }); - return res.status(401).send("Unauthorized"); - } - - const idToken = match[1].trim(); - - try { - const decodedIdToken = await admin.auth().verifyIdToken(idToken); - req.user = decodedIdToken; - return next(); - } catch (error) { - logger.log("api-unauthorized-call", "warn", null, null, { - type: "unauthorized", - reason: "invalid or expired token", - path: req.path, - body: req.body, - code: error?.errorInfo?.code || error?.code, - message: error?.message - }); - return res.status(401).send("Unauthorized"); - } -}; - -module.exports = validateFirebaseIdTokenLite; diff --git a/server/routes/renderRoutes.js b/server/routes/renderRoutes.js index 5bf651a34..41b6cf6aa 100644 --- a/server/routes/renderRoutes.js +++ b/server/routes/renderRoutes.js @@ -1,14 +1,13 @@ const express = require("express"); const router = express.Router(); const { inlineCSS } = require("../render/inlinecss"); -const validateFirebaseIdTokenLite = require("../middleware/validateFirebaseIdTokenLiteMiddleware"); +const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware"); const { canvas } = require("../render/canvas-handler"); const validateCanvasInputMiddleware = require("../middleware/validateCanvasInputMiddleware"); // Define the route for inline CSS rendering -router.post("/inlinecss", validateFirebaseIdTokenLite, inlineCSS); - -router.post("/canvas-skia", validateFirebaseIdTokenLite, validateCanvasInputMiddleware, canvas); -router.post("/canvas", validateFirebaseIdTokenLite, validateCanvasInputMiddleware, canvas); +router.post("/inlinecss", validateFirebaseIdTokenMiddleware, inlineCSS); +router.post("/canvas-skia", validateFirebaseIdTokenMiddleware, validateCanvasInputMiddleware, canvas); +router.post("/canvas", validateFirebaseIdTokenMiddleware, validateCanvasInputMiddleware, canvas); module.exports = router; From 6942d6e4f9fd83f980cc933373b8e64e5f34895d Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 21 Aug 2025 14:57:55 -0400 Subject: [PATCH 03/26] feature/IO-3255-simplified-parts-management - Cleanup / Bug fixes --- client/package-lock.json | 250 ++++++++++++++++++ client/package.json | 1 + .../phone-form-item.component.jsx | 9 +- .../global-footer/global-footer.component.jsx | 14 +- .../pages/manage/manage.page.component.jsx | 13 +- client/vite.config.js | 81 +++--- 6 files changed, 310 insertions(+), 58 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index b95636150..b3be0b3cd 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -108,6 +108,7 @@ "eslint-plugin-react": "^7.37.5", "globals": "^15.15.0", "jsdom": "^26.0.0", + "lightningcss": "^1.30.1", "memfs": "^4.36.3", "os-browserify": "^0.3.0", "playwright": "^1.54.2", @@ -10209,6 +10210,255 @@ "integrity": "sha512-aWVR6xXYYRvnK0v/uIwkf5Lthq9Jpn0N8TISW/oDTWlYB2sOimuiLn9Q26aUw4KxkJoiT8ACdiw44Y8VwKFIfQ==", "license": "MIT" }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", diff --git a/client/package.json b/client/package.json index 4c1953199..d32fce7b4 100644 --- a/client/package.json +++ b/client/package.json @@ -150,6 +150,7 @@ "eslint-plugin-react": "^7.37.5", "globals": "^15.15.0", "jsdom": "^26.0.0", + "lightningcss": "^1.30.1", "memfs": "^4.36.3", "os-browserify": "^0.3.0", "playwright": "^1.54.2", diff --git a/client/src/components/form-items-formatted/phone-form-item.component.jsx b/client/src/components/form-items-formatted/phone-form-item.component.jsx index 756d35c88..c25fbb415 100644 --- a/client/src/components/form-items-formatted/phone-form-item.component.jsx +++ b/client/src/components/form-items-formatted/phone-form-item.component.jsx @@ -4,13 +4,8 @@ import parsePhoneNumber from "libphonenumber-js"; import { forwardRef } from "react"; import "./phone-form-item.styles.scss"; -function FormItemPhone(props) { - return ( - - ); +function FormItemPhone(props, ref) { + return ; } export default forwardRef(FormItemPhone); diff --git a/client/src/components/global-footer/global-footer.component.jsx b/client/src/components/global-footer/global-footer.component.jsx index a66bdb0fd..9286de833 100644 --- a/client/src/components/global-footer/global-footer.component.jsx +++ b/client/src/components/global-footer/global-footer.component.jsx @@ -1,6 +1,5 @@ import { AlertOutlined, BulbOutlined } from "@ant-design/icons"; import { Button, Layout, Space } from "antd"; -import { useEffect } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { Link } from "react-router-dom"; @@ -17,18 +16,7 @@ const mapStateToProps = createStructuredSelector({ export function GlobalFooter({ isPartsEntry }) { const { t } = useTranslation(); - - useEffect(() => { - // Canny Not Required on Parts Entry - if (isPartsEntry) return; - window.Canny("initChangelog", { - appID: "680bd2c7ee501290377f6686", - position: "top", - align: "left", - theme: "light" // options: light [default], dark, auto - }); - }, [isPartsEntry]); - + if (isPartsEntry) { return (