feature/IO-3096-GlobalNotifications - Checkpoint, BULLMQ!

This commit is contained in:
Dave Richer
2025-02-13 16:19:36 -05:00
parent 5cfadf7929
commit df13f257db
13 changed files with 887 additions and 747 deletions

182
client/package-lock.json generated
View File

@@ -9,10 +9,10 @@
"version": "0.2.1",
"hasInstallScript": true,
"dependencies": {
"@ant-design/pro-layout": "^7.22.0",
"@apollo/client": "^3.12.6",
"@ant-design/pro-layout": "^7.22.2",
"@apollo/client": "^3.12.11",
"@emotion/is-prop-valid": "^1.3.1",
"@fingerprintjs/fingerprintjs": "^4.5.1",
"@fingerprintjs/fingerprintjs": "^4.6.0",
"@jsreport/browser-client": "^3.1.0",
"@reduxjs/toolkit": "^2.5.0",
"@sentry/cli": "^2.40.0",
@@ -20,7 +20,7 @@
"@splitsoftware/splitio-react": "^1.13.0",
"@tanem/react-nprogress": "^5.0.53",
"@vitejs/plugin-react": "^4.3.4",
"antd": "^5.23.1",
"antd": "^5.24.0",
"apollo-link-logger": "^2.0.1",
"apollo-link-sentry": "^3.3.0",
"autosize": "^6.0.1",
@@ -66,7 +66,7 @@
"react-resizable": "^3.0.5",
"react-router-dom": "^6.26.2",
"react-sticky": "^6.0.3",
"react-virtuoso": "^4.10.4",
"react-virtuoso": "^4.12.5",
"recharts": "^2.15.0",
"redux": "^5.0.1",
"redux-actions": "^3.0.3",
@@ -74,9 +74,9 @@
"redux-saga": "^1.3.0",
"redux-state-sync": "^3.1.4",
"reselect": "^5.1.1",
"sass": "^1.83.4",
"sass": "^1.84.0",
"socket.io-client": "^4.8.1",
"styled-components": "^6.1.14",
"styled-components": "^6.1.15",
"subscriptions-transport-ws": "^0.11.0",
"use-memo-one": "^1.1.3",
"userpilot": "^1.3.6",
@@ -84,13 +84,13 @@
"web-vitals": "^3.5.2"
},
"devDependencies": {
"@ant-design/icons": "^5.5.2",
"@ant-design/icons": "^5.6.1",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-react": "^7.26.3",
"@dotenvx/dotenvx": "^1.33.0",
"@dotenvx/dotenvx": "^1.36.0",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/react": "^11.14.0",
"@eslint/js": "^9.18.0",
"@eslint/js": "^9.20.0",
"@sentry/webpack-plugin": "^2.22.4",
"@testing-library/cypress": "^10.0.2",
"browserslist": "^4.24.4",
@@ -102,13 +102,13 @@
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-cypress": "^2.15.1",
"eslint-plugin-react": "^7.37.4",
"globals": "^15.14.0",
"globals": "^15.15.0",
"memfs": "^4.17.0",
"os-browserify": "^0.3.0",
"react-error-overlay": "6.0.11",
"redux-logger": "^3.0.6",
"source-map-explorer": "^2.5.3",
"vite": "^6.0.7",
"vite": "^6.1.0",
"vite-plugin-babel": "^1.3.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-node-polyfills": "^0.23.0",
@@ -192,9 +192,9 @@
}
},
"node_modules/@ant-design/icons": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.6.0.tgz",
"integrity": "sha512-Mb6QkQmPLZsmIHJ6oBsoyKrrT8/kAUdQ6+8q38e2bQSclROi69SiDlI4zZroaIPseae1w110RJH0zGrphAvlSQ==",
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.6.1.tgz",
"integrity": "sha512-0/xS39c91WjPAZOWsvi1//zjx6kAp4kxWwctR6kuU6p133w8RU0D2dSCvZC19uQyharg/sAvYxGYWl01BbZZfg==",
"license": "MIT",
"dependencies": {
"@ant-design/colors": "^7.0.0",
@@ -218,9 +218,9 @@
"license": "MIT"
},
"node_modules/@ant-design/pro-layout": {
"version": "7.22.1",
"resolved": "https://registry.npmjs.org/@ant-design/pro-layout/-/pro-layout-7.22.1.tgz",
"integrity": "sha512-aOwdd/u/yz/0ZHPDpnoVUIDGneZUDw62lCo3C4s6o0SGQrCOkYvY0efG4yLC4RA8eSFvXwnMt5pB7ii7f46KLQ==",
"version": "7.22.2",
"resolved": "https://registry.npmjs.org/@ant-design/pro-layout/-/pro-layout-7.22.2.tgz",
"integrity": "sha512-RlXqN+EVnF1Sup84O0IjS/vMMgwFnbBZwvR+GVnmZg/+cIa4/BDTXyhbb1KRwUqzn1ctDzj7JfbWOWqmGMw6yA==",
"license": "MIT",
"dependencies": {
"@ant-design/cssinjs": "^1.21.1",
@@ -322,9 +322,9 @@
}
},
"node_modules/@apollo/client": {
"version": "3.12.8",
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.12.8.tgz",
"integrity": "sha512-053z5eCM7zNl81Lxs/SqHv8e+x3sszrtmGS2TNuPW0ZTZzmKATMsIsoblx1Kt0E67Ze3jb99JSPiQHG9ozGc3g==",
"version": "3.12.11",
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.12.11.tgz",
"integrity": "sha512-1RppV9U3E6Uusl/33yGkZa+rXpkGU5iCstcYltwWjdTjoA/YBD2Yyu0aHy8J4uKfIExUgnMW1HJWn4A0E0rRsw==",
"license": "MIT",
"dependencies": {
"@graphql-typed-document-node/core": "^3.1.1",
@@ -343,7 +343,7 @@
},
"peerDependencies": {
"graphql": "^15.0.0 || ^16.0.0",
"graphql-ws": "^5.5.5",
"graphql-ws": "^5.5.5 || ^6.0.3",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc",
"subscriptions-transport-ws": "^0.9.0 || ^0.11.0"
@@ -2425,9 +2425,9 @@
}
},
"node_modules/@dotenvx/dotenvx": {
"version": "1.34.0",
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.34.0.tgz",
"integrity": "sha512-+Dp/xaI3IZ4eKv+b2vg4V89VnqLKbmJ7UZ7unnZxMu9SNLOSc2jYaXey1YHCJM+67T0pOr2Gbej3TewnuoqTWQ==",
"version": "1.36.0",
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.36.0.tgz",
"integrity": "sha512-SCS+N/UdQcMwJCefvC32K5VD4kV19wC32eR2lJ0S+9gurNngJAK96BZBPcIHNTi0tEFa71DBUbiRQiD2+OVyIQ==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -3141,9 +3141,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.19.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz",
"integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==",
"version": "9.20.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz",
"integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3151,9 +3151,9 @@
}
},
"node_modules/@fingerprintjs/fingerprintjs": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-4.5.1.tgz",
"integrity": "sha512-hKJaRoLHNeUUPhb+Md3pTlY/Js2YR4aXjroaDHpxrjoM8kGnEFyZVZxXo6l3gRyKnQN52Uoqsycd3M73eCdMzw==",
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-4.6.0.tgz",
"integrity": "sha512-g2z4lF2saGxVT+AQSmJhPSwW/hBn8vnFJMW6UYOMl9ipJT7re0RZbr2+lB2eCZj/lJ89wWc21FMA14v9iOKroQ==",
"license": "BUSL-1.1",
"dependencies": {
"tslib": "^2.4.1"
@@ -6759,16 +6759,16 @@
}
},
"node_modules/antd": {
"version": "5.23.3",
"resolved": "https://registry.npmjs.org/antd/-/antd-5.23.3.tgz",
"integrity": "sha512-xDvwl7C43/NZ9rTOS1bkbuKoSxqZKf6FlaSW/BRsV8QST3Ce2jGx7dJzYahKIZwe3WNSgvEXAlTrckBHMKHcgQ==",
"version": "5.24.0",
"resolved": "https://registry.npmjs.org/antd/-/antd-5.24.0.tgz",
"integrity": "sha512-05PZBIf6ijLHAQskBTW3nwS2t7tQmyLA6Xq8vK2Sk5tsgCsH/UE1cNCDYnKFGRJ7cKYuWJ565JDo9LejbiO42A==",
"license": "MIT",
"dependencies": {
"@ant-design/colors": "^7.2.0",
"@ant-design/cssinjs": "^1.23.0",
"@ant-design/cssinjs-utils": "^1.1.3",
"@ant-design/fast-color": "^2.0.6",
"@ant-design/icons": "^5.6.0",
"@ant-design/icons": "^5.6.1",
"@ant-design/react-slick": "~1.1.2",
"@babel/runtime": "^7.26.0",
"@rc-component/color-picker": "~2.0.1",
@@ -6792,11 +6792,11 @@
"rc-mentions": "~2.19.1",
"rc-menu": "~9.16.0",
"rc-motion": "^2.9.5",
"rc-notification": "~5.6.2",
"rc-pagination": "~5.0.0",
"rc-picker": "~4.9.2",
"rc-notification": "~5.6.3",
"rc-pagination": "~5.1.0",
"rc-picker": "~4.11.0",
"rc-progress": "~4.0.0",
"rc-rate": "~2.13.0",
"rc-rate": "~2.13.1",
"rc-resize-observer": "^1.4.3",
"rc-segmented": "~2.7.0",
"rc-select": "~14.16.6",
@@ -6804,13 +6804,13 @@
"rc-steps": "~6.0.1",
"rc-switch": "~4.1.0",
"rc-table": "~7.50.2",
"rc-tabs": "~15.5.0",
"rc-tabs": "~15.5.1",
"rc-textarea": "~1.9.0",
"rc-tooltip": "~6.3.2",
"rc-tooltip": "~6.4.0",
"rc-tree": "~5.13.0",
"rc-tree-select": "~5.27.0",
"rc-upload": "~4.8.1",
"rc-util": "^5.44.3",
"rc-util": "^5.44.4",
"scroll-into-view-if-needed": "^3.1.0",
"throttle-debounce": "^5.0.2"
},
@@ -11114,9 +11114,9 @@
"integrity": "sha512-5e01v8eLGfuQSOvx2MsDMOWS0GFtCx1wPzQSmcHw4hkxFzrQDBO3Xwg/m8Hr/7qXMrHeOIE29qWVzyv06u1TZA=="
},
"node_modules/globals": {
"version": "15.14.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz",
"integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==",
"version": "15.15.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
"integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -14736,9 +14736,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.38",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
"integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
"version": "8.4.49",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
"funding": [
{
"type": "opencollective",
@@ -14756,8 +14756,8 @@
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.0.0",
"source-map-js": "^1.2.0"
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -15258,9 +15258,9 @@
}
},
"node_modules/rc-notification": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.2.tgz",
"integrity": "sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==",
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.3.tgz",
"integrity": "sha512-42szwnn8VYQoT6GnjO00i1iwqV9D1TTMvxObWsuLwgl0TsOokzhkYiufdtQBsJMFjJravS1hfDKVMHLKLcPE4g==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.10.1",
@@ -15293,9 +15293,9 @@
}
},
"node_modules/rc-pagination": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-5.0.0.tgz",
"integrity": "sha512-QjrPvbAQwps93iluvFM62AEYglGYhWW2q/nliQqmvkTi4PXP4HHoh00iC1Sa5LLVmtWQHmG73fBi2x6H6vFHRg==",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-5.1.0.tgz",
"integrity": "sha512-8416Yip/+eclTFdHXLKTxZvn70duYVGTvUUWbckCCZoIl3jagqke3GLsFrMs0bsQBikiYpZLD9206Ej4SOdOXQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.10.1",
@@ -15308,9 +15308,9 @@
}
},
"node_modules/rc-picker": {
"version": "4.9.2",
"resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.9.2.tgz",
"integrity": "sha512-SLW4PRudODOomipKI0dvykxW4P8LOqtMr17MOaLU6NQJhkh9SZeh44a/8BMxwv5T6e3kiIeYc9k5jFg2Mv35Pg==",
"version": "4.11.1",
"resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.11.1.tgz",
"integrity": "sha512-qHaZrHrYjAVwMcKqMXJz9xHifQgQpKSav0E1ejOe3SFTHZggPlmKzLnA5i//Y4DEumR4HZEsePSOdOlmX1JvAw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.24.7",
@@ -15362,9 +15362,9 @@
}
},
"node_modules/rc-rate": {
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz",
"integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==",
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.1.tgz",
"integrity": "sha512-QUhQ9ivQ8Gy7mtMZPAjLbxBt5y9GRp65VcUyGUMF3N3fhiftivPHdpuDIaWIMOTEprAjZPC08bls1dQB+I1F2Q==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.10.1",
@@ -15506,9 +15506,9 @@
}
},
"node_modules/rc-tabs": {
"version": "15.5.0",
"resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.5.0.tgz",
"integrity": "sha512-NrDcTaUJLh9UuDdMBkjKTn97U9iXG44s9D03V5NHkhEDWO5/nC6PwC3RhkCWFMKB9hh+ryqgZ+TIr1b9Jd/hnQ==",
"version": "15.5.1",
"resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.5.1.tgz",
"integrity": "sha512-yiWivLAjEo5d1v2xlseB2dQocsOhkoVSfo1krS8v8r+02K+TBUjSjXIf7dgyVSxp6wRIPv5pMi5hanNUlQMgUA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.11.2",
@@ -15545,14 +15545,15 @@
}
},
"node_modules/rc-tooltip": {
"version": "6.3.2",
"resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.3.2.tgz",
"integrity": "sha512-oA4HZIiZJbUQ5ojigM0y4XtWxaH/aQlJSzknjICRWNpqyemy1sL3X3iEQV2eSPBWEq+bqU3+aSs81z+28j9luA==",
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.4.0.tgz",
"integrity": "sha512-kqyivim5cp8I5RkHmpsp1Nn/Wk+1oeloMv9c7LXNgDxUpGm+RbXJGL+OPvDlcRnx9DBeOe4wyOIl4OKUERyH1g==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.11.2",
"@rc-component/trigger": "^2.0.0",
"classnames": "^2.3.1"
"classnames": "^2.3.1",
"rc-util": "^5.44.3"
},
"peerDependencies": {
"react": ">=16.9.0",
@@ -15612,9 +15613,9 @@
}
},
"node_modules/rc-util": {
"version": "5.44.3",
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.44.3.tgz",
"integrity": "sha512-q6KCcOFk3rv/zD3MckhJteZxb0VjAIFuf622B7ElK4vfrZdAzs16XR5p3VTdy3+U5jfJU5ACz4QnhLSuAGe5dA==",
"version": "5.44.4",
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.44.4.tgz",
"integrity": "sha512-resueRJzmHG9Q6rI/DfK6Kdv9/Lfls05vzMs1Sk3M2P+3cJa+MakaZyWY8IPfehVuhPJFKrIY1IK4GqbiaiY5w==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.3",
@@ -16076,16 +16077,13 @@
}
},
"node_modules/react-virtuoso": {
"version": "4.12.3",
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.12.3.tgz",
"integrity": "sha512-6X1p/sU7hecmjDZMAwN+r3go9EVjofKhwkUbVlL8lXhBZecPv9XVCkZ/kBPYOr0Mv0Vl5+Ziwgexg9Kh7+NNXQ==",
"version": "4.12.5",
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.12.5.tgz",
"integrity": "sha512-YeCbRRsC9CLf0buD0Rct7WsDbzf+yBU1wGbo05/XjbcN2nJuhgh040m3y3+6HVogTZxEqVm45ac9Fpae4/MxRQ==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"react": ">=16 || >=17 || >= 18",
"react-dom": ">=16 || >=17 || >= 18"
"react": ">=16 || >=17 || >= 18 || >= 19",
"react-dom": ">=16 || >=17 || >= 18 || >=19"
}
},
"node_modules/reactcss": {
@@ -16800,9 +16798,9 @@
"license": "MIT"
},
"node_modules/sass": {
"version": "1.83.4",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.83.4.tgz",
"integrity": "sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA==",
"version": "1.84.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.84.0.tgz",
"integrity": "sha512-XDAbhEPJRxi7H0SxrnOpiXFQoUJHwkR2u3Zc4el+fK/Tt5Hpzw5kkQ59qVDfvdaUq6gCrEZIbySFBM2T9DNKHg==",
"license": "MIT",
"dependencies": {
"chokidar": "^4.0.0",
@@ -17714,9 +17712,9 @@
}
},
"node_modules/styled-components": {
"version": "6.1.14",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.14.tgz",
"integrity": "sha512-KtfwhU5jw7UoxdM0g6XU9VZQFV4do+KrM8idiVCH5h4v49W+3p3yMe0icYwJgZQZepa5DbH04Qv8P0/RdcLcgg==",
"version": "6.1.15",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.15.tgz",
"integrity": "sha512-PpOTEztW87Ua2xbmLa7yssjNyUF9vE7wdldRfn1I2E6RTkqknkBYpj771OxM/xrvRGinLy2oysa7GOd7NcZZIA==",
"license": "MIT",
"dependencies": {
"@emotion/is-prop-valid": "1.2.2",
@@ -17724,7 +17722,7 @@
"@types/stylis": "4.2.5",
"css-to-react-native": "3.2.0",
"csstype": "3.1.3",
"postcss": "8.4.38",
"postcss": "8.4.49",
"shallowequal": "1.1.0",
"stylis": "4.3.2",
"tslib": "2.6.2"
@@ -18964,15 +18962,15 @@
}
},
"node_modules/vite": {
"version": "6.0.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz",
"integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz",
"integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.24.2",
"postcss": "^8.4.49",
"rollup": "^4.23.0"
"postcss": "^8.5.1",
"rollup": "^4.30.1"
},
"bin": {
"vite": "bin/vite.js"

View File

@@ -8,10 +8,10 @@
"private": true,
"proxy": "http://localhost:4000",
"dependencies": {
"@ant-design/pro-layout": "^7.22.0",
"@apollo/client": "^3.12.6",
"@ant-design/pro-layout": "^7.22.2",
"@apollo/client": "^3.12.11",
"@emotion/is-prop-valid": "^1.3.1",
"@fingerprintjs/fingerprintjs": "^4.5.1",
"@fingerprintjs/fingerprintjs": "^4.6.0",
"@jsreport/browser-client": "^3.1.0",
"@reduxjs/toolkit": "^2.5.0",
"@sentry/cli": "^2.40.0",
@@ -19,7 +19,7 @@
"@splitsoftware/splitio-react": "^1.13.0",
"@tanem/react-nprogress": "^5.0.53",
"@vitejs/plugin-react": "^4.3.4",
"antd": "^5.23.1",
"antd": "^5.24.0",
"apollo-link-logger": "^2.0.1",
"apollo-link-sentry": "^3.3.0",
"autosize": "^6.0.1",
@@ -65,7 +65,7 @@
"react-resizable": "^3.0.5",
"react-router-dom": "^6.26.2",
"react-sticky": "^6.0.3",
"react-virtuoso": "^4.10.4",
"react-virtuoso": "^4.12.5",
"recharts": "^2.15.0",
"redux": "^5.0.1",
"redux-actions": "^3.0.3",
@@ -73,9 +73,9 @@
"redux-saga": "^1.3.0",
"redux-state-sync": "^3.1.4",
"reselect": "^5.1.1",
"sass": "^1.83.4",
"sass": "^1.84.0",
"socket.io-client": "^4.8.1",
"styled-components": "^6.1.14",
"styled-components": "^6.1.15",
"subscriptions-transport-ws": "^0.11.0",
"use-memo-one": "^1.1.3",
"userpilot": "^1.3.6",
@@ -120,13 +120,13 @@
"@rollup/rollup-linux-x64-gnu": "4.6.1"
},
"devDependencies": {
"@ant-design/icons": "^5.5.2",
"@ant-design/icons": "^5.6.1",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-react": "^7.26.3",
"@dotenvx/dotenvx": "^1.33.0",
"@dotenvx/dotenvx": "^1.36.0",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/react": "^11.14.0",
"@eslint/js": "^9.18.0",
"@eslint/js": "^9.20.0",
"@sentry/webpack-plugin": "^2.22.4",
"@testing-library/cypress": "^10.0.2",
"browserslist": "^4.24.4",
@@ -138,13 +138,13 @@
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-cypress": "^2.15.1",
"eslint-plugin-react": "^7.37.4",
"globals": "^15.14.0",
"globals": "^15.15.0",
"memfs": "^4.17.0",
"os-browserify": "^0.3.0",
"react-error-overlay": "6.0.11",
"redux-logger": "^3.0.6",
"source-map-explorer": "^2.5.3",
"vite": "^6.0.7",
"vite": "^6.1.0",
"vite-plugin-babel": "^1.3.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-node-polyfills": "^0.23.0",

View File

@@ -1,30 +1,7 @@
import { connect } from "react-redux";
import HeaderComponent from "./header.component";
// const mapDispatchToProps = (dispatch) => ({
// setUserLanguage: (language) => dispatch(setUserLanguage(language))
// });
// setUserLanguage was removed from signature because it is not used in the component, and it is throwing a deprecation warning
export function HeaderContainer() {
// Commented out the handleMenuClick function because it is not used in the component, and it is throwing a deprecation warning
/* const handleMenuClick = (e) => {
if (e.item.props.actiontype === "lang-select") {
i18next.changeLanguage(e.key, (err, t) => {
if (err) {
logImEXEvent("language_change_error", { error: err });
return console.log("Error encountered when changing languages.", err);
}
logImEXEvent("language_change", { language: e.key });
setUserLanguage(e.key);
});
}
};*/
// return <HeaderComponent handleMenuClick={handleMenuClick} />;
return <HeaderComponent />;
}

1186
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -19,37 +19,39 @@
"makeitpretty": "prettier --write \"**/*.{css,js,json,jsx,scss}\""
},
"dependencies": {
"@aws-sdk/client-cloudwatch-logs": "^3.738.0",
"@aws-sdk/client-elasticache": "^3.738.0",
"@aws-sdk/client-s3": "^3.738.0",
"@aws-sdk/client-secrets-manager": "^3.738.0",
"@aws-sdk/client-ses": "^3.738.0",
"@aws-sdk/credential-provider-node": "^3.738.0",
"@aws-sdk/client-cloudwatch-logs": "^3.744.0",
"@aws-sdk/client-elasticache": "^3.744.0",
"@aws-sdk/client-s3": "^3.744.0",
"@aws-sdk/client-secrets-manager": "^3.744.0",
"@aws-sdk/client-ses": "^3.744.0",
"@aws-sdk/credential-provider-node": "^3.744.0",
"@opensearch-project/opensearch": "^2.13.0",
"@socket.io/admin-ui": "^0.5.1",
"@socket.io/redis-adapter": "^8.3.0",
"aws4": "^1.13.2",
"axios": "^1.7.7",
"bee-queue": "^1.7.1",
"better-queue": "^3.8.12",
"bluebird": "^3.7.2",
"body-parser": "^1.20.3",
"bullmq": "^5.40.4",
"chart.js": "^4.4.6",
"cloudinary": "^2.5.1",
"compression": "^1.7.5",
"compression": "^1.8.0",
"cookie-parser": "^1.4.7",
"cors": "2.8.5",
"crisp-status-reporter": "^1.2.2",
"csrf": "^3.1.0",
"dd-trace": "^5.33.1",
"dd-trace": "^5.36.0",
"dinero.js": "^1.9.1",
"dotenv": "^16.4.5",
"express": "^4.21.1",
"firebase-admin": "^13.0.2",
"firebase-admin": "^13.1.0",
"graphql": "^16.10.0",
"graphql-request": "^6.1.0",
"inline-css": "^4.0.3",
"intuit-oauth": "^4.1.3",
"ioredis": "^5.4.2",
"intuit-oauth": "^4.2.0",
"ioredis": "^5.5.0",
"json-2-csv": "^5.5.8",
"juice": "^11.0.0",
"lodash": "^4.17.21",
@@ -76,14 +78,14 @@
"xmlbuilder2": "^3.1.1"
},
"devDependencies": {
"@eslint/js": "^9.19.0",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@eslint/js": "^9.20.0",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"concurrently": "^8.2.2",
"eslint": "^9.19.0",
"eslint": "^9.20.1",
"eslint-plugin-react": "^7.37.4",
"globals": "^15.14.0",
"globals": "^15.15.0",
"p-limit": "^3.1.0",
"prettier": "^3.3.3",
"prettier": "^3.5.1",
"source-map-explorer": "^2.5.2"
}
}

View File

@@ -4,3 +4,4 @@ cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
maxmemory-policy noeviction

View File

@@ -5,7 +5,7 @@ require("dotenv").config({
});
if (process.env.NODE_ENV) {
const tracer = require("dd-trace").init({
require("dd-trace").init({
profiling: true,
env: process.env.NODE_ENV,
service: "bodyshop-api"
@@ -31,6 +31,8 @@ const { redisSocketEvents } = require("./server/web-sockets/redisSocketEvents");
const { ElastiCacheClient, DescribeCacheClustersCommand } = require("@aws-sdk/client-elasticache");
const { InstanceRegion } = require("./server/utils/instanceMgr");
const StartStatusReporter = require("./server/utils/statusReporter");
const loadEmailQueue = require("./server/notifications/queues/emailQueue");
const loadAppQueue = require("./server/notifications/queues/appQueue");
const cleanupTasks = [];
let isShuttingDown = false;
@@ -58,7 +60,7 @@ const SOCKETIO_CORS_ORIGIN = [
"https://beta.test.imex.online",
"https://www.beta.test.imex.online",
"https://beta.imex.online",
"https://www.beta.imex.online",
"https://www.beta.imex.online",
"https://www.test.promanager.web-est.com",
"https://test.promanager.web-est.com",
"https://www.promanager.web-est.com",
@@ -287,6 +289,28 @@ const applySocketIO = async ({ server, app }) => {
return api;
};
/**
* Load Queues for Email and App
*/
const loadQueues = async ({ pubClient, logger, redisHelpers }) => {
const queueSettings = { pubClient, logger, redisHelpers };
// Assuming loadEmailQueue and loadAppQueue return Promises
const [notificationsEmailsQueue, notificationsAppQueue] = await Promise.all([
loadEmailQueue()(queueSettings),
loadAppQueue()(queueSettings)
]);
// Add error listeners or other setup for queues if needed
notificationsEmailsQueue.on("error", (error) => {
logger.log(`Error in notificationsEmailsQueue: ${error}`, "ERROR", "queue", "api", null, { error: error?.message });
});
notificationsAppQueue.on("error", (error) => {
logger.log(`Error in notificationsAppQueue: ${error}`, "ERROR", "queue", "api", null, { error: error?.message });
});
};
/**
* Main function to start the server
* @returns {Promise<void>}
@@ -304,6 +328,9 @@ const main = async () => {
// Legacy Socket Events
require("./server/web-sockets/web-socket");
// Initialize Queues
await loadQueues({ pubClient: pubClient, logger, redisHelpers });
applyMiddleware({ app });
applyRoutes({ app });
redisSocketEvents({ io: ioRedis, redisHelpers, ioHelpers, logger });
@@ -321,7 +348,7 @@ const main = async () => {
await server.listen(port);
logger.log(`Server started on port ${port}`, "INFO", "api");
} catch (error) {
logger.log(`Server failed to start on port ${port}`, "ERROR", "api", error);
logger.log(`Server failed to start on port ${port}`, "ERROR", "api", null, { error: error.message });
}
};

View File

@@ -2721,7 +2721,7 @@ query GET_JOB_WATCHERS($jobid: uuid!) {
}
}
job: jobs_by_pk(id: $jobid) {
id,
id
ro_number
clm_no
bodyshop {

View File

@@ -0,0 +1,16 @@
const { Queue } = require("bullmq");
let appQueue;
const loadAppQueue = async ({ pubClient, logger, redisHelpers }) => {
if (!appQueue) {
logger.logger.info("Initializing Notifications App Queue");
appQueue = await new Queue("notificationsApp", { connection: pubClient, prefix: "{BULLMQ}" });
}
return appQueue;
};
const getQueue = () => (!appQueue ? loadAppQueue : appQueue);
module.exports = getQueue;

View File

@@ -0,0 +1,40 @@
const { Queue, Worker } = require("bullmq");
let emailQueue;
const loadEmailQueue = async ({ pubClient, logger, redisHelpers }) => {
if (!emailQueue) {
logger.logger.info("Initializing Notifications Email Queue");
emailQueue = await new Queue("notificationsEmails", { connection: pubClient, prefix: "{BULLMQ}" });
}
// TODO: Test code for worker
// const worker = new Worker(
// "notificationsEmails",
// async (job) => {
// console.log("Processing job", job.id, "with data", job.data);
// // Simulate some work
// await new Promise((resolve) => setTimeout(resolve, 2000)); // Wait for 2 seconds
// console.log("Job processed");
// },
// { connection: pubClient, prefix: "{BULLMQ}" }
// );
//
// worker.on("completed", (job) => {
// console.log(`Job ${job.id} completed!`);
// // Optionally, close the worker after it's done
// worker.close().then(() => {
// console.log("Worker closed");
// });
// });
//
// worker.on("error", (err) => {
// console.error("Error in worker:", err);
// });
return emailQueue;
};
const getQueue = () => (!emailQueue ? loadEmailQueue : emailQueue);
module.exports = getQueue;

View File

@@ -1,4 +1,5 @@
const consoleDir = require("../utils/consoleDir");
const { getJobAssignmentType } = require("./stringHelpers");
const alternateTransportChangedBuilder = (data) => {
consoleDir(data);
@@ -17,7 +18,23 @@ const intakeDeliveryChecklistCompletedBuilder = (data) => {
};
const jobAssignedToMeBuilder = (data) => {
consoleDir(data);
return {
app: {
key: "notifications.job.assigned",
variables: {
type: data.scenarioFields?.[0],
jobId: data.jobId,
bodyShopName: data.bodyShopName
},
recipients: data.scenarioWatchers.map((watcher) => ({ email: watcher.user, employeeId: watcher.employeeId }))
},
email: {
subject: `You have been assigned to [${getJobAssignmentType(data.scenarioFields?.[0])}] on ${data?.jobRoNumber} in ${data.bodyShopName}`,
body: `Hello, a new job has been assigned to you in ${data.bodyShopName}.`,
recipient: data.scenarioWatchers.map((watcher) => watcher.user)
},
fcm: {}
};
};
const jobsAddedToProductionBuilder = (data) => {

View File

@@ -9,6 +9,7 @@ const { client: gqlClient } = require("../graphql-client/graphql-client");
const queries = require("../graphql-client/queries");
const { isEmpty, isFunction } = require("lodash");
const { getMatchingScenarios } = require("./scenarioMapperr");
const emailQueue = require("./queues/emailQueue");
/**
* Parses an event and determines matching scenarios for notifications.
@@ -80,6 +81,8 @@ const scenarioParser = async (req, jobIdField) => {
// console.log(`3`);
const bodyShopId = watcherData?.job?.bodyshop?.id;
const bodyShopName = watcherData?.job?.bodyshop?.shopname;
const jobRoNumber = watcherData?.job?.ro_number;
const jobClaimNumber = watcherData?.job?.clm_no;
if (!bodyShopId || !bodyShopName) {
throw new Error("No bodyshop data found for this job.");
@@ -149,6 +152,9 @@ const scenarioParser = async (req, jobIdField) => {
// Step 7: Trigger scenario builders for matching scenarios with eligible watchers.
// console.log(`7`);
const scenariosToDispatch = [];
for (const scenario of finalScenarioData.matchingScenarios) {
if (isEmpty(scenario.scenarioWatchers) || !isFunction(scenario.builder)) {
continue;
@@ -171,25 +177,45 @@ const scenarioParser = async (req, jobIdField) => {
// Step 8: Filter scenario fields to only include changed fields.
// console.log(`8`);
const filteredScenarioFields =
scenario.fields?.filter((field) => eventData.changedFieldNames.includes(field)) || [];
scenario.builder({
trigger: finalScenarioData.trigger.name,
bodyShopId: finalScenarioData.bodyShopId,
bodyShopName: finalScenarioData.bodyShopName,
scenarioKey: scenario.key,
scenarioTable: scenario.table,
scenarioFields: filteredScenarioFields,
scenarioBuilder: scenario.builder,
scenarioWatchers: eligibleWatchers,
jobId: finalScenarioData.jobId,
isNew: finalScenarioData.isNew,
changedFieldNames: finalScenarioData.changedFieldNames,
changedFields: finalScenarioData.changedFields,
data: finalScenarioData.data
});
scenariosToDispatch.push(
scenario.builder({
trigger: finalScenarioData.trigger.name,
bodyShopId: finalScenarioData.bodyShopId,
bodyShopName: finalScenarioData.bodyShopName,
scenarioKey: scenario.key,
scenarioTable: scenario.table,
scenarioFields: filteredScenarioFields,
scenarioBuilder: scenario.builder,
scenarioWatchers: eligibleWatchers,
jobId: finalScenarioData.jobId,
jobRoNumber: jobRoNumber,
jobClaimNumber: jobClaimNumber,
isNew: finalScenarioData.isNew,
changedFieldNames: finalScenarioData.changedFieldNames,
changedFields: finalScenarioData.changedFields,
data: finalScenarioData.data
})
);
}
if (isEmpty(scenariosToDispatch)) {
return;
}
// Step 9: Dispatch Email Notifications to the Email Notification Queue
// console.log(`8`);
const emailsToDispatch = scenariosToDispatch.map((scenario) => scenario.email);
// Step 10: Dispatch App Notifications to the App Notification Queue
const appsToDispatch = scenariosToDispatch.map((scenario) => scenario.app);
// TODO: Test Code for Queues
// emailQueue().add("test", { data: "test" });
};
module.exports = scenarioParser;

View File

@@ -0,0 +1,18 @@
const getJobAssignmentType = (data) => {
switch (data) {
case "employee_pre":
return "Prep";
case "employee_body":
return "Body";
case "employee_csr":
return "CSR";
case "employee_refinish":
return "Refinish";
default:
return "";
}
};
module.exports = {
getJobAssignmentType
};