16
.prettierrc.js
Normal file
16
.prettierrc.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
exports.default = {
|
||||||
|
printWidth: 120,
|
||||||
|
useTabs: false,
|
||||||
|
tabWidth: 2,
|
||||||
|
trailingComma: "es5",
|
||||||
|
semi: true,
|
||||||
|
singleQuote: false,
|
||||||
|
bracketSpacing: true,
|
||||||
|
arrowParens: "always",
|
||||||
|
jsxSingleQuote: false,
|
||||||
|
bracketSameLine: false,
|
||||||
|
endOfLine: "lf",
|
||||||
|
importOrder: ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
|
||||||
|
importOrderSeparation: true,
|
||||||
|
importOrderSortSpecifiers: true,
|
||||||
|
};
|
||||||
@@ -3,7 +3,13 @@
|
|||||||
This documentation details the schema required for `.filters` files on the report server. It is used to dynamically
|
This documentation details the schema required for `.filters` files on the report server. It is used to dynamically
|
||||||
modify the graphQL query and provide the user more power over their reports.
|
modify the graphQL query and provide the user more power over their reports.
|
||||||
|
|
||||||
# Special Notes
|
For filters and sorters, valid types include (`type` key in the schema):
|
||||||
|
- string (default)
|
||||||
|
- number
|
||||||
|
- bool or boolean
|
||||||
|
- date
|
||||||
|
|
||||||
|
## Special Notes
|
||||||
- When passing the data to the template server, the property filters and sorters is added to the data object and will reflect the filters and sorters the user has selected
|
- When passing the data to the template server, the property filters and sorters is added to the data object and will reflect the filters and sorters the user has selected
|
||||||
|
|
||||||
## High level Schema Overview
|
## High level Schema Overview
|
||||||
@@ -40,9 +46,10 @@ Filters effect the where clause of the graphQL query. They are used to filter th
|
|||||||
A note on special notation used in the `name` field.
|
A note on special notation used in the `name` field.
|
||||||
|
|
||||||
## Reflection
|
## Reflection
|
||||||
|
|
||||||
Filters can make use of reflection to pre-fill select boxes, the following is an example of that in the filters file.
|
Filters can make use of reflection to pre-fill select boxes, the following is an example of that in the filters file.
|
||||||
|
|
||||||
```
|
```json
|
||||||
{
|
{
|
||||||
"name": "jobs.status",
|
"name": "jobs.status",
|
||||||
"translation": "jobs.fields.status",
|
"translation": "jobs.fields.status",
|
||||||
@@ -67,7 +74,9 @@ The following cases are available
|
|||||||
- `special.employees` - This will reflect the employees `bodyshop.employees`
|
- `special.employees` - This will reflect the employees `bodyshop.employees`
|
||||||
- `special.first_names` - This will reflect the first names `bodyshop.employees`
|
- `special.first_names` - This will reflect the first names `bodyshop.employees`
|
||||||
- `special.last_names` - This will reflect the last names `bodyshop.employees`
|
- `special.last_names` - This will reflect the last names `bodyshop.employees`
|
||||||
-
|
- `special.referral_sources` - This will reflect the referral sources `bodyshop.md_referral_sources
|
||||||
|
- `special.class`- This will reflect the class `bodyshop.md_classes`
|
||||||
|
-
|
||||||
### Path without brackets, multi level
|
### Path without brackets, multi level
|
||||||
|
|
||||||
`"name": "jobs.joblines.mod_lb_hrs",`
|
`"name": "jobs.joblines.mod_lb_hrs",`
|
||||||
@@ -142,8 +151,7 @@ query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz!
|
|||||||
|
|
||||||
- Will only support two level of nesting in the graphQL query `jobs.joblines.mod_lb_hrs` vs `[jobs].joblines.mod_lb_hrs`
|
- Will only support two level of nesting in the graphQL query `jobs.joblines.mod_lb_hrs` vs `[jobs].joblines.mod_lb_hrs`
|
||||||
is fine, but `jobs.[joblines.].some_table.mod_lb_hrs` is not.
|
is fine, but `jobs.[joblines.].some_table.mod_lb_hrs` is not.
|
||||||
- The `dates` object is not yet implemented and will be added in a future release.
|
- The type object must be 'string' or 'number' or 'bool' or 'boolean' or 'date' and is case-sensitive.
|
||||||
- The type object must be 'string' or 'number' and is case-sensitive.
|
|
||||||
- The `translation` key is used to look up the label in the GUI, if it is not found, the `label` key is used.
|
- The `translation` key is used to look up the label in the GUI, if it is not found, the `label` key is used.
|
||||||
- Do not add the ability to filter things that are already filtered as part of the original query, this would be
|
- Do not add the ability to filter things that are already filtered as part of the original query, this would be
|
||||||
redundant and could cause issues.
|
redundant and could cause issues.
|
||||||
@@ -158,6 +166,7 @@ query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz!
|
|||||||
using the sorters.
|
using the sorters.
|
||||||
|
|
||||||
### Default Sorters
|
### Default Sorters
|
||||||
|
|
||||||
- A sorter can be given a default object containing a `order` and `direction` key value. This will be used to sort the report if the user does not select any of the sorters themselves.
|
- A sorter can be given a default object containing a `order` and `direction` key value. This will be used to sort the report if the user does not select any of the sorters themselves.
|
||||||
- The `order` key is the order in which the sorters are applied, and the `direction` key is the direction of the sort, either `asc` or `desc`.
|
- The `order` key is the order in which the sorters are applied, and the `direction` key is the direction of the sort, either `asc` or `desc`.
|
||||||
|
|
||||||
@@ -172,4 +181,4 @@ query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz!
|
|||||||
"direction": "asc"
|
"direction": "asc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
513
client/package-lock.json
generated
513
client/package-lock.json
generated
@@ -17,8 +17,8 @@
|
|||||||
"@jsreport/browser-client": "^3.1.0",
|
"@jsreport/browser-client": "^3.1.0",
|
||||||
"@reduxjs/toolkit": "^2.2.1",
|
"@reduxjs/toolkit": "^2.2.1",
|
||||||
"@sentry/cli": "^2.28.6",
|
"@sentry/cli": "^2.28.6",
|
||||||
"@sentry/react": "^7.102.1",
|
"@sentry/react": "^7.104.0",
|
||||||
"@sentry/tracing": "^7.102.1",
|
"@sentry/tracing": "^7.104.0",
|
||||||
"@splitsoftware/splitio-react": "^1.11.0",
|
"@splitsoftware/splitio-react": "^1.11.0",
|
||||||
"@tanem/react-nprogress": "^5.0.51",
|
"@tanem/react-nprogress": "^5.0.51",
|
||||||
"antd": "^5.14.2",
|
"antd": "^5.14.2",
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"enquire-js": "^0.2.1",
|
"enquire-js": "^0.2.1",
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"exifr": "^7.1.3",
|
"exifr": "^7.1.3",
|
||||||
"firebase": "^10.8.0",
|
"firebase": "^10.8.1",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
"i18next": "^23.10.0",
|
"i18next": "^23.10.0",
|
||||||
"i18next-browser-languagedetector": "^7.0.2",
|
"i18next-browser-languagedetector": "^7.0.2",
|
||||||
@@ -46,11 +46,11 @@
|
|||||||
"phone": "^3.1.42",
|
"phone": "^3.1.42",
|
||||||
"preval.macro": "^5.0.0",
|
"preval.macro": "^5.0.0",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"query-string": "^8.2.0",
|
"query-string": "^9.0.0",
|
||||||
"rc-queue-anim": "^2.0.0",
|
"rc-queue-anim": "^2.0.0",
|
||||||
"rc-scroll-anim": "^2.7.6",
|
"rc-scroll-anim": "^2.7.6",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-big-calendar": "^1.10.3",
|
"react-big-calendar": "^1.11.0",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
"react-cookie": "^7.1.0",
|
"react-cookie": "^7.1.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@@ -62,15 +62,15 @@
|
|||||||
"react-image-lightbox": "^5.1.4",
|
"react-image-lightbox": "^5.1.4",
|
||||||
"react-intersection-observer": "^9.8.1",
|
"react-intersection-observer": "^9.8.1",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-number-format": "^5.1.4",
|
"react-number-format": "^5.3.3",
|
||||||
"react-redux": "^9.1.0",
|
"react-redux": "^9.1.0",
|
||||||
"react-resizable": "^3.0.5",
|
"react-resizable": "^3.0.5",
|
||||||
"react-router-dom": "^6.22.1",
|
"react-router-dom": "^6.22.2",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"react-sticky": "^6.0.3",
|
"react-sticky": "^6.0.3",
|
||||||
"react-sublime-video": "^0.2.5",
|
"react-sublime-video": "^0.2.5",
|
||||||
"react-virtualized": "^9.22.5",
|
"react-virtualized": "^9.22.5",
|
||||||
"recharts": "^2.12.1",
|
"recharts": "^2.12.2",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-saga": "^1.3.0",
|
"redux-saga": "^1.3.0",
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
"workbox-precaching": "^7.0.0",
|
"workbox-precaching": "^7.0.0",
|
||||||
"workbox-routing": "^7.0.0",
|
"workbox-routing": "^7.0.0",
|
||||||
"workbox-strategies": "^7.0.0",
|
"workbox-strategies": "^7.0.0",
|
||||||
"yauzl": "^3.1.0"
|
"yauzl": "^3.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||||
@@ -2991,9 +2991,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fastify/busboy": {
|
"node_modules/@fastify/busboy": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
|
||||||
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==",
|
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
@@ -3042,9 +3042,9 @@
|
|||||||
"integrity": "sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw=="
|
"integrity": "sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw=="
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/app": {
|
"node_modules/@firebase/app": {
|
||||||
"version": "0.9.27",
|
"version": "0.9.28",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.27.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.28.tgz",
|
||||||
"integrity": "sha512-p2Dvl1ge4kRsyK5+wWcmdAIE9MSwZ0pDKAYB51LZgZuz6wciUZk4E1yAEdkfQlRxuHehn+Ol9WP5Qk2XQZiHGg==",
|
"integrity": "sha512-MS0+EtNixrwJbVDs5Bt/lhUhzeWGUtUoP6X+zYZck5GAZwI5g4F91noVA9oIXlFlpn6Q1xIbiaHA2GwGk7/7Ag==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/component": "0.6.5",
|
"@firebase/component": "0.6.5",
|
||||||
"@firebase/logger": "0.4.0",
|
"@firebase/logger": "0.4.0",
|
||||||
@@ -3094,11 +3094,11 @@
|
|||||||
"integrity": "sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ=="
|
"integrity": "sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/app-compat": {
|
"node_modules/@firebase/app-compat": {
|
||||||
"version": "0.2.27",
|
"version": "0.2.28",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.27.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.28.tgz",
|
||||||
"integrity": "sha512-SYlqocfUDKPHR6MSFC8hree0BTiWFu5o8wbf6zFlYXyG41w7TcHp4wJi4H/EL5V6cM4kxwruXTJtqXX/fRAZtw==",
|
"integrity": "sha512-Mr2NbeM1Oaayuw5unUAMzt+7/MN+e2uklT1l87D+ZLJl2UvhZAZmMt74GjEI9N3sDYKMeszSbszBqtJ1fGVafQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/app": "0.9.27",
|
"@firebase/app": "0.9.28",
|
||||||
"@firebase/component": "0.6.5",
|
"@firebase/component": "0.6.5",
|
||||||
"@firebase/logger": "0.4.0",
|
"@firebase/logger": "0.4.0",
|
||||||
"@firebase/util": "1.9.4",
|
"@firebase/util": "1.9.4",
|
||||||
@@ -3111,15 +3111,15 @@
|
|||||||
"integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q=="
|
"integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q=="
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/auth": {
|
"node_modules/@firebase/auth": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.6.1.tgz",
|
||||||
"integrity": "sha512-Qhl35eJTV6BwvuueTPCY6x8kUlYyzALtjp/Ws0X3fw3AnjVVfuVb7oQ3Xh5VPVfMFhaIuUAd1KXwcAuIklkSDw==",
|
"integrity": "sha512-oOuQVOxtxKr+kTTqEkkI2qXIeGbkNLpA8FzO030LF4KXmMcETqsPaIqw7Aw1Y4Zl82l1qpZtpc4vN4Da2qZdfQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/component": "0.6.5",
|
"@firebase/component": "0.6.5",
|
||||||
"@firebase/logger": "0.4.0",
|
"@firebase/logger": "0.4.0",
|
||||||
"@firebase/util": "1.9.4",
|
"@firebase/util": "1.9.4",
|
||||||
"tslib": "^2.1.0",
|
"tslib": "^2.1.0",
|
||||||
"undici": "5.26.5"
|
"undici": "5.28.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@firebase/app": "0.x",
|
"@firebase/app": "0.x",
|
||||||
@@ -3132,16 +3132,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/auth-compat": {
|
"node_modules/@firebase/auth-compat": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.3.tgz",
|
||||||
"integrity": "sha512-pRgje5BPCNR1vXyvGOVXwOHtv88A2WooXfklI8sV7/jWi03ExFqNfpJT26GUo/oD39NoKJ3Kt6rD5gVvdV7lMw==",
|
"integrity": "sha512-2pVtVEvu8P7SF6jSPfLPKWUClQFj+StqAZ0fD/uQ6mv8DyWn7AuuANFEu7Pv96JPcaL6Gy9jC5dFqjpptjqSRA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/auth": "1.6.0",
|
"@firebase/auth": "1.6.1",
|
||||||
"@firebase/auth-types": "0.12.0",
|
"@firebase/auth-types": "0.12.0",
|
||||||
"@firebase/component": "0.6.5",
|
"@firebase/component": "0.6.5",
|
||||||
"@firebase/util": "1.9.4",
|
"@firebase/util": "1.9.4",
|
||||||
"tslib": "^2.1.0",
|
"tslib": "^2.1.0",
|
||||||
"undici": "5.26.5"
|
"undici": "5.28.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@firebase/app-compat": "0.x"
|
"@firebase/app-compat": "0.x"
|
||||||
@@ -3207,9 +3207,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/firestore": {
|
"node_modules/@firebase/firestore": {
|
||||||
"version": "4.4.2",
|
"version": "4.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.4.3.tgz",
|
||||||
"integrity": "sha512-YaX6ypa/RzU6OkxzUQlpSxwhOIWdTraCNz7sMsbaSEjjl/pj/QvX6TqjkdWGzuBYh2S6rz7ErhDO0g39oZZw/g==",
|
"integrity": "sha512-Ix61zbeuTsHf0WFbk6+67n89Vzd9M8MMTdnz7c7z+BRE3BS5Vuc3gX5ZcHFjqPkQJ7rpLB1egHsYe4Przp5C2g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/component": "0.6.5",
|
"@firebase/component": "0.6.5",
|
||||||
"@firebase/logger": "0.4.0",
|
"@firebase/logger": "0.4.0",
|
||||||
@@ -3218,7 +3218,7 @@
|
|||||||
"@grpc/grpc-js": "~1.9.0",
|
"@grpc/grpc-js": "~1.9.0",
|
||||||
"@grpc/proto-loader": "^0.7.8",
|
"@grpc/proto-loader": "^0.7.8",
|
||||||
"tslib": "^2.1.0",
|
"tslib": "^2.1.0",
|
||||||
"undici": "5.26.5"
|
"undici": "5.28.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.10.0"
|
"node": ">=10.10.0"
|
||||||
@@ -3228,12 +3228,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/firestore-compat": {
|
"node_modules/@firebase/firestore-compat": {
|
||||||
"version": "0.3.25",
|
"version": "0.3.26",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.25.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.26.tgz",
|
||||||
"integrity": "sha512-+xI7WmsgZCBhMn/+uhDKcg+lsOUJ9FJyt5PGTzkFPbCsozWfeQZ7eVnfPh0rMkUOf0yIQ924RIe04gwvEIbcoQ==",
|
"integrity": "sha512-dNrKiH5Cn6ItANV9nJI2Y0msKBj/skO7skDlRo/BUSQE1DKbNzumxpJEz+PK/PV1nTegnRgVvs47gpQeVWXtYQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/component": "0.6.5",
|
"@firebase/component": "0.6.5",
|
||||||
"@firebase/firestore": "4.4.2",
|
"@firebase/firestore": "4.4.3",
|
||||||
"@firebase/firestore-types": "3.0.0",
|
"@firebase/firestore-types": "3.0.0",
|
||||||
"@firebase/util": "1.9.4",
|
"@firebase/util": "1.9.4",
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
@@ -3252,9 +3252,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/functions": {
|
"node_modules/@firebase/functions": {
|
||||||
"version": "0.11.1",
|
"version": "0.11.2",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.2.tgz",
|
||||||
"integrity": "sha512-3uUa1hB79Gmy6E1gHTfzoHeZolBeHc/I/n3+lOCDe6BOos9AHmzRjKygcFE/7VA2FJjitCE0K+OHI6+OuoY8fQ==",
|
"integrity": "sha512-2NULTYOZbu0rXczwfYdqQH0w1FmmYrKjTy1YPQSHLCAkMBdfewoKmVm4Lyo2vRn0H9ZndciLY7NszKDFt9MKCQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/app-check-interop-types": "0.3.0",
|
"@firebase/app-check-interop-types": "0.3.0",
|
||||||
"@firebase/auth-interop-types": "0.2.1",
|
"@firebase/auth-interop-types": "0.2.1",
|
||||||
@@ -3262,19 +3262,19 @@
|
|||||||
"@firebase/messaging-interop-types": "0.2.0",
|
"@firebase/messaging-interop-types": "0.2.0",
|
||||||
"@firebase/util": "1.9.4",
|
"@firebase/util": "1.9.4",
|
||||||
"tslib": "^2.1.0",
|
"tslib": "^2.1.0",
|
||||||
"undici": "5.26.5"
|
"undici": "5.28.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@firebase/app": "0.x"
|
"@firebase/app": "0.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/functions-compat": {
|
"node_modules/@firebase/functions-compat": {
|
||||||
"version": "0.3.7",
|
"version": "0.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.8.tgz",
|
||||||
"integrity": "sha512-uXe6Kmku5lNogp3OpPBcOJbSvnaCOn+YxS3zlXKNU6Q/NLwcvO3RY1zwYyctCos2RemEw3KEQ7YdzcECXjHWLw==",
|
"integrity": "sha512-VDHSw6UOu8RxfgAY/q8e+Jn+9Fh60Fc28yck0yfMsi2e0BiWgonIMWkFspFGGLgOJebTHl+hc+9v91rhzU6xlg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/component": "0.6.5",
|
"@firebase/component": "0.6.5",
|
||||||
"@firebase/functions": "0.11.1",
|
"@firebase/functions": "0.11.2",
|
||||||
"@firebase/functions-types": "0.6.0",
|
"@firebase/functions-types": "0.6.0",
|
||||||
"@firebase/util": "1.9.4",
|
"@firebase/util": "1.9.4",
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
@@ -3441,26 +3441,26 @@
|
|||||||
"integrity": "sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA=="
|
"integrity": "sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA=="
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/storage": {
|
"node_modules/@firebase/storage": {
|
||||||
"version": "0.12.1",
|
"version": "0.12.2",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.2.tgz",
|
||||||
"integrity": "sha512-KJ5NV7FUh54TeTlEjdkTTX60ciCKOp9EqlbLnpdcXUYRJg0Z4810TXbilPc1z7fTIG4iPjtdi95bGE9n4dBX8A==",
|
"integrity": "sha512-MzanOBcxDx9oOwDaDPMuiYxd6CxcN1xZm+os5uNE3C1itbRKLhM9rzpODDKWzcbnHHFtXk3Q3lsK/d3Xa1WYYw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/component": "0.6.5",
|
"@firebase/component": "0.6.5",
|
||||||
"@firebase/util": "1.9.4",
|
"@firebase/util": "1.9.4",
|
||||||
"tslib": "^2.1.0",
|
"tslib": "^2.1.0",
|
||||||
"undici": "5.26.5"
|
"undici": "5.28.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@firebase/app": "0.x"
|
"@firebase/app": "0.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@firebase/storage-compat": {
|
"node_modules/@firebase/storage-compat": {
|
||||||
"version": "0.3.4",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.5.tgz",
|
||||||
"integrity": "sha512-Y0m5e2gS/wB9Ioth2X/Sgz76vcxvqgQrCmfa9qwhss/N31kxY2Gks6Frv0nrE18AjVfcSmcfDitqUwxcMOTRSg==",
|
"integrity": "sha512-5dJXfY5NxCF5NAk4dLvJqC+m6cgcf0Fr29nrMHwhwI34pBheQq2PdRZqALsqZCES9dnHTuFNlqGQDpLr+Ph4rw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/component": "0.6.5",
|
"@firebase/component": "0.6.5",
|
||||||
"@firebase/storage": "0.12.1",
|
"@firebase/storage": "0.12.2",
|
||||||
"@firebase/storage-types": "0.8.0",
|
"@firebase/storage-types": "0.8.0",
|
||||||
"@firebase/util": "1.9.4",
|
"@firebase/util": "1.9.4",
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
@@ -4394,9 +4394,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@remix-run/router": {
|
"node_modules/@remix-run/router": {
|
||||||
"version": "1.15.1",
|
"version": "1.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.1.tgz",
|
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz",
|
||||||
"integrity": "sha512-zcU0gM3z+3iqj8UX45AmWY810l3oUmXM7uH4dt5xtzvMhRtYVhKGOmgOd1877dOPPepfCjUv57w+syamWIYe7w==",
|
"integrity": "sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
@@ -4500,89 +4500,40 @@
|
|||||||
"integrity": "sha512-2/U3GXA6YiPYQDLGwtGlnNgKYBSwCFIHf8Y9LUY5VATHdtbLlU0Y1R3QoBnT0aB4qv/BEiVVsj7LJXoQCgJ2vA=="
|
"integrity": "sha512-2/U3GXA6YiPYQDLGwtGlnNgKYBSwCFIHf8Y9LUY5VATHdtbLlU0Y1R3QoBnT0aB4qv/BEiVVsj7LJXoQCgJ2vA=="
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/feedback": {
|
"node_modules/@sentry-internal/feedback": {
|
||||||
"version": "7.102.1",
|
"version": "7.104.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.102.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.104.0.tgz",
|
||||||
"integrity": "sha512-vY4hpLLMNLjICtWiizc7KeGbWOTUMGrF7C+9dPCztZww3CLgzWy9A7DvPj5hodRiYzpdRnAMl8yQnMFbYXh7bA==",
|
"integrity": "sha512-+OWqm+X9ZfEQQmxVoZsc9lpzd85pabAT+bEj57StRMTnfdRbD9TippS20nCD9N2Ql5v2/41NfiPONMejGbnOwg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/core": "7.102.1",
|
"@sentry/core": "7.104.0",
|
||||||
"@sentry/types": "7.102.1",
|
"@sentry/types": "7.104.0",
|
||||||
"@sentry/utils": "7.102.1"
|
"@sentry/utils": "7.104.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/feedback/node_modules/@sentry/core": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-QjY+LSP3du3J/C8x/FfEbRxgZgsWd0jfTJ4P7s9f219I1csK4OeBMC3UA1HwEa0pY/9OF6H/egW2CjOcMM5Pdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/types": "7.102.1",
|
|
||||||
"@sentry/utils": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry-internal/feedback/node_modules/@sentry/types": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-htKorf3t/D0XYtM7foTcmG+rM47rDP6XdbvCcX5gBCuCYlzpM1vqCt2rl3FLktZC6TaIpFRJw1TLfx6m+x5jdA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry-internal/feedback/node_modules/@sentry/utils": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-+8WcFjHVV/HROXSAwMuUzveElBFC43EiTG7SNEBNgOUeQzQVTmbUZXyTVgLrUmtoWqvnIxCacoLxtZo1o67kdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/types": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry-internal/replay-canvas": {
|
"node_modules/@sentry-internal/replay-canvas": {
|
||||||
"version": "7.102.1",
|
"version": "7.104.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.102.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.104.0.tgz",
|
||||||
"integrity": "sha512-GUX4RWI10uRjdjeyvCLtAAhWRVqnAnG6+yNxWfqUQ3qMA7B7XxG43KT2UhSnulmErNzODQ6hA68rGPwwYeRIww==",
|
"integrity": "sha512-gfdnkFIpxAveKNghkvRCqv+hSiBkxYVoyFZLTvUPuM9Cmvmket1/PpnuWMC2jNtCEewG3gxkPDd4EaT9oa1HZQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/core": "7.102.1",
|
"@sentry/core": "7.104.0",
|
||||||
"@sentry/replay": "7.102.1",
|
"@sentry/replay": "7.104.0",
|
||||||
"@sentry/types": "7.102.1",
|
"@sentry/types": "7.104.0",
|
||||||
"@sentry/utils": "7.102.1"
|
"@sentry/utils": "7.104.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/core": {
|
"node_modules/@sentry-internal/tracing": {
|
||||||
"version": "7.102.1",
|
"version": "7.104.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.102.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.104.0.tgz",
|
||||||
"integrity": "sha512-QjY+LSP3du3J/C8x/FfEbRxgZgsWd0jfTJ4P7s9f219I1csK4OeBMC3UA1HwEa0pY/9OF6H/egW2CjOcMM5Pdg==",
|
"integrity": "sha512-2z7OijM1J5ndJUiJJElC3iH9qb/Eb8eYm2v8oJhM8WVdc5uCKfrQuYHNgGOnmY2FOCfEUlTmMQGpDw7DJ67L5w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/types": "7.102.1",
|
"@sentry/core": "7.104.0",
|
||||||
"@sentry/utils": "7.102.1"
|
"@sentry/types": "7.104.0",
|
||||||
},
|
"@sentry/utils": "7.104.0"
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/types": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-htKorf3t/D0XYtM7foTcmG+rM47rDP6XdbvCcX5gBCuCYlzpM1vqCt2rl3FLktZC6TaIpFRJw1TLfx6m+x5jdA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/utils": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-+8WcFjHVV/HROXSAwMuUzveElBFC43EiTG7SNEBNgOUeQzQVTmbUZXyTVgLrUmtoWqvnIxCacoLxtZo1o67kdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/types": "7.102.1"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@@ -4598,61 +4549,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/browser": {
|
"node_modules/@sentry/browser": {
|
||||||
"version": "7.102.1",
|
"version": "7.104.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.102.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.104.0.tgz",
|
||||||
"integrity": "sha512-7BOfPBiM7Kp6q/iy0JIbsBTxIASV+zWXByqqjuEMWGj3X2u4oRIfm3gv4erPU/l+CORQUVQZLSPGoIoM1gbB/A==",
|
"integrity": "sha512-HsqO+mr1SowGoP0VbuWrQ2DZT0t5PLomy7LEYa6+4lbOemnY+5YV2NSwBTKbjYysvKipSwaRtPhXrsXsMaz8Bg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry-internal/feedback": "7.102.1",
|
"@sentry-internal/feedback": "7.104.0",
|
||||||
"@sentry-internal/replay-canvas": "7.102.1",
|
"@sentry-internal/replay-canvas": "7.104.0",
|
||||||
"@sentry-internal/tracing": "7.102.1",
|
"@sentry-internal/tracing": "7.104.0",
|
||||||
"@sentry/core": "7.102.1",
|
"@sentry/core": "7.104.0",
|
||||||
"@sentry/replay": "7.102.1",
|
"@sentry/replay": "7.104.0",
|
||||||
"@sentry/types": "7.102.1",
|
"@sentry/types": "7.104.0",
|
||||||
"@sentry/utils": "7.102.1"
|
"@sentry/utils": "7.104.0"
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/browser/node_modules/@sentry-internal/tracing": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-RkFlFyAC0fQOvBbBqnq0CLmFW5m3JJz9pKbZd5vXPraWAlniKSb1bC/4DF9SlNx0FN1LWG+IU3ISdpzwwTeAGg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/core": "7.102.1",
|
|
||||||
"@sentry/types": "7.102.1",
|
|
||||||
"@sentry/utils": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/browser/node_modules/@sentry/core": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-QjY+LSP3du3J/C8x/FfEbRxgZgsWd0jfTJ4P7s9f219I1csK4OeBMC3UA1HwEa0pY/9OF6H/egW2CjOcMM5Pdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/types": "7.102.1",
|
|
||||||
"@sentry/utils": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/browser/node_modules/@sentry/types": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-htKorf3t/D0XYtM7foTcmG+rM47rDP6XdbvCcX5gBCuCYlzpM1vqCt2rl3FLktZC6TaIpFRJw1TLfx6m+x5jdA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/browser/node_modules/@sentry/utils": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-+8WcFjHVV/HROXSAwMuUzveElBFC43EiTG7SNEBNgOUeQzQVTmbUZXyTVgLrUmtoWqvnIxCacoLxtZo1o67kdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/types": "7.102.1"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@@ -4858,15 +4765,27 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/react": {
|
"node_modules/@sentry/core": {
|
||||||
"version": "7.102.1",
|
"version": "7.104.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.102.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.104.0.tgz",
|
||||||
"integrity": "sha512-X4j2DgbktlEifnd21YJKCayAmff5hnaS+9MNz9OonEwD0ARi0ks7bo0wtWHMjPK20992MO+JwczVg/1BXJYDdQ==",
|
"integrity": "sha512-XPndD6IGQGd07/EntvYVzOWQUo/Gd7L3DwYFeEKeBv6ByWjbBNmVZFRhU0GPPsCHKyW9yMU9OO9diLSS4ijsRg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/browser": "7.102.1",
|
"@sentry/types": "7.104.0",
|
||||||
"@sentry/core": "7.102.1",
|
"@sentry/utils": "7.104.0"
|
||||||
"@sentry/types": "7.102.1",
|
},
|
||||||
"@sentry/utils": "7.102.1",
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/react": {
|
||||||
|
"version": "7.104.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.104.0.tgz",
|
||||||
|
"integrity": "sha512-JdPzX/rJ4sSr/pVFOKwVrUhr8McCn38w5Q+/wdCabO8fdUkoBe4P05LRCH4Rng0uOk8MeEQ+EvfMVB79DmxIgQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/browser": "7.104.0",
|
||||||
|
"@sentry/core": "7.104.0",
|
||||||
|
"@sentry/types": "7.104.0",
|
||||||
|
"@sentry/utils": "7.104.0",
|
||||||
"hoist-non-react-statics": "^3.3.2"
|
"hoist-non-react-statics": "^3.3.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -4876,145 +4795,45 @@
|
|||||||
"react": "15.x || 16.x || 17.x || 18.x"
|
"react": "15.x || 16.x || 17.x || 18.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/react/node_modules/@sentry/core": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-QjY+LSP3du3J/C8x/FfEbRxgZgsWd0jfTJ4P7s9f219I1csK4OeBMC3UA1HwEa0pY/9OF6H/egW2CjOcMM5Pdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/types": "7.102.1",
|
|
||||||
"@sentry/utils": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/react/node_modules/@sentry/types": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-htKorf3t/D0XYtM7foTcmG+rM47rDP6XdbvCcX5gBCuCYlzpM1vqCt2rl3FLktZC6TaIpFRJw1TLfx6m+x5jdA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/react/node_modules/@sentry/utils": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-+8WcFjHVV/HROXSAwMuUzveElBFC43EiTG7SNEBNgOUeQzQVTmbUZXyTVgLrUmtoWqvnIxCacoLxtZo1o67kdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/types": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/replay": {
|
"node_modules/@sentry/replay": {
|
||||||
"version": "7.102.1",
|
"version": "7.104.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.102.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.104.0.tgz",
|
||||||
"integrity": "sha512-HR/j9dGIvbrId8fh8mQlODx7JrhRmawEd9e9P3laPtogWCg/5TI+XPb2VGSaXOX9VWtb/6Z2UjHsaGjgg6YcuA==",
|
"integrity": "sha512-HmWBr/u+SNeULxCxM8lJb2iqhjizeLGJtuKSShPEguEXIUT4kzdoqLh6wn7BAjiKzhmyjrnBcosR5LUqJtGYZQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry-internal/tracing": "7.102.1",
|
"@sentry-internal/tracing": "7.104.0",
|
||||||
"@sentry/core": "7.102.1",
|
"@sentry/core": "7.104.0",
|
||||||
"@sentry/types": "7.102.1",
|
"@sentry/types": "7.104.0",
|
||||||
"@sentry/utils": "7.102.1"
|
"@sentry/utils": "7.104.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/replay/node_modules/@sentry-internal/tracing": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-RkFlFyAC0fQOvBbBqnq0CLmFW5m3JJz9pKbZd5vXPraWAlniKSb1bC/4DF9SlNx0FN1LWG+IU3ISdpzwwTeAGg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/core": "7.102.1",
|
|
||||||
"@sentry/types": "7.102.1",
|
|
||||||
"@sentry/utils": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/replay/node_modules/@sentry/core": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-QjY+LSP3du3J/C8x/FfEbRxgZgsWd0jfTJ4P7s9f219I1csK4OeBMC3UA1HwEa0pY/9OF6H/egW2CjOcMM5Pdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/types": "7.102.1",
|
|
||||||
"@sentry/utils": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/replay/node_modules/@sentry/types": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-htKorf3t/D0XYtM7foTcmG+rM47rDP6XdbvCcX5gBCuCYlzpM1vqCt2rl3FLktZC6TaIpFRJw1TLfx6m+x5jdA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/replay/node_modules/@sentry/utils": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-+8WcFjHVV/HROXSAwMuUzveElBFC43EiTG7SNEBNgOUeQzQVTmbUZXyTVgLrUmtoWqvnIxCacoLxtZo1o67kdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/types": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/tracing": {
|
"node_modules/@sentry/tracing": {
|
||||||
"version": "7.102.1",
|
"version": "7.104.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.102.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.104.0.tgz",
|
||||||
"integrity": "sha512-9VQEox0R7ouhhUVHtBwlGlXG5beDCM/Uo0BY+G0M1H03aFJsLAwnxPNeWnK3WvPejxf94EgdimKMjDjv9l2Sbg==",
|
"integrity": "sha512-p1mmqNKrCVlA4b6js3twZotAIdS1cLXh05oU9WmSAW3iDo1Vf9QO5+/9K1Vh3a9fPQt3nDJeD/OgAb7C4VBIsA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry-internal/tracing": "7.102.1"
|
"@sentry-internal/tracing": "7.104.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/tracing/node_modules/@sentry-internal/tracing": {
|
"node_modules/@sentry/types": {
|
||||||
"version": "7.102.1",
|
"version": "7.104.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.102.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.104.0.tgz",
|
||||||
"integrity": "sha512-RkFlFyAC0fQOvBbBqnq0CLmFW5m3JJz9pKbZd5vXPraWAlniKSb1bC/4DF9SlNx0FN1LWG+IU3ISdpzwwTeAGg==",
|
"integrity": "sha512-5bs0xe0+GZR4QBm9Nrqw59o0sv3kBtCosrZDVxBru/dQbrfnB+/kVorvuM0rV3+coNITTKcKDegSZmK1d2uOGQ==",
|
||||||
"dependencies": {
|
|
||||||
"@sentry/core": "7.102.1",
|
|
||||||
"@sentry/types": "7.102.1",
|
|
||||||
"@sentry/utils": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/tracing/node_modules/@sentry/core": {
|
"node_modules/@sentry/utils": {
|
||||||
"version": "7.102.1",
|
"version": "7.104.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.102.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.104.0.tgz",
|
||||||
"integrity": "sha512-QjY+LSP3du3J/C8x/FfEbRxgZgsWd0jfTJ4P7s9f219I1csK4OeBMC3UA1HwEa0pY/9OF6H/egW2CjOcMM5Pdg==",
|
"integrity": "sha512-ZVg+xZirI9DlOi0NegNVocswdh/8p6QkzlQzDQY2LP2CC6JQdmwi64o0S4rPH4YIHNKQJTpIjduoxeKgd1EO5g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/types": "7.102.1",
|
"@sentry/types": "7.104.0"
|
||||||
"@sentry/utils": "7.102.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/tracing/node_modules/@sentry/types": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-htKorf3t/D0XYtM7foTcmG+rM47rDP6XdbvCcX5gBCuCYlzpM1vqCt2rl3FLktZC6TaIpFRJw1TLfx6m+x5jdA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/tracing/node_modules/@sentry/utils": {
|
|
||||||
"version": "7.102.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.102.1.tgz",
|
|
||||||
"integrity": "sha512-+8WcFjHVV/HROXSAwMuUzveElBFC43EiTG7SNEBNgOUeQzQVTmbUZXyTVgLrUmtoWqvnIxCacoLxtZo1o67kdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sentry/types": "7.102.1"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@@ -11230,25 +11049,25 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/firebase": {
|
"node_modules/firebase": {
|
||||||
"version": "10.8.0",
|
"version": "10.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/firebase/-/firebase-10.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/firebase/-/firebase-10.8.1.tgz",
|
||||||
"integrity": "sha512-UJpC24vw8JFuHEOQyArBGKTUd7+kohLISCzHyn0M/prP0KOTx2io1eyLliEid330QqnWI7FOlPxoU97qecCSfQ==",
|
"integrity": "sha512-4B2jzhU/aumfKL446MG41/T5+t+9d9urf5XGrjC0HRQUm4Ya/amV48HBchnje69ExaJP5f2WxO9OX3wh9ee4wA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/analytics": "0.10.1",
|
"@firebase/analytics": "0.10.1",
|
||||||
"@firebase/analytics-compat": "0.2.7",
|
"@firebase/analytics-compat": "0.2.7",
|
||||||
"@firebase/app": "0.9.27",
|
"@firebase/app": "0.9.28",
|
||||||
"@firebase/app-check": "0.8.2",
|
"@firebase/app-check": "0.8.2",
|
||||||
"@firebase/app-check-compat": "0.3.9",
|
"@firebase/app-check-compat": "0.3.9",
|
||||||
"@firebase/app-compat": "0.2.27",
|
"@firebase/app-compat": "0.2.28",
|
||||||
"@firebase/app-types": "0.9.0",
|
"@firebase/app-types": "0.9.0",
|
||||||
"@firebase/auth": "1.6.0",
|
"@firebase/auth": "1.6.1",
|
||||||
"@firebase/auth-compat": "0.5.2",
|
"@firebase/auth-compat": "0.5.3",
|
||||||
"@firebase/database": "1.0.3",
|
"@firebase/database": "1.0.3",
|
||||||
"@firebase/database-compat": "1.0.3",
|
"@firebase/database-compat": "1.0.3",
|
||||||
"@firebase/firestore": "4.4.2",
|
"@firebase/firestore": "4.4.3",
|
||||||
"@firebase/firestore-compat": "0.3.25",
|
"@firebase/firestore-compat": "0.3.26",
|
||||||
"@firebase/functions": "0.11.1",
|
"@firebase/functions": "0.11.2",
|
||||||
"@firebase/functions-compat": "0.3.7",
|
"@firebase/functions-compat": "0.3.8",
|
||||||
"@firebase/installations": "0.6.5",
|
"@firebase/installations": "0.6.5",
|
||||||
"@firebase/installations-compat": "0.2.5",
|
"@firebase/installations-compat": "0.2.5",
|
||||||
"@firebase/messaging": "0.12.6",
|
"@firebase/messaging": "0.12.6",
|
||||||
@@ -11257,8 +11076,8 @@
|
|||||||
"@firebase/performance-compat": "0.2.5",
|
"@firebase/performance-compat": "0.2.5",
|
||||||
"@firebase/remote-config": "0.4.5",
|
"@firebase/remote-config": "0.4.5",
|
||||||
"@firebase/remote-config-compat": "0.2.5",
|
"@firebase/remote-config-compat": "0.2.5",
|
||||||
"@firebase/storage": "0.12.1",
|
"@firebase/storage": "0.12.2",
|
||||||
"@firebase/storage-compat": "0.3.4",
|
"@firebase/storage-compat": "0.3.5",
|
||||||
"@firebase/util": "1.9.4"
|
"@firebase/util": "1.9.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -18174,16 +17993,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/query-string": {
|
"node_modules/query-string": {
|
||||||
"version": "8.2.0",
|
"version": "9.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-8.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/query-string/-/query-string-9.0.0.tgz",
|
||||||
"integrity": "sha512-tUZIw8J0CawM5wyGBiDOAp7ObdRQh4uBor/fUR9ZjmbZVvw95OD9If4w3MQxr99rg0DJZ/9CIORcpEqU5hQG7g==",
|
"integrity": "sha512-4EWwcRGsO2H+yzq6ddHcVqkCQ2EFUSfDMEjF8ryp8ReymyZhIuaFRGLomeOQLkrzacMHoyky2HW0Qe30UbzkKw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"decode-uri-component": "^0.4.1",
|
"decode-uri-component": "^0.4.1",
|
||||||
"filter-obj": "^5.1.0",
|
"filter-obj": "^5.1.0",
|
||||||
"split-on-first": "^3.0.0"
|
"split-on-first": "^3.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.16"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
@@ -19048,9 +18867,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-big-calendar": {
|
"node_modules/react-big-calendar": {
|
||||||
"version": "1.10.3",
|
"version": "1.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-1.10.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-1.11.0.tgz",
|
||||||
"integrity": "sha512-LmIWlFfGUn8yt4RxcVkGNmjM3GcWynr1bfDwKrrz4KKj517+DH3OGmQzErURN6Zb0OB88HF4oH2dvDHpBQJgIw==",
|
"integrity": "sha512-CabU9UCYIjbAew4GpDJa6ycrRINEEONbXEfO0YU7hHuHA2lhyMjnONY+GcpnJvhpOZC3wTtUa7krCriCm+iuKg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.7",
|
"@babel/runtime": "^7.20.7",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
@@ -19336,9 +19155,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-number-format": {
|
"node_modules/react-number-format": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.3.3.tgz",
|
||||||
"integrity": "sha512-qpYcQLauIeEhCZUZY9jXZnnroOtdy3jYaS1zQ3M1Sr6r/KMOBEIGNIb7eKT19g2N1wbYgFgvDzs19hw5TrB8XQ==",
|
"integrity": "sha512-maGHWmOvwYzyeRIpL0YC6drWqYaX6iFqjisdJXpZ+HzEtSEJsL6nqw4azTpF5Sm6SAvwUeAr7JY924Ebqq8EdA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prop-types": "^15.7.2"
|
"prop-types": "^15.7.2"
|
||||||
},
|
},
|
||||||
@@ -19413,11 +19232,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router": {
|
"node_modules/react-router": {
|
||||||
"version": "6.22.1",
|
"version": "6.22.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.2.tgz",
|
||||||
"integrity": "sha512-0pdoRGwLtemnJqn1K0XHUbnKiX0S4X8CgvVVmHGOWmofESj31msHo/1YiqcJWK7Wxfq2a4uvvtS01KAQyWK/CQ==",
|
"integrity": "sha512-YD3Dzprzpcq+tBMHBS822tCjnWD3iIZbTeSXMY9LPSG541EfoBGyZ3bS25KEnaZjLcmQpw2AVLkFyfgXY8uvcw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remix-run/router": "1.15.1"
|
"@remix-run/router": "1.15.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
@@ -19427,12 +19246,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router-dom": {
|
"node_modules/react-router-dom": {
|
||||||
"version": "6.22.1",
|
"version": "6.22.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.2.tgz",
|
||||||
"integrity": "sha512-iwMyyyrbL7zkKY7MRjOVRy+TMnS/OPusaFVxM2P11x9dzSzGmLsebkCvYirGq0DWB9K9hOspHYYtDz33gE5Duw==",
|
"integrity": "sha512-WgqxD2qySEIBPZ3w0sHH+PUAiamDeszls9tzqMPBDA1YYVucTBXLU7+gtRfcSnhe92A3glPnvSxK2dhNoAVOIQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remix-run/router": "1.15.1",
|
"@remix-run/router": "1.15.2",
|
||||||
"react-router": "6.22.1"
|
"react-router": "6.22.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
@@ -19662,9 +19481,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/recharts": {
|
"node_modules/recharts": {
|
||||||
"version": "2.12.1",
|
"version": "2.12.2",
|
||||||
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.2.tgz",
|
||||||
"integrity": "sha512-35vUCEBPf+pM+iVgSgVTn86faKya5pc4JO6cYJL63qOK2zDEyzDn20Tdj+CDI/3z+VcpKyQ8ZBQ9OiQ+vuAbjg==",
|
"integrity": "sha512-9bpxjXSF5g81YsKkTSlaX7mM4b6oYI1mIYck6YkUcWuL3tomADccI51/6thY4LmvhYuRTwpfrOvE80Zc3oBRfQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"eventemitter3": "^4.0.1",
|
"eventemitter3": "^4.0.1",
|
||||||
@@ -22605,9 +22424,9 @@
|
|||||||
"integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw=="
|
"integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw=="
|
||||||
},
|
},
|
||||||
"node_modules/undici": {
|
"node_modules/undici": {
|
||||||
"version": "5.26.5",
|
"version": "5.28.3",
|
||||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz",
|
||||||
"integrity": "sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==",
|
"integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/busboy": "^2.0.0"
|
"@fastify/busboy": "^2.0.0"
|
||||||
},
|
},
|
||||||
@@ -24162,9 +23981,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yauzl": {
|
"node_modules/yauzl": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.1.1.tgz",
|
||||||
"integrity": "sha512-zbff6SaAPyewVextulqeBjJm+1ZhS69vSN7cRpqVD7jMNSE9oXEdQ1SGF+ydfB+gKE2a3GiWfXf/pnwVZ1/tOA==",
|
"integrity": "sha512-MPxA7oN5cvGV0wzfkeHKF2/+Q4TkMpHSWGRy/96I4Cozljmx0ph91+Muxh6HegEtDC4GftJ8qYDE51vghFiEYA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer-crc32": "~0.2.3",
|
"buffer-crc32": "~0.2.3",
|
||||||
"pend": "~1.2.0"
|
"pend": "~1.2.0"
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
"@jsreport/browser-client": "^3.1.0",
|
"@jsreport/browser-client": "^3.1.0",
|
||||||
"@reduxjs/toolkit": "^2.2.1",
|
"@reduxjs/toolkit": "^2.2.1",
|
||||||
"@sentry/cli": "^2.28.6",
|
"@sentry/cli": "^2.28.6",
|
||||||
"@sentry/react": "^7.102.1",
|
"@sentry/react": "^7.104.0",
|
||||||
"@sentry/tracing": "^7.102.1",
|
"@sentry/tracing": "^7.104.0",
|
||||||
"@splitsoftware/splitio-react": "^1.11.0",
|
"@splitsoftware/splitio-react": "^1.11.0",
|
||||||
"@tanem/react-nprogress": "^5.0.51",
|
"@tanem/react-nprogress": "^5.0.51",
|
||||||
"antd": "^5.14.2",
|
"antd": "^5.14.2",
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
"enquire-js": "^0.2.1",
|
"enquire-js": "^0.2.1",
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"exifr": "^7.1.3",
|
"exifr": "^7.1.3",
|
||||||
"firebase": "^10.8.0",
|
"firebase": "^10.8.1",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
"i18next": "^23.10.0",
|
"i18next": "^23.10.0",
|
||||||
"i18next-browser-languagedetector": "^7.0.2",
|
"i18next-browser-languagedetector": "^7.0.2",
|
||||||
@@ -42,11 +42,11 @@
|
|||||||
"phone": "^3.1.42",
|
"phone": "^3.1.42",
|
||||||
"preval.macro": "^5.0.0",
|
"preval.macro": "^5.0.0",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"query-string": "^8.2.0",
|
"query-string": "^9.0.0",
|
||||||
"rc-queue-anim": "^2.0.0",
|
"rc-queue-anim": "^2.0.0",
|
||||||
"rc-scroll-anim": "^2.7.6",
|
"rc-scroll-anim": "^2.7.6",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-big-calendar": "^1.10.3",
|
"react-big-calendar": "^1.11.0",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
"react-cookie": "^7.1.0",
|
"react-cookie": "^7.1.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@@ -58,15 +58,15 @@
|
|||||||
"react-image-lightbox": "^5.1.4",
|
"react-image-lightbox": "^5.1.4",
|
||||||
"react-intersection-observer": "^9.8.1",
|
"react-intersection-observer": "^9.8.1",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-number-format": "^5.1.4",
|
"react-number-format": "^5.3.3",
|
||||||
"react-redux": "^9.1.0",
|
"react-redux": "^9.1.0",
|
||||||
"react-resizable": "^3.0.5",
|
"react-resizable": "^3.0.5",
|
||||||
"react-router-dom": "^6.22.1",
|
"react-router-dom": "^6.22.2",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"react-sticky": "^6.0.3",
|
"react-sticky": "^6.0.3",
|
||||||
"react-sublime-video": "^0.2.5",
|
"react-sublime-video": "^0.2.5",
|
||||||
"react-virtualized": "^9.22.5",
|
"react-virtualized": "^9.22.5",
|
||||||
"recharts": "^2.12.1",
|
"recharts": "^2.12.2",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-saga": "^1.3.0",
|
"redux-saga": "^1.3.0",
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
"workbox-precaching": "^7.0.0",
|
"workbox-precaching": "^7.0.0",
|
||||||
"workbox-routing": "^7.0.0",
|
"workbox-routing": "^7.0.0",
|
||||||
"workbox-strategies": "^7.0.0",
|
"workbox-strategies": "^7.0.0",
|
||||||
"yauzl": "^3.1.0"
|
"yauzl": "^3.1.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
||||||
|
|||||||
@@ -5,10 +5,22 @@ import React, {useState} from "react";
|
|||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {DELETE_BILL} from "../../graphql/bills.queries";
|
import {DELETE_BILL} from "../../graphql/bills.queries";
|
||||||
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
|
import {insertAuditTrail} from "../../redux/application/application.actions";
|
||||||
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
|
||||||
export default function BillDeleteButton({bill, callback}) {
|
const mapStateToProps = createStructuredSelector({});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
insertAuditTrail: ({ jobid, operation }) =>
|
||||||
|
dispatch(insertAuditTrail({ jobid, operation })),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(BillDeleteButton);
|
||||||
|
|
||||||
|
export function BillDeleteButton({ bill, jobid, callback, insertAuditTrail }) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const {t} = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [deleteBill] = useMutation(DELETE_BILL);
|
const [deleteBill] = useMutation(DELETE_BILL);
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
@@ -35,7 +47,11 @@ export default function BillDeleteButton({bill, callback}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!!!result.errors) {
|
if (!!!result.errors) {
|
||||||
notification["success"]({message: t("bills.successes.deleted")});
|
notification["success"]({ message: t("bills.successes.deleted") });
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: jobid,
|
||||||
|
operation: AuditTrailMapping.billdeleted(bill.invoice_number),
|
||||||
|
});
|
||||||
|
|
||||||
if (callback && typeof callback === "function") callback(bill.id);
|
if (callback && typeof callback === "function") callback(bill.id);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -50,17 +50,17 @@ export function BillsListTableComponent({
|
|||||||
|
|
||||||
const Templates = TemplateList("bill");
|
const Templates = TemplateList("bill");
|
||||||
const bills = billsQuery.data ? billsQuery.data.bills : [];
|
const bills = billsQuery.data ? billsQuery.data.bills : [];
|
||||||
const {refetch} = billsQuery;
|
const { refetch } = billsQuery;
|
||||||
const recordActions = (record, showView = false) => (
|
const recordActions = (record, showView = false) => (
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
{showView && (
|
{showView && (
|
||||||
<Button onClick={() => handleOnRowClick(record)}>
|
<Button onClick={() => handleOnRowClick(record)}>
|
||||||
<EditFilled/>
|
<EditFilled />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<BillDeleteButton bill={record}/>
|
<BillDeleteButton bill={record} jobid={job.id} />
|
||||||
<BillDetailEditReturnComponent
|
<BillDetailEditReturnComponent
|
||||||
data={{bills_by_pk: {...record, jobid: job.id}}}
|
data={{ bills_by_pk: { ...record, jobid: job.id } }}
|
||||||
disabled={
|
disabled={
|
||||||
record.is_credit_memo ||
|
record.is_credit_memo ||
|
||||||
record.vendorid === bodyshop.inhousevendorid ||
|
record.vendorid === bodyshop.inhousevendorid ||
|
||||||
|
|||||||
@@ -1,22 +1,34 @@
|
|||||||
import {SyncOutlined, WarningFilled} from "@ant-design/icons";
|
import { SyncOutlined, WarningFilled } from "@ant-design/icons";
|
||||||
import {Button, Card, Dropdown, Input, Space, Table, Tooltip,} from "antd";
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Dropdown,
|
||||||
|
Input,
|
||||||
|
Space,
|
||||||
|
Table,
|
||||||
|
Tooltip,
|
||||||
|
} from "antd";
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import React, {useState} from "react";
|
import React, { useState } from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import {DateTimeFormatter} from "../../utils/DateFormatter";
|
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
import {GenerateDocument} from "../../utils/RenderTemplate";
|
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||||
import {TemplateList} from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
import {alphaSort} from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import {OwnerNameDisplayFunction} from "../owner-name-display/owner-name-display.component";
|
import useLocalStorage from "../../utils/useLocalStorage";
|
||||||
|
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function CourtesyCarsList({loading, courtesycars, refetch}) {
|
export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
filteredInfo: {text: ""},
|
|
||||||
});
|
});
|
||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
const {t} = useTranslation();
|
const [filter, setFilter] = useLocalStorage(
|
||||||
|
"filter_courtesy_cars_list",
|
||||||
|
null
|
||||||
|
);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@@ -42,6 +54,7 @@ export default function CourtesyCarsList({loading, courtesycars, refetch}) {
|
|||||||
dataIndex: "status",
|
dataIndex: "status",
|
||||||
key: "status",
|
key: "status",
|
||||||
sorter: (a, b) => alphaSort(a.status, b.status),
|
sorter: (a, b) => alphaSort(a.status, b.status),
|
||||||
|
filteredValue: filter?.status || null,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
text: t("courtesycars.status.in"),
|
text: t("courtesycars.status.in"),
|
||||||
@@ -64,7 +77,7 @@ export default function CourtesyCarsList({loading, courtesycars, refetch}) {
|
|||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
const {nextservicedate, nextservicekm, mileage, insuranceexpires} =
|
const { nextservicedate, nextservicekm, mileage, insuranceexpires } =
|
||||||
record;
|
record;
|
||||||
|
|
||||||
const mileageOver = nextservicekm ? nextservicekm <= mileage : false;
|
const mileageOver = nextservicekm ? nextservicekm <= mileage : false;
|
||||||
@@ -75,19 +88,23 @@ export default function CourtesyCarsList({loading, courtesycars, refetch}) {
|
|||||||
const insuranceOver =
|
const insuranceOver =
|
||||||
insuranceexpires &&
|
insuranceexpires &&
|
||||||
dayjs(insuranceexpires).endOf("day").isBefore(dayjs());
|
dayjs(insuranceexpires).endOf("day").isBefore(dayjs());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space>
|
<Space>
|
||||||
{t(record.status)}
|
{t(record.status)}
|
||||||
{(mileageOver || dueForService || insuranceOver) && (
|
{(mileageOver || dueForService || insuranceOver) && (
|
||||||
<Tooltip title={(mileageOver || dueForService) && insuranceOver
|
<Tooltip
|
||||||
? t("contracts.labels.insuranceexpired") +
|
title={
|
||||||
" / " +
|
(mileageOver || dueForService) && insuranceOver
|
||||||
t("contracts.labels.cardueforservice")
|
? t("contracts.labels.insuranceexpired") +
|
||||||
: insuranceOver
|
" / " +
|
||||||
? t("contracts.labels.insuranceexpired")
|
t("contracts.labels.cardueforservice")
|
||||||
: t("contracts.labels.cardueforservice")
|
: insuranceOver
|
||||||
}>
|
? t("contracts.labels.insuranceexpired")
|
||||||
<WarningFilled style={{color: "tomato"}}/>
|
: t("contracts.labels.cardueforservice")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<WarningFilled style={{ color: "tomato" }} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
@@ -99,6 +116,7 @@ export default function CourtesyCarsList({loading, courtesycars, refetch}) {
|
|||||||
dataIndex: "readiness",
|
dataIndex: "readiness",
|
||||||
key: "readiness",
|
key: "readiness",
|
||||||
sorter: (a, b) => alphaSort(a.readiness, b.readiness),
|
sorter: (a, b) => alphaSort(a.readiness, b.readiness),
|
||||||
|
filteredValue: filter?.readiness || null,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
text: t("courtesycars.readiness.ready"),
|
text: t("courtesycars.readiness.ready"),
|
||||||
@@ -214,7 +232,8 @@ export default function CourtesyCarsList({loading, courtesycars, refetch}) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const handleTableChange = (pagination, filters, sorter) => {
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
setState({...state, filteredInfo: filters, sortedInfo: sorter});
|
setState({ ...state, sortedInfo: sorter });
|
||||||
|
setFilter(filters);
|
||||||
};
|
};
|
||||||
|
|
||||||
const tableData = searchText
|
const tableData = searchText
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import {createStructuredSelector} from "reselect";
|
|||||||
import {auth, logImEXEvent} from "../../firebase/firebase.utils";
|
import {auth, logImEXEvent} from "../../firebase/firebase.utils";
|
||||||
import {INSERT_EXPORT_LOG} from "../../graphql/accounting.queries";
|
import {INSERT_EXPORT_LOG} from "../../graphql/accounting.queries";
|
||||||
import {UPDATE_JOB} from "../../graphql/jobs.queries";
|
import {UPDATE_JOB} from "../../graphql/jobs.queries";
|
||||||
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
import {
|
import {
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import client from "../../utils/GraphQLClient";
|
import client from "../../utils/GraphQLClient";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -20,6 +22,11 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
insertAuditTrail: ({ jobid, operation }) =>
|
||||||
|
dispatch(insertAuditTrail({ jobid, operation })),
|
||||||
|
});
|
||||||
|
|
||||||
function updateJobCache(items) {
|
function updateJobCache(items) {
|
||||||
client.cache.modify({
|
client.cache.modify({
|
||||||
id: "ROOT_QUERY",
|
id: "ROOT_QUERY",
|
||||||
@@ -40,9 +47,10 @@ export function JobsCloseExportButton({
|
|||||||
disabled,
|
disabled,
|
||||||
setSelectedJobs,
|
setSelectedJobs,
|
||||||
refetch,
|
refetch,
|
||||||
|
insertAuditTrail,
|
||||||
}) {
|
}) {
|
||||||
const history = useNavigate();
|
const history = useNavigate();
|
||||||
const {t} = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [updateJob] = useMutation(UPDATE_JOB);
|
const [updateJob] = useMutation(UPDATE_JOB);
|
||||||
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
|
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -181,6 +189,10 @@ export function JobsCloseExportButton({
|
|||||||
key: "jobsuccessexport",
|
key: "jobsuccessexport",
|
||||||
message: t("jobs.successes.exported"),
|
message: t("jobs.successes.exported"),
|
||||||
});
|
});
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: jobId,
|
||||||
|
operation: AuditTrailMapping.jobexported(),
|
||||||
|
});
|
||||||
updateJobCache(
|
updateJobCache(
|
||||||
jobUpdateResponse.data.update_jobs.returning.map((job) => job.id)
|
jobUpdateResponse.data.update_jobs.returning.map((job) => job.id)
|
||||||
);
|
);
|
||||||
@@ -192,12 +204,20 @@ export function JobsCloseExportButton({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
|
if (
|
||||||
|
bodyshop.accountingconfig &&
|
||||||
|
bodyshop.accountingconfig.qbo &&
|
||||||
|
successfulTransactions.length > 0
|
||||||
|
) {
|
||||||
notification.open({
|
notification.open({
|
||||||
type: "success",
|
type: "success",
|
||||||
key: "jobsuccessexport",
|
key: "jobsuccessexport",
|
||||||
message: t("jobs.successes.exported"),
|
message: t("jobs.successes.exported"),
|
||||||
});
|
});
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: jobId,
|
||||||
|
operation: AuditTrailMapping.jobexported(),
|
||||||
|
});
|
||||||
updateJobCache([
|
updateJobCache([
|
||||||
...new Set(
|
...new Set(
|
||||||
successfulTransactions.map(
|
successfulTransactions.map(
|
||||||
@@ -227,4 +247,7 @@ export function JobsCloseExportButton({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(JobsCloseExportButton);
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(JobsCloseExportButton);
|
||||||
|
|||||||
@@ -237,6 +237,10 @@ export function JobsDetailHeaderActions({
|
|||||||
message: JSON.stringify(result.errors),
|
message: JSON.stringify(result.errors),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: job.id,
|
||||||
|
operation: AuditTrailMapping.jobvoid(),
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (e.key === "email")
|
if (e.key === "email")
|
||||||
@@ -470,6 +474,24 @@ export function JobsDetailHeaderActions({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSuspend = (e) => {
|
||||||
|
logImEXEvent("production_toggle_alert");
|
||||||
|
//e.stopPropagation();
|
||||||
|
updateJob({
|
||||||
|
variables: {
|
||||||
|
jobId: job.id,
|
||||||
|
job: {
|
||||||
|
suspended: !job.suspended,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: job.id,
|
||||||
|
operation: AuditTrailMapping.jobsuspend(
|
||||||
|
!!job.suspended ? !job.suspended : true
|
||||||
|
),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Function to handle OK
|
// Function to handle OK
|
||||||
const handleCancelScheduleOK = async () => {
|
const handleCancelScheduleOK = async () => {
|
||||||
@@ -504,19 +526,6 @@ export function JobsDetailHeaderActions({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSuspend = (e) => {
|
|
||||||
logImEXEvent("production_toggle_alert");
|
|
||||||
//e.stopPropagation();
|
|
||||||
updateJob({
|
|
||||||
variables: {
|
|
||||||
jobId: job.id,
|
|
||||||
job: {
|
|
||||||
suspended: !job.suspended,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const popOverContent = (
|
const popOverContent = (
|
||||||
<Card>
|
<Card>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -9,7 +9,12 @@ import {createStructuredSelector} from "reselect";
|
|||||||
import {auth, logImEXEvent} from "../../firebase/firebase.utils";
|
import {auth, logImEXEvent} from "../../firebase/firebase.utils";
|
||||||
import {INSERT_EXPORT_LOG} from "../../graphql/accounting.queries";
|
import {INSERT_EXPORT_LOG} from "../../graphql/accounting.queries";
|
||||||
import {UPDATE_JOBS} from "../../graphql/jobs.queries";
|
import {UPDATE_JOBS} from "../../graphql/jobs.queries";
|
||||||
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
import {
|
||||||
|
selectBodyshop,
|
||||||
|
selectCurrentUser,
|
||||||
|
} from "../../redux/user/user.selectors";
|
||||||
import client from "../../utils/GraphQLClient";
|
import client from "../../utils/GraphQLClient";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -17,6 +22,11 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
insertAuditTrail: ({ jobid, operation }) =>
|
||||||
|
dispatch(insertAuditTrail({ jobid, operation })),
|
||||||
|
});
|
||||||
|
|
||||||
function updateJobCache(items) {
|
function updateJobCache(items) {
|
||||||
client.cache.modify({
|
client.cache.modify({
|
||||||
id: "ROOT_QUERY",
|
id: "ROOT_QUERY",
|
||||||
@@ -38,8 +48,9 @@ export function JobsExportAllButton({
|
|||||||
loadingCallback,
|
loadingCallback,
|
||||||
completedCallback,
|
completedCallback,
|
||||||
refetch,
|
refetch,
|
||||||
|
insertAuditTrail,
|
||||||
}) {
|
}) {
|
||||||
const {t} = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [updateJob] = useMutation(UPDATE_JOBS);
|
const [updateJob] = useMutation(UPDATE_JOBS);
|
||||||
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
|
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
|
||||||
|
|
||||||
@@ -168,47 +179,64 @@ export function JobsExportAllButton({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!!jobUpdateResponse.errors) {
|
if (!!!jobUpdateResponse.errors) {
|
||||||
notification.open({
|
notification.open({
|
||||||
type: "success",
|
type: "success",
|
||||||
key: "jobsuccessexport",
|
key: "jobsuccessexport",
|
||||||
message: t("jobs.successes.exported"),
|
message: t("jobs.successes.exported"),
|
||||||
});
|
});
|
||||||
updateJobCache(
|
jobUpdateResponse.data.update_jobs.returning.forEach((job) => {
|
||||||
jobUpdateResponse.data.update_jobs.returning.map(
|
insertAuditTrail({
|
||||||
(job) => job.id
|
jobid: job.id,
|
||||||
)
|
operation: AuditTrailMapping.jobexported(),
|
||||||
);
|
});
|
||||||
} else {
|
});
|
||||||
notification["error"]({
|
updateJobCache(
|
||||||
message: t("jobs.errors.exporting", {
|
jobUpdateResponse.data.update_jobs.returning.map(
|
||||||
error: JSON.stringify(jobUpdateResponse.error),
|
(job) => job.id
|
||||||
}),
|
)
|
||||||
});
|
);
|
||||||
}
|
} else {
|
||||||
}
|
notification["error"]({
|
||||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
|
message: t("jobs.errors.exporting", {
|
||||||
notification.open({
|
error: JSON.stringify(jobUpdateResponse.error),
|
||||||
type: "success",
|
}),
|
||||||
key: "jobsuccessexport",
|
});
|
||||||
message: t("jobs.successes.exported"),
|
}
|
||||||
});
|
}
|
||||||
updateJobCache([
|
if (
|
||||||
...new Set(
|
bodyshop.accountingconfig &&
|
||||||
successfulTransactions.map(
|
bodyshop.accountingconfig.qbo &&
|
||||||
(st) =>
|
successfulTransactions.length > 0
|
||||||
st[
|
) {
|
||||||
bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
|
notification.open({
|
||||||
? "jobid"
|
type: "success",
|
||||||
: "id"
|
key: "jobsuccessexport",
|
||||||
]
|
message: t("jobs.successes.exported"),
|
||||||
)
|
});
|
||||||
),
|
const successfulTransactionsSet = [
|
||||||
]);
|
...new Set(
|
||||||
}
|
successfulTransactions.map(
|
||||||
}
|
(st) =>
|
||||||
})
|
st[
|
||||||
);
|
bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
|
||||||
|
? "jobid"
|
||||||
|
: "id"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
];
|
||||||
|
if (successfulTransactionsSet.length > 0) {
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: successfulTransactionsSet[0],
|
||||||
|
operation: AuditTrailMapping.jobexported(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
updateJobCache(successfulTransactionsSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
if (!!completedCallback) completedCallback([]);
|
if (!!completedCallback) completedCallback([]);
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
if (!!loadingCallback) loadingCallback(false);
|
||||||
@@ -222,4 +250,7 @@ export function JobsExportAllButton({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(JobsExportAllButton);
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(JobsExportAllButton);
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ const PaymentExpandedRowComponent = ({record, bodyshop}) => {
|
|||||||
await insertPayment({
|
await insertPayment({
|
||||||
variables: {
|
variables: {
|
||||||
paymentInput: {
|
paymentInput: {
|
||||||
amount: -refund_response.data.amount,
|
amount: -refund_response?.data?.amount,
|
||||||
transactionid: payment_response.response.receiptelements.transid,
|
transactionid: payment_response?.response?.receiptelements?.transid,
|
||||||
payer: record.payer,
|
payer: record.payer,
|
||||||
type: "Refund",
|
type: "Refund",
|
||||||
jobid: payment_response.jobid,
|
jobid: payment_response.jobid,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {useTranslation} from "react-i18next";
|
|||||||
import {getOrderOperatorsByType, getWhereOperatorsByType} from "../../utils/graphQLmodifier";
|
import {getOrderOperatorsByType, getWhereOperatorsByType} from "../../utils/graphQLmodifier";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
import {generateInternalReflections} from "./report-center-modal-utils";
|
import {generateInternalReflections} from "./report-center-modal-utils";
|
||||||
|
import {FormDatePicker} from "../form-date-picker/form-date-picker.component.jsx";
|
||||||
|
|
||||||
export default function ReportCenterModalFiltersSortersComponent({form, bodyshop}) {
|
export default function ReportCenterModalFiltersSortersComponent({form, bodyshop}) {
|
||||||
return (
|
return (
|
||||||
@@ -31,10 +31,9 @@ function FiltersSection({filters, form, bodyshop}) {
|
|||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card type='inner' title={t('reportcenter.labels.advanced_filters_filters')}
|
<Card type='inner' title={t('reportcenter.labels.advanced_filters_filters')} style={{marginTop: '10px'}}>
|
||||||
style={{marginTop: '10px'}}>
|
|
||||||
<Form.List name={["filters"]}>
|
<Form.List name={["filters"]}>
|
||||||
{(fields, {add, remove, move}) => {
|
{(fields, {add, remove}) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{fields.map((field, index) => (
|
{fields.map((field, index) => (
|
||||||
@@ -72,7 +71,8 @@ function FiltersSection({filters, form, bodyshop}) {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
<Col span={6}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
dependencies={[['filters', field.name, "field"]]}>
|
dependencies={[['filters', field.name, "field"],['filters', field.name, "value"]]}
|
||||||
|
>
|
||||||
{
|
{
|
||||||
() => {
|
() => {
|
||||||
const name = form.getFieldValue(['filters', field.name, "field"]);
|
const name = form.getFieldValue(['filters', field.name, "field"]);
|
||||||
@@ -82,7 +82,6 @@ function FiltersSection({filters, form, bodyshop}) {
|
|||||||
key={`${index}operator`}
|
key={`${index}operator`}
|
||||||
label={t('reportcenter.labels.advanced_filters_filter_operator')}
|
label={t('reportcenter.labels.advanced_filters_filter_operator')}
|
||||||
name={[field.name, "operator"]}
|
name={[field.name, "operator"]}
|
||||||
dependencies={[]}
|
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -92,20 +91,32 @@ function FiltersSection({filters, form, bodyshop}) {
|
|||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
getPopupContainer={trigger => trigger.parentNode}
|
getPopupContainer={trigger => trigger.parentNode}
|
||||||
options={getWhereOperatorsByType(type)}/>
|
options={ getWhereOperatorsByType(type)}
|
||||||
|
onChange={() => {
|
||||||
|
// Clear related Fields
|
||||||
|
|
||||||
|
form.setFieldValue(['filters', field.name, 'value'], undefined);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
<Col span={6}>
|
||||||
<Form.Item
|
<Form.Item dependencies={[
|
||||||
dependencies={[['filters', field.name, "field"]]}>
|
['filters', field.name, "field"],
|
||||||
|
['filters', field.name, "operator"]
|
||||||
|
]}
|
||||||
|
>
|
||||||
{
|
{
|
||||||
() => {
|
() => {
|
||||||
|
// Because it looks cleaner than inlining.
|
||||||
const name = form.getFieldValue(['filters', field.name, "field"]);
|
const name = form.getFieldValue(['filters', field.name, "field"]);
|
||||||
const type = filters.find(f => f.name === name)?.type;
|
const type = filters.find(f => f.name === name)?.type;
|
||||||
const reflector = filters.find(f => f.name === name)?.reflector;
|
const reflector = filters.find(f => f.name === name)?.reflector;
|
||||||
|
const operator = form.getFieldValue(['filters', field.name, "operator"]);
|
||||||
|
const operatorType = operator ? getWhereOperatorsByType(type).find((o) => o.value === operator)?.type : null;
|
||||||
|
|
||||||
return <Form.Item
|
return <Form.Item
|
||||||
key={`${index}value`}
|
key={`${index}value`}
|
||||||
@@ -137,8 +148,22 @@ function FiltersSection({filters, form, bodyshop}) {
|
|||||||
|
|
||||||
const reflections = reflector ? generateReflections(reflector) : [];
|
const reflections = reflector ? generateReflections(reflector) : [];
|
||||||
const fieldPath = [[field.name, "value"]];
|
const fieldPath = [[field.name, "value"]];
|
||||||
|
// We have reflections so we will use a select box
|
||||||
if (reflections.length > 0) {
|
if (reflections.length > 0) {
|
||||||
|
// We have reflections and the operator type is array, so we will use a select box with multiple options
|
||||||
|
if (operatorType === "array") {
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
disabled={!operator}
|
||||||
|
mode="multiple"
|
||||||
|
options={reflections}
|
||||||
|
getPopupContainer={trigger => trigger.parentNode}
|
||||||
|
onChange={(value) => {
|
||||||
|
form.setFieldValue(fieldPath, value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
options={reflections}
|
options={reflections}
|
||||||
@@ -150,16 +175,50 @@ function FiltersSection({filters, form, bodyshop}) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have a type of number, so we will use a number input
|
||||||
if (type === "number") {
|
if (type === "number") {
|
||||||
return (
|
return (
|
||||||
<InputNumber
|
<InputNumber
|
||||||
|
disabled={!operator}
|
||||||
onChange={(value) => form.setFieldValue(fieldPath, value)}/>
|
onChange={(value) => form.setFieldValue(fieldPath, value)}/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have a type of date, so we will use a date picker
|
||||||
|
if (type === "date") {
|
||||||
|
return (
|
||||||
|
<FormDatePicker
|
||||||
|
disabled={!operator}
|
||||||
|
onChange={(date) => form.setFieldValue(fieldPath, date)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have a type of boolean, so we will use a select box with a true or false option.
|
||||||
|
if (type === "boolean" || type === "bool") {
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
disabled={!operator}
|
||||||
|
getPopupContainer={trigger => trigger.parentNode}
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: t('reportcenter.labels.advanced_filters_true'),
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('reportcenter.labels.advanced_filters_false'),
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
onChange={(value) => form.setFieldValue(fieldPath, value)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Input
|
<Input
|
||||||
onChange={(e) => form.setFieldValue(fieldPath, e.target.value)}/>
|
disabled={!operator}
|
||||||
|
onChange={(e) => form.setFieldValue(fieldPath, e.target.value)}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
@@ -206,13 +265,12 @@ function FiltersSection({filters, form, bodyshop}) {
|
|||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function SortersSection({sorters, form}) {
|
function SortersSection({sorters}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Card type='inner' title={t('reportcenter.labels.advanced_filters_sorters')}
|
<Card type='inner' title={t('reportcenter.labels.advanced_filters_sorters')} style={{marginTop: '10px'}}>
|
||||||
style={{marginTop: '10px'}}>
|
|
||||||
<Form.List name={["sorters"]}>
|
<Form.List name={["sorters"]}>
|
||||||
{(fields, {add, remove, move}) => {
|
{(fields, {add, remove}) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
Sorters
|
Sorters
|
||||||
|
|||||||
@@ -8,6 +8,21 @@ import {uniqBy} from "lodash";
|
|||||||
*/
|
*/
|
||||||
const getValueFromPath = (obj, path) => path.split('.').reduce((prev, curr) => prev?.[curr], obj);
|
const getValueFromPath = (obj, path) => path.split('.').reduce((prev, curr) => prev?.[curr], obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate options from array
|
||||||
|
* @param bodyshop
|
||||||
|
* @param path
|
||||||
|
* @returns {unknown[]}
|
||||||
|
*/
|
||||||
|
const generateOptionsFromArray = (bodyshop, path) => {
|
||||||
|
const options = getValueFromPath(bodyshop, path);
|
||||||
|
return uniqBy(options.map((value) => ({
|
||||||
|
label: value,
|
||||||
|
value: value,
|
||||||
|
})), 'value');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Valid internal reflections
|
* Valid internal reflections
|
||||||
* Note: This is intended for future functionality
|
* Note: This is intended for future functionality
|
||||||
@@ -46,15 +61,16 @@ const generateOptionsFromObject = (bodyshop, path, labelPath, valuePath) => {
|
|||||||
*/
|
*/
|
||||||
const generateSpecialReflections = (bodyshop, finalPath) => {
|
const generateSpecialReflections = (bodyshop, finalPath) => {
|
||||||
switch (finalPath) {
|
switch (finalPath) {
|
||||||
|
// Special case because Referral Sources is an Array, not an Object.
|
||||||
|
case 'referral_source':
|
||||||
|
return generateOptionsFromArray(bodyshop, 'md_referral_sources');
|
||||||
|
case 'class':
|
||||||
|
return generateOptionsFromArray(bodyshop, 'md_classes');
|
||||||
case 'cost_centers':
|
case 'cost_centers':
|
||||||
return generateOptionsFromObject(bodyshop, 'md_responsibility_centers.costs', 'name', 'name');
|
return generateOptionsFromObject(bodyshop, 'md_responsibility_centers.costs', 'name', 'name');
|
||||||
// Special case because Categories is an Array, not an Object.
|
// Special case because Categories is an Array, not an Object.
|
||||||
case 'categories':
|
case 'categories':
|
||||||
const catOptions = getValueFromPath(bodyshop, 'md_categories');
|
return generateOptionsFromArray(bodyshop, 'md_categories');
|
||||||
return uniqBy(catOptions.map((value) => ({
|
|
||||||
label: value,
|
|
||||||
value: value,
|
|
||||||
})), 'value');
|
|
||||||
case 'insurance_companies':
|
case 'insurance_companies':
|
||||||
return generateOptionsFromObject(bodyshop, 'md_ins_cos', 'name', 'name');
|
return generateOptionsFromObject(bodyshop, 'md_ins_cos', 'name', 'name');
|
||||||
case 'employee_teams':
|
case 'employee_teams':
|
||||||
@@ -118,4 +134,4 @@ const generateInternalReflections = ({bodyshop, upperPath, finalPath}) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export {generateInternalReflections,}
|
export {generateInternalReflections}
|
||||||
@@ -26,6 +26,8 @@ export function ScoreboardDayStats({bodyshop, date, entries}) {
|
|||||||
return acc + value.bodyhrs;
|
return acc + value.bodyhrs;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
|
const numJobs = entries.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={dayjs(date).format("D - ddd")}
|
title={dayjs(date).format("D - ddd")}
|
||||||
@@ -34,17 +36,18 @@ export function ScoreboardDayStats({bodyshop, date, entries}) {
|
|||||||
>
|
>
|
||||||
<Statistic
|
<Statistic
|
||||||
valueStyle={{color: dailyBodyTarget > bodyHrs ? "red" : "green"}}
|
valueStyle={{color: dailyBodyTarget > bodyHrs ? "red" : "green"}}
|
||||||
label="B"
|
label="Body"
|
||||||
value={bodyHrs.toFixed(1)}
|
value={bodyHrs.toFixed(1)}
|
||||||
/>
|
/>
|
||||||
<Statistic
|
<Statistic
|
||||||
valueStyle={{color: dailyPaintTarget > paintHrs ? "red" : "green"}}
|
valueStyle={{color: dailyPaintTarget > paintHrs ? "red" : "green"}}
|
||||||
label="P"
|
label="Refinish"
|
||||||
value={paintHrs.toFixed(1)}
|
value={paintHrs.toFixed(1)}
|
||||||
/>
|
/>
|
||||||
<Divider style={{margin: 0}}/>
|
<Divider style={{margin: 0}}/>
|
||||||
|
<Statistic label="Total" value={(bodyHrs + paintHrs).toFixed(1)}/>
|
||||||
<Statistic value={(bodyHrs + paintHrs).toFixed(1)}/>
|
<Divider style={{ margin: 0 }} />
|
||||||
|
<Statistic label="Jobs" value={numJobs} />
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,227 +26,260 @@ export function ScoreboardTargetsTable({bodyshop, scoreBoardlist}) {
|
|||||||
const values = useMemo(() => {
|
const values = useMemo(() => {
|
||||||
const dateHash = _.groupBy(scoreBoardlist, "date");
|
const dateHash = _.groupBy(scoreBoardlist, "date");
|
||||||
|
|
||||||
let ret = {
|
let ret = {
|
||||||
todayBody: 0,
|
todayBody: 0,
|
||||||
todayPaint: 0,
|
todayPaint: 0,
|
||||||
weeklyPaint: 0,
|
todayJobs: 0,
|
||||||
weeklyBody: 0,
|
weeklyPaint: 0,
|
||||||
toDateBody: 0,
|
weeklyJobs: 0,
|
||||||
toDatePaint: 0,
|
weeklyBody: 0,
|
||||||
};
|
toDateBody: 0,
|
||||||
|
toDatePaint: 0,
|
||||||
|
toDateJobs: 0,
|
||||||
|
};
|
||||||
|
|
||||||
const today = dayjs();
|
const today = dayjs();
|
||||||
if (dateHash[today.format("YYYY-MM-DD")]) {
|
if (dateHash[today.format("YYYY-MM-DD")]) {
|
||||||
dateHash[today.format("YYYY-MM-DD")].forEach((d) => {
|
dateHash[today.format("YYYY-MM-DD")].forEach((d) => {
|
||||||
ret.todayBody = ret.todayBody + d.bodyhrs;
|
ret.todayBody = ret.todayBody + d.bodyhrs;
|
||||||
ret.todayPaint = ret.todayPaint + d.painthrs;
|
ret.todayPaint = ret.todayPaint + d.painthrs;
|
||||||
});
|
ret.todayJobs++;
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let StartOfWeek = dayjs().startOf("week");
|
let StartOfWeek = dayjs().startOf("week");
|
||||||
while (StartOfWeek.isSameOrBefore(today)) {
|
while (StartOfWeek.isSameOrBefore(today)) {
|
||||||
if (dateHash[StartOfWeek.format("YYYY-MM-DD")]) {
|
if (dateHash[StartOfWeek.format("YYYY-MM-DD")]) {
|
||||||
dateHash[StartOfWeek.format("YYYY-MM-DD")].forEach((d) => {
|
dateHash[StartOfWeek.format("YYYY-MM-DD")].forEach((d) => {
|
||||||
ret.weeklyBody = ret.weeklyBody + d.bodyhrs;
|
ret.weeklyBody = ret.weeklyBody + d.bodyhrs;
|
||||||
ret.weeklyPaint = ret.weeklyPaint + d.painthrs;
|
ret.weeklyPaint = ret.weeklyPaint + d.painthrs;
|
||||||
});
|
ret.weeklyJobs++;
|
||||||
}
|
});
|
||||||
StartOfWeek = StartOfWeek.add(1, "day");
|
}
|
||||||
}
|
StartOfWeek = StartOfWeek.add(1, "day");
|
||||||
|
}
|
||||||
|
|
||||||
let startOfMonth = dayjs().startOf("month");
|
let startOfMonth = dayjs().startOf("month");
|
||||||
while (startOfMonth.isSameOrBefore(today)) {
|
while (startOfMonth.isSameOrBefore(today)) {
|
||||||
if (dateHash[startOfMonth.format("YYYY-MM-DD")]) {
|
if (dateHash[startOfMonth.format("YYYY-MM-DD")]) {
|
||||||
dateHash[startOfMonth.format("YYYY-MM-DD")].forEach((d) => {
|
dateHash[startOfMonth.format("YYYY-MM-DD")].forEach((d) => {
|
||||||
ret.toDateBody = ret.toDateBody + d.bodyhrs;
|
ret.toDateBody = ret.toDateBody + d.bodyhrs;
|
||||||
ret.toDatePaint = ret.toDatePaint + d.painthrs;
|
ret.toDatePaint = ret.toDatePaint + d.painthrs;
|
||||||
});
|
ret.toDateJobs++;
|
||||||
}
|
});
|
||||||
startOfMonth = startOfMonth.add(1, "day");
|
}
|
||||||
}
|
startOfMonth = startOfMonth.add(1, "day");
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}, [scoreBoardlist]);
|
}, [scoreBoardlist]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={t("scoreboard.labels.targets")}
|
title={t("scoreboard.labels.targets")}
|
||||||
extra={<ScoreboardJobsList scoreBoardlist={scoreBoardlist}/>}
|
extra={<ScoreboardJobsList scoreBoardlist={scoreBoardlist} />}
|
||||||
>
|
>
|
||||||
<Row gutter={rowGutter}>
|
<Row gutter={rowGutter}>
|
||||||
<Col xs={24} sm={{offset: 0, span: 4}} lg={{span: 4}}>
|
<Col xs={24} sm={{ offset: 0, span: 4 }} lg={{ span: 4 }}>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("scoreboard.labels.workingdays")}
|
title={t("scoreboard.labels.workingdays")}
|
||||||
value={Util.CalculateWorkingDaysThisMonth()}
|
value={Util.CalculateWorkingDaysThisMonth()}
|
||||||
prefix={<CalendarOutlined/>}
|
prefix={<CalendarOutlined />}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} sm={{offset: 0, span: 20}} lg={{offset: 0, span: 20}}>
|
<Col xs={24} sm={{ offset: 0, span: 20 }} lg={{ offset: 0, span: 20 }}>
|
||||||
<Row>
|
<Row>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("scoreboard.labels.dailytarget")}
|
title={t("scoreboard.labels.dailytarget")}
|
||||||
value={bodyshop.scoreboard_target.dailyBodyTarget}
|
value={bodyshop.scoreboard_target.dailyBodyTarget}
|
||||||
prefix="B"
|
prefix={t("scoreboard.labels.bodyabbrev")}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("scoreboard.labels.dailyactual")}
|
title={t("scoreboard.labels.dailyactual")}
|
||||||
value={values.todayBody.toFixed(1)}
|
value={values.todayBody.toFixed(1)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("scoreboard.labels.weeklytarget")}
|
title={t("scoreboard.labels.weeklytarget")}
|
||||||
value={Util.WeeklyTargetHrs(
|
value={Util.WeeklyTargetHrs(
|
||||||
bodyshop.scoreboard_target.dailyBodyTarget,
|
bodyshop.scoreboard_target.dailyBodyTarget,
|
||||||
bodyshop
|
bodyshop
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("scoreboard.labels.weeklyactual")}
|
title={t("scoreboard.labels.weeklyactual")}
|
||||||
value={values.weeklyBody.toFixed(1)}
|
value={values.weeklyBody.toFixed(1)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("scoreboard.labels.monthlytarget")}
|
title={t("scoreboard.labels.monthlytarget")}
|
||||||
value={Util.MonthlyTargetHrs(
|
value={Util.MonthlyTargetHrs(
|
||||||
bodyshop.scoreboard_target.dailyBodyTarget,
|
bodyshop.scoreboard_target.dailyBodyTarget,
|
||||||
bodyshop
|
bodyshop
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("scoreboard.labels.asoftodaytarget")}
|
title={t("scoreboard.labels.asoftodaytarget")}
|
||||||
value={Util.AsOfTodayTargetHrs(
|
value={Util.AsOfTodayTargetHrs(
|
||||||
bodyshop.scoreboard_target.dailyBodyTarget,
|
bodyshop.scoreboard_target.dailyBodyTarget,
|
||||||
bodyshop
|
bodyshop
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("scoreboard.labels.todateactual")}
|
title={t("scoreboard.labels.todateactual")}
|
||||||
value={values.toDateBody.toFixed(1)}
|
value={values.toDateBody.toFixed(1)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
value={bodyshop.scoreboard_target.dailyPaintTarget}
|
value={bodyshop.scoreboard_target.dailyPaintTarget}
|
||||||
prefix="P"
|
prefix={t("scoreboard.labels.refinishabbrev")}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic value={values.todayPaint.toFixed(1)}/>
|
<Statistic value={values.todayPaint.toFixed(1)} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
value={Util.WeeklyTargetHrs(
|
value={Util.WeeklyTargetHrs(
|
||||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||||
bodyshop
|
bodyshop
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic value={values.weeklyPaint.toFixed(1)}/>
|
<Statistic value={values.weeklyPaint.toFixed(1)} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
value={Util.MonthlyTargetHrs(
|
value={Util.MonthlyTargetHrs(
|
||||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||||
bodyshop
|
bodyshop
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
value={Util.AsOfTodayTargetHrs(
|
value={Util.AsOfTodayTargetHrs(
|
||||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||||
bodyshop
|
bodyshop
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic value={values.toDatePaint.toFixed(1)}/>
|
<Statistic value={values.toDatePaint.toFixed(1)} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Divider style={{margin: 5}}/>
|
<Divider style={{ margin: 5 }} />
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Col {...statSpans}></Col>
|
<Col {...statSpans}>
|
||||||
<Col {...statSpans}>
|
<Statistic
|
||||||
<Statistic
|
value={"\u00A0"}
|
||||||
value={(values.todayPaint + values.todayBody).toFixed(1)}
|
prefix={t("scoreboard.labels.total")}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
value={(
|
value={(values.todayPaint + values.todayBody).toFixed(1)}
|
||||||
Util.WeeklyTargetHrs(
|
/>
|
||||||
bodyshop.scoreboard_target.dailyBodyTarget,
|
</Col>
|
||||||
bodyshop
|
<Col {...statSpans}>
|
||||||
) +
|
<Statistic
|
||||||
Util.WeeklyTargetHrs(
|
value={(
|
||||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
Util.WeeklyTargetHrs(
|
||||||
bodyshop
|
bodyshop.scoreboard_target.dailyBodyTarget,
|
||||||
)
|
bodyshop
|
||||||
).toFixed(1)}
|
) +
|
||||||
/>
|
Util.WeeklyTargetHrs(
|
||||||
</Col>
|
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||||
<Col {...statSpans}>
|
bodyshop
|
||||||
<Statistic
|
)
|
||||||
value={(values.weeklyPaint + values.weeklyBody).toFixed(1)}
|
).toFixed(1)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...statSpans}>
|
<Col {...statSpans}>
|
||||||
<Statistic
|
<Statistic
|
||||||
value={(
|
value={(values.weeklyPaint + values.weeklyBody).toFixed(1)}
|
||||||
Util.MonthlyTargetHrs(
|
/>
|
||||||
bodyshop.scoreboard_target.dailyBodyTarget,
|
</Col>
|
||||||
bodyshop
|
<Col {...statSpans}>
|
||||||
) +
|
<Statistic
|
||||||
Util.MonthlyTargetHrs(
|
value={(
|
||||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
Util.MonthlyTargetHrs(
|
||||||
bodyshop
|
bodyshop.scoreboard_target.dailyBodyTarget,
|
||||||
)
|
bodyshop
|
||||||
).toFixed(1)}
|
) +
|
||||||
/>
|
Util.MonthlyTargetHrs(
|
||||||
</Col>
|
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||||
<Col {...statSpans}>
|
bodyshop
|
||||||
<Statistic
|
)
|
||||||
value={(
|
).toFixed(1)}
|
||||||
Util.AsOfTodayTargetHrs(
|
/>
|
||||||
bodyshop.scoreboard_target.dailyBodyTarget,
|
</Col>
|
||||||
bodyshop
|
<Col {...statSpans}>
|
||||||
) +
|
<Statistic
|
||||||
Util.AsOfTodayTargetHrs(
|
value={(
|
||||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
Util.AsOfTodayTargetHrs(
|
||||||
bodyshop
|
bodyshop.scoreboard_target.dailyBodyTarget,
|
||||||
)
|
bodyshop
|
||||||
).toFixed(1)}
|
) +
|
||||||
/>
|
Util.AsOfTodayTargetHrs(
|
||||||
</Col>
|
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||||
<Col {...statSpans}>
|
bodyshop
|
||||||
<Statistic
|
)
|
||||||
value={(values.toDatePaint + values.toDateBody).toFixed(1)}
|
).toFixed(1)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
<Col {...statSpans}>
|
||||||
</Col>
|
<Statistic
|
||||||
</Row>
|
value={(values.toDatePaint + values.toDateBody).toFixed(1)}
|
||||||
</Card>
|
/>
|
||||||
);
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Divider style={{ margin: 5 }} />
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col {...statSpans}>
|
||||||
|
<Statistic
|
||||||
|
value={"\u00A0"}
|
||||||
|
prefix={t("scoreboard.labels.jobs")}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col {...statSpans}>
|
||||||
|
<Statistic value={values.todayJobs} />
|
||||||
|
</Col>
|
||||||
|
<Col {...statSpans} />
|
||||||
|
<Col {...statSpans}>
|
||||||
|
<Statistic value={values.weeklyJobs} />
|
||||||
|
</Col>
|
||||||
|
<Col {...statSpans} />
|
||||||
|
<Col {...statSpans} />
|
||||||
|
<Col {...statSpans}>
|
||||||
|
<Statistic value={values.toDateJobs} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(ScoreboardTargetsTable);
|
)(ScoreboardTargetsTable);
|
||||||
|
|||||||
@@ -16,8 +16,13 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com
|
|||||||
import {OwnerNameDisplayFunction} from "../../components/owner-name-display/owner-name-display.component";
|
import {OwnerNameDisplayFunction} from "../../components/owner-name-display/owner-name-display.component";
|
||||||
import {auth} from "../../firebase/firebase.utils";
|
import {auth} from "../../firebase/firebase.utils";
|
||||||
import {QUERY_JOB_EXPORT_DMS} from "../../graphql/jobs.queries";
|
import {QUERY_JOB_EXPORT_DMS} from "../../graphql/jobs.queries";
|
||||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
import {
|
||||||
|
insertAuditTrail,
|
||||||
|
setBreadcrumbs,
|
||||||
|
setSelectedHeader,
|
||||||
|
} from "../../redux/application/application.actions";
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -26,6 +31,8 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||||
|
insertAuditTrail: ({ jobid, operation }) =>
|
||||||
|
dispatch(insertAuditTrail({ jobid, operation })),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);
|
export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);
|
||||||
@@ -45,7 +52,12 @@ export const socket = SocketIO(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export function DmsContainer({bodyshop, setBreadcrumbs, setSelectedHeader}) {
|
export function DmsContainer({
|
||||||
|
bodyshop,
|
||||||
|
setBreadcrumbs,
|
||||||
|
setSelectedHeader,
|
||||||
|
insertAuditTrail,
|
||||||
|
}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const [logLevel, setLogLevel] = useState("DEBUG");
|
const [logLevel, setLogLevel] = useState("DEBUG");
|
||||||
const history = useNavigate();
|
const history = useNavigate();
|
||||||
@@ -103,6 +115,10 @@ export function DmsContainer({bodyshop, setBreadcrumbs, setSelectedHeader}) {
|
|||||||
notification.success({
|
notification.success({
|
||||||
message: t("jobs.successes.exported"),
|
message: t("jobs.successes.exported"),
|
||||||
});
|
});
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: payload,
|
||||||
|
operation: AuditTrailMapping.jobexported(),
|
||||||
|
});
|
||||||
history("/manage/accounting/receivables");
|
history("/manage/accounting/receivables");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -281,12 +281,12 @@ export function* insertAuditTrailSaga({
|
|||||||
yield client.mutate({
|
yield client.mutate({
|
||||||
mutation: INSERT_AUDIT_TRAIL,
|
mutation: INSERT_AUDIT_TRAIL,
|
||||||
variables,
|
variables,
|
||||||
update(cache, {data}) {
|
update(cache, { data }) {
|
||||||
cache.modify({
|
cache.modify({
|
||||||
fields: {
|
fields: {
|
||||||
audit_trail(existingAuditTrail, {readField}) {
|
audit_trail(existingAuditTrail, { readField }) {
|
||||||
const newAuditTrail = cache.writeQuery({
|
const newAuditTrail = cache.writeQuery({
|
||||||
data: data.insert_audit_trail_one,
|
data: data,
|
||||||
query: INSERT_AUDIT_TRAIL,
|
query: INSERT_AUDIT_TRAIL,
|
||||||
variables,
|
variables,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -107,13 +107,14 @@
|
|||||||
"alerttoggle": "Alert Toggle set to {{status}}",
|
"alerttoggle": "Alert Toggle set to {{status}}",
|
||||||
"appointmentcancel": "Appointment canceled. Lost Reason: {{lost_sale_reason}}.",
|
"appointmentcancel": "Appointment canceled. Lost Reason: {{lost_sale_reason}}.",
|
||||||
"appointmentinsert": "Appointment created. Appointment Date: {{start}}.",
|
"appointmentinsert": "Appointment created. Appointment Date: {{start}}.",
|
||||||
"billposted": "Bill with invoice number {{invoice_number}} posted.",
|
"billdeleted": "Bill with invoice number {{invoice_number}} deleted.",
|
||||||
|
"billposted": "Bill with invoice number {{invoice_number}} posted.",
|
||||||
"billupdated": "Bill with invoice number {{invoice_number}} updated.",
|
"billupdated": "Bill with invoice number {{invoice_number}} updated.",
|
||||||
"failedpayment": "Failed payment",
|
"failedpayment": "Failed payment",
|
||||||
"jobassignmentchange": "Employee {{name}} assigned to {{operation}}",
|
"jobassignmentchange": "Employee {{name}} assigned to {{operation}}",
|
||||||
"jobassignmentremoved": "Employee assignment removed for {{operation}}",
|
"jobassignmentremoved": "Employee assignment removed for {{operation}}",
|
||||||
"jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.",
|
"jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.",
|
||||||
"jobconverted": "Job converted and assigned number {{ro_number}}.",
|
"jobconverted": "Job converted and assigned number {{ro_number}}.","jobexported": "Job has been exported.",
|
||||||
"jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.",
|
"jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.",
|
||||||
"jobimported": "Job imported.",
|
"jobimported": "Job imported.",
|
||||||
"jobinproductionchange": "Job production status set to {{inproduction}}",
|
"jobinproductionchange": "Job production status set to {{inproduction}}",
|
||||||
@@ -126,8 +127,9 @@
|
|||||||
"jobspartsorder": "Parts order {{order_number}} added to Job.",
|
"jobspartsorder": "Parts order {{order_number}} added to Job.",
|
||||||
"jobspartsreturn": "Parts return {{order_number}} added to Job.",
|
"jobspartsreturn": "Parts return {{order_number}} added to Job.",
|
||||||
"jobstatuschange": "Job status changed to {{status}}.",
|
"jobstatuschange": "Job status changed to {{status}}.",
|
||||||
"jobsupplement": "Job supplement imported."
|
"jobsupplement": "Job supplement imported.",
|
||||||
}
|
"jobsuspend": "Suspend Toggle set to {{status}}",
|
||||||
|
"jobvoid": "Job has been voided."}
|
||||||
},
|
},
|
||||||
"billlines": {
|
"billlines": {
|
||||||
"actions": {
|
"actions": {
|
||||||
@@ -2620,6 +2622,8 @@
|
|||||||
"advanced_filters_sorters": "Sorters",
|
"advanced_filters_sorters": "Sorters",
|
||||||
"advanced_filters_filter_field": "Field",
|
"advanced_filters_filter_field": "Field",
|
||||||
"advanced_filters_sorter_field": "Field",
|
"advanced_filters_sorter_field": "Field",
|
||||||
|
"advanced_filters_true": "True",
|
||||||
|
"advanced_filters_false": "False",
|
||||||
"advanced_filters_sorter_direction": "Direction",
|
"advanced_filters_sorter_direction": "Direction",
|
||||||
"advanced_filters_filter_operator": "Operator",
|
"advanced_filters_filter_operator": "Operator",
|
||||||
"advanced_filters_filter_value": "Value",
|
"advanced_filters_filter_value": "Value",
|
||||||
@@ -2793,7 +2797,8 @@
|
|||||||
"allemployeetimetickets": "All Employee Time Tickets",
|
"allemployeetimetickets": "All Employee Time Tickets",
|
||||||
"asoftodaytarget": "As of Today",
|
"asoftodaytarget": "As of Today",
|
||||||
"body": "Body",
|
"body": "Body",
|
||||||
"bodycharttitle": "Body Targets vs Actual",
|
"bodyabbrev": "B",
|
||||||
|
"bodycharttitle": "Body Targets vs Actual",
|
||||||
"calendarperiod": "Periods based on calendar weeks/months.",
|
"calendarperiod": "Periods based on calendar weeks/months.",
|
||||||
"combinedcharttitle": "Combined Targets vs Actual",
|
"combinedcharttitle": "Combined Targets vs Actual",
|
||||||
"dailyactual": "Actual (D)",
|
"dailyactual": "Actual (D)",
|
||||||
@@ -2808,14 +2813,14 @@
|
|||||||
"priorweek": "Prior Week",
|
"priorweek": "Prior Week",
|
||||||
"productivestatistics": "Productive Hours Statistics",
|
"productivestatistics": "Productive Hours Statistics",
|
||||||
"productivetimeticketsoverdate": "Productive Hours over Selected Dates",
|
"productivetimeticketsoverdate": "Productive Hours over Selected Dates",
|
||||||
"refinish": "Refinish",
|
"refinish": "Refinish","refinishabbrev": "R",
|
||||||
"refinishcharttitle": "Refinish Targets vs Actual",
|
"refinishcharttitle": "Refinish Targets vs Actual",
|
||||||
"targets": "Targets",
|
"targets": "Targets",
|
||||||
"thismonth": "This Month",
|
"thismonth": "This Month",
|
||||||
"thisweek": "This Week",
|
"thisweek": "This Week",
|
||||||
"timetickets": "Time Tickets",
|
"timetickets": "Time Tickets",
|
||||||
"timeticketsemployee": "Time Tickets by Employee",
|
"timeticketsemployee": "Time Tickets by Employee",
|
||||||
"todateactual": "Actual (MTD)",
|
"todateactual": "Actual (MTD)","total": "Total",
|
||||||
"totalhrs": "Total Hours",
|
"totalhrs": "Total Hours",
|
||||||
"totaloverperiod": "Total over Selected Dates",
|
"totaloverperiod": "Total over Selected Dates",
|
||||||
"weeklyactual": "Actual (W)",
|
"weeklyactual": "Actual (W)",
|
||||||
|
|||||||
@@ -107,14 +107,16 @@
|
|||||||
"alerttoggle": "",
|
"alerttoggle": "",
|
||||||
"appointmentcancel": "",
|
"appointmentcancel": "",
|
||||||
"appointmentinsert": "",
|
"appointmentinsert": "",
|
||||||
"billposted": "",
|
"billdeleted": "",
|
||||||
|
"billposted": "",
|
||||||
"billupdated": "",
|
"billupdated": "",
|
||||||
"failedpayment": "",
|
"failedpayment": "",
|
||||||
"jobassignmentchange": "",
|
"jobassignmentchange": "",
|
||||||
"jobassignmentremoved": "",
|
"jobassignmentremoved": "",
|
||||||
"jobchecklist": "",
|
"jobchecklist": "",
|
||||||
"jobconverted": "",
|
"jobconverted": "",
|
||||||
"jobfieldchanged": "",
|
"jobexported": "",
|
||||||
|
"jobfieldchanged": "",
|
||||||
"jobimported": "",
|
"jobimported": "",
|
||||||
"jobinproductionchange": "",
|
"jobinproductionchange": "",
|
||||||
"jobinvoiced": "",
|
"jobinvoiced": "",
|
||||||
@@ -126,8 +128,9 @@
|
|||||||
"jobspartsorder": "",
|
"jobspartsorder": "",
|
||||||
"jobspartsreturn": "",
|
"jobspartsreturn": "",
|
||||||
"jobstatuschange": "",
|
"jobstatuschange": "",
|
||||||
"jobsupplement": ""
|
"jobsupplement": "",
|
||||||
}
|
"jobsuspend": "",
|
||||||
|
"jobvoid": ""}
|
||||||
},
|
},
|
||||||
"billlines": {
|
"billlines": {
|
||||||
"actions": {
|
"actions": {
|
||||||
@@ -2620,6 +2623,8 @@
|
|||||||
"advanced_filters_sorters": "",
|
"advanced_filters_sorters": "",
|
||||||
"advanced_filters_filter_field": "",
|
"advanced_filters_filter_field": "",
|
||||||
"advanced_filters_sorter_field": "",
|
"advanced_filters_sorter_field": "",
|
||||||
|
"advanced_filters_true": "",
|
||||||
|
"advanced_filters_false": "",
|
||||||
"advanced_filters_sorter_direction": "",
|
"advanced_filters_sorter_direction": "",
|
||||||
"advanced_filters_filter_operator": "",
|
"advanced_filters_filter_operator": "",
|
||||||
"advanced_filters_filter_value": "",
|
"advanced_filters_filter_value": "",
|
||||||
@@ -2793,7 +2798,8 @@
|
|||||||
"allemployeetimetickets": "",
|
"allemployeetimetickets": "",
|
||||||
"asoftodaytarget": "",
|
"asoftodaytarget": "",
|
||||||
"body": "",
|
"body": "",
|
||||||
"bodycharttitle": "",
|
"bodyabbrev": "",
|
||||||
|
"bodycharttitle": "",
|
||||||
"calendarperiod": "",
|
"calendarperiod": "",
|
||||||
"combinedcharttitle": "",
|
"combinedcharttitle": "",
|
||||||
"dailyactual": "",
|
"dailyactual": "",
|
||||||
@@ -2809,13 +2815,14 @@
|
|||||||
"productivestatistics": "",
|
"productivestatistics": "",
|
||||||
"productivetimeticketsoverdate": "",
|
"productivetimeticketsoverdate": "",
|
||||||
"refinish": "",
|
"refinish": "",
|
||||||
"refinishcharttitle": "",
|
"refinishabbrev": "",
|
||||||
|
"refinishcharttitle": "",
|
||||||
"targets": "",
|
"targets": "",
|
||||||
"thismonth": "",
|
"thismonth": "",
|
||||||
"thisweek": "",
|
"thisweek": "",
|
||||||
"timetickets": "",
|
"timetickets": "",
|
||||||
"timeticketsemployee": "",
|
"timeticketsemployee": "",
|
||||||
"todateactual": "",
|
"todateactual": "","total": "",
|
||||||
"totalhrs": "",
|
"totalhrs": "",
|
||||||
"totaloverperiod": "",
|
"totaloverperiod": "",
|
||||||
"weeklyactual": "",
|
"weeklyactual": "",
|
||||||
|
|||||||
@@ -107,14 +107,16 @@
|
|||||||
"alerttoggle": "",
|
"alerttoggle": "",
|
||||||
"appointmentcancel": "",
|
"appointmentcancel": "",
|
||||||
"appointmentinsert": "",
|
"appointmentinsert": "",
|
||||||
"billposted": "",
|
"billdeleted": "",
|
||||||
|
"billposted": "",
|
||||||
"billupdated": "",
|
"billupdated": "",
|
||||||
"failedpayment": "",
|
"failedpayment": "",
|
||||||
"jobassignmentchange": "",
|
"jobassignmentchange": "",
|
||||||
"jobassignmentremoved": "",
|
"jobassignmentremoved": "",
|
||||||
"jobchecklist": "",
|
"jobchecklist": "",
|
||||||
"jobconverted": "",
|
"jobconverted": "",
|
||||||
"jobfieldchanged": "",
|
"jobexported": "",
|
||||||
|
"jobfieldchanged": "",
|
||||||
"jobimported": "",
|
"jobimported": "",
|
||||||
"jobinproductionchange": "",
|
"jobinproductionchange": "",
|
||||||
"jobinvoiced": "",
|
"jobinvoiced": "",
|
||||||
@@ -126,8 +128,9 @@
|
|||||||
"jobspartsorder": "",
|
"jobspartsorder": "",
|
||||||
"jobspartsreturn": "",
|
"jobspartsreturn": "",
|
||||||
"jobstatuschange": "",
|
"jobstatuschange": "",
|
||||||
"jobsupplement": ""
|
"jobsupplement": "",
|
||||||
}
|
"jobsuspend": "",
|
||||||
|
"jobvoid": ""}
|
||||||
},
|
},
|
||||||
"billlines": {
|
"billlines": {
|
||||||
"actions": {
|
"actions": {
|
||||||
@@ -2620,6 +2623,8 @@
|
|||||||
"advanced_filters_sorters": "",
|
"advanced_filters_sorters": "",
|
||||||
"advanced_filters_filter_field": "",
|
"advanced_filters_filter_field": "",
|
||||||
"advanced_filters_sorter_field": "",
|
"advanced_filters_sorter_field": "",
|
||||||
|
"advanced_filters_true": "",
|
||||||
|
"advanced_filters_false": "",
|
||||||
"advanced_filters_sorter_direction": "",
|
"advanced_filters_sorter_direction": "",
|
||||||
"advanced_filters_filter_operator": "",
|
"advanced_filters_filter_operator": "",
|
||||||
"advanced_filters_filter_value": "",
|
"advanced_filters_filter_value": "",
|
||||||
@@ -2793,7 +2798,8 @@
|
|||||||
"allemployeetimetickets": "",
|
"allemployeetimetickets": "",
|
||||||
"asoftodaytarget": "",
|
"asoftodaytarget": "",
|
||||||
"body": "",
|
"body": "",
|
||||||
"bodycharttitle": "",
|
"bodyabbrev": "",
|
||||||
|
"bodycharttitle": "",
|
||||||
"calendarperiod": "",
|
"calendarperiod": "",
|
||||||
"combinedcharttitle": "",
|
"combinedcharttitle": "",
|
||||||
"dailyactual": "",
|
"dailyactual": "",
|
||||||
@@ -2809,13 +2815,14 @@
|
|||||||
"productivestatistics": "",
|
"productivestatistics": "",
|
||||||
"productivetimeticketsoverdate": "",
|
"productivetimeticketsoverdate": "",
|
||||||
"refinish": "",
|
"refinish": "",
|
||||||
"refinishcharttitle": "",
|
"refinishabbrev": "",
|
||||||
|
"refinishcharttitle": "",
|
||||||
"targets": "",
|
"targets": "",
|
||||||
"thismonth": "",
|
"thismonth": "",
|
||||||
"thisweek": "",
|
"thisweek": "",
|
||||||
"timetickets": "",
|
"timetickets": "",
|
||||||
"timeticketsemployee": "",
|
"timeticketsemployee": "",
|
||||||
"todateactual": "",
|
"todateactual": "","total": "",
|
||||||
"totalhrs": "",
|
"totalhrs": "",
|
||||||
"totaloverperiod": "",
|
"totaloverperiod": "",
|
||||||
"weeklyactual": "",
|
"weeklyactual": "",
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ const AuditTrailMapping = {
|
|||||||
i18n.t("audit_trail.messages.appointmentcancel", {lost_sale_reason}),
|
i18n.t("audit_trail.messages.appointmentcancel", {lost_sale_reason}),
|
||||||
appointmentinsert: (start) =>
|
appointmentinsert: (start) =>
|
||||||
i18n.t("audit_trail.messages.appointmentinsert", {start}),
|
i18n.t("audit_trail.messages.appointmentinsert", {start}),
|
||||||
|
billdeleted: (invoice_number) =>
|
||||||
|
i18n.t("audit_trail.messages.billdeleted", { invoice_number }),
|
||||||
billposted: (invoice_number) =>
|
billposted: (invoice_number) =>
|
||||||
i18n.t("audit_trail.messages.billposted", {invoice_number}),
|
i18n.t("audit_trail.messages.billposted", {invoice_number}),
|
||||||
billupdated: (invoice_number) =>
|
billupdated: (invoice_number) =>
|
||||||
@@ -33,6 +35,7 @@ const AuditTrailMapping = {
|
|||||||
i18n.t("audit_trail.messages.jobchecklist", {type, inproduction, status}),
|
i18n.t("audit_trail.messages.jobchecklist", {type, inproduction, status}),
|
||||||
jobconverted: (ro_number) =>
|
jobconverted: (ro_number) =>
|
||||||
i18n.t("audit_trail.messages.jobconverted", {ro_number}),
|
i18n.t("audit_trail.messages.jobconverted", {ro_number}),
|
||||||
|
jobexported: () => i18n.t("audit_trail.messages.jobexported"),
|
||||||
jobfieldchange: (field, value) =>
|
jobfieldchange: (field, value) =>
|
||||||
i18n.t("audit_trail.messages.jobfieldchanged", {field, value}),
|
i18n.t("audit_trail.messages.jobfieldchanged", {field, value}),
|
||||||
jobimported: () => i18n.t("audit_trail.messages.jobimported"),
|
jobimported: () => i18n.t("audit_trail.messages.jobimported"),
|
||||||
@@ -51,6 +54,8 @@ const AuditTrailMapping = {
|
|||||||
jobstatuschange: (status) =>
|
jobstatuschange: (status) =>
|
||||||
i18n.t("audit_trail.messages.jobstatuschange", {status}),
|
i18n.t("audit_trail.messages.jobstatuschange", {status}),
|
||||||
jobsupplement: () => i18n.t("audit_trail.messages.jobsupplement"),
|
jobsupplement: () => i18n.t("audit_trail.messages.jobsupplement"),
|
||||||
|
jobsuspend: (status) => i18n.t("audit_trail.messages.jobsuspend", { status }),
|
||||||
|
jobvoid: () => i18n.t("audit_trail.messages.jobvoid"),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AuditTrailMapping;
|
export default AuditTrailMapping;
|
||||||
|
|||||||
@@ -2,22 +2,66 @@ import {Kind, parse, print, visit} from "graphql";
|
|||||||
import client from "./GraphQLClient";
|
import client from "./GraphQLClient";
|
||||||
import {gql} from "@apollo/client";
|
import {gql} from "@apollo/client";
|
||||||
|
|
||||||
|
/* eslint-disable no-loop-func */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The available operators for filtering (string)
|
||||||
|
* @type {[{label: string, value: string},{label: string, value: string},{label: string, value: string},{label: string, value: string},{label: string, value: string},null,null,null]}
|
||||||
|
*/
|
||||||
const STRING_OPERATORS = [
|
const STRING_OPERATORS = [
|
||||||
{value: "_eq", label: "equals"},
|
{value: "_eq", label: "equals"},
|
||||||
{value: "_neq", label: "does not equal"},
|
{value: "_neq", label: "does not equal"},
|
||||||
{value: "_like", label: "contains"},
|
{value: "_like", label: "contains"},
|
||||||
{value: "_nlike", label: "does not contain"},
|
{value: "_nlike", label: "does not contain"},
|
||||||
{value: "_ilike", label: "contains case-insensitive"},
|
{value: "_ilike", label: "contains case-insensitive"},
|
||||||
{value: "_nilike", label: "does not contain case-insensitive"}
|
{value: "_nilike", label: "does not contain case-insensitive"},
|
||||||
|
{value: "_in", label: "in", type: "array"},
|
||||||
|
{value: "_nin", label: "not in", type: "array"}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The available operators for filtering (dates)
|
||||||
|
* @type {[{label: string, value: string},{label: string, value: string},{label: string, value: string},{label: string, value: string},{label: string, value: string},null,null,null]}
|
||||||
|
*/
|
||||||
|
const DATE_OPERATORS = [
|
||||||
|
{value: "_eq", label: "equals"},
|
||||||
|
{value: "_neq", label: "does not equal"},
|
||||||
|
{value: "_gt", label: "greater than"},
|
||||||
|
{value: "_lt", label: "less than"},
|
||||||
|
{value: "_gte", label: "greater than or equal"},
|
||||||
|
{value: "_lte", label: "less than or equal"},
|
||||||
|
{value: "_in", label: "in", type: "array"},
|
||||||
|
{value: "_nin", label: "not in", type: "array"}
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The available operators for filtering (booleans)
|
||||||
|
* @type {[{label: string, value: string},{label: string, value: string}]}
|
||||||
|
*/
|
||||||
|
const BOOLEAN_OPERATORS = [
|
||||||
|
{value: "_eq", label: "equals"},
|
||||||
|
{value: "_neq", label: "does not equal"},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The available operators for filtering (numbers)
|
||||||
|
* @type {[{label: string, value: string},{label: string, value: string},{label: string, value: string},{label: string, value: string},{label: string, value: string},null,null,null]}
|
||||||
|
*/
|
||||||
const NUMBER_OPERATORS = [
|
const NUMBER_OPERATORS = [
|
||||||
{value: "_eq", label: "equals"},
|
{value: "_eq", label: "equals"},
|
||||||
{value: "_neq", label: "does not equal"},
|
{value: "_neq", label: "does not equal"},
|
||||||
{value: "_gt", label: "greater than"},
|
{value: "_gt", label: "greater than"},
|
||||||
{value: "_lt", label: "less than"},
|
{value: "_lt", label: "less than"},
|
||||||
{value: "_gte", label: "greater than or equal"},
|
{value: "_gte", label: "greater than or equal"},
|
||||||
{value: "_lte", label: "less than or equal"}
|
{value: "_lte", label: "less than or equal"},
|
||||||
|
{value: "_in", label: "in", type: "array"},
|
||||||
|
{value: "_nin", label: "not in", type: "array"}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The available operators for sorting
|
||||||
|
* @type {[{label: string, value: string},{label: string, value: string}]}
|
||||||
|
*/
|
||||||
const ORDER_BY_OPERATORS = [
|
const ORDER_BY_OPERATORS = [
|
||||||
{value: "asc", label: "ascending"},
|
{value: "asc", label: "ascending"},
|
||||||
{value: "desc", label: "descending"}
|
{value: "desc", label: "descending"}
|
||||||
@@ -31,7 +75,6 @@ export function getOrderOperatorsByType() {
|
|||||||
return ORDER_BY_OPERATORS;
|
return ORDER_BY_OPERATORS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the available operators for filtering
|
* Get the available operators for filtering
|
||||||
* @param type
|
* @param type
|
||||||
@@ -40,13 +83,14 @@ export function getOrderOperatorsByType() {
|
|||||||
export function getWhereOperatorsByType(type = 'string') {
|
export function getWhereOperatorsByType(type = 'string') {
|
||||||
const operators = {
|
const operators = {
|
||||||
string: STRING_OPERATORS,
|
string: STRING_OPERATORS,
|
||||||
number: NUMBER_OPERATORS
|
number: NUMBER_OPERATORS,
|
||||||
|
boolean: BOOLEAN_OPERATORS,
|
||||||
|
bool: BOOLEAN_OPERATORS,
|
||||||
|
date: DATE_OPERATORS
|
||||||
};
|
};
|
||||||
return operators[type];
|
return operators[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable no-loop-func */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a GraphQL query into an AST
|
* Parse a GraphQL query into an AST
|
||||||
* @param query
|
* @param query
|
||||||
@@ -78,11 +122,9 @@ export async function generateTemplate(templateQueryToExecute, templateObject, u
|
|||||||
// Parse the query and apply the filters and sorters
|
// Parse the query and apply the filters and sorters
|
||||||
const ast = parseQuery(templateQueryToExecute);
|
const ast = parseQuery(templateQueryToExecute);
|
||||||
|
|
||||||
let filterFields = [];
|
|
||||||
|
|
||||||
if (templateObject?.filters && templateObject?.filters?.length) {
|
if (templateObject?.filters && templateObject?.filters?.length) {
|
||||||
applyFilters(ast, templateObject.filters, filterFields);
|
applyFilters(ast, templateObject.filters);
|
||||||
wrapFiltersInAnd(ast, filterFields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (templateObject?.sorters && templateObject?.sorters?.length) {
|
if (templateObject?.sorters && templateObject?.sorters?.length) {
|
||||||
@@ -109,7 +151,6 @@ export async function generateTemplate(templateQueryToExecute, templateObject, u
|
|||||||
return {contextData, useShopSpecificTemplate};
|
return {contextData, useShopSpecificTemplate};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply sorters to the AST
|
* Apply sorters to the AST
|
||||||
* @param ast
|
* @param ast
|
||||||
@@ -170,10 +211,59 @@ export function applySorters(ast, sorters) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply Top Level Sub to the AST
|
||||||
|
* @param node
|
||||||
|
* @param fieldPath
|
||||||
|
* @param filterField
|
||||||
|
*/
|
||||||
|
function applyTopLevelSub(node, fieldPath, filterField) {
|
||||||
|
// Find or create the where argument for the top-level subfield
|
||||||
|
let whereArg = node.selectionSet.selections
|
||||||
|
.find(selection => selection.name.value === fieldPath[0])
|
||||||
|
?.arguments.find(arg => arg.name.value === 'where');
|
||||||
|
|
||||||
|
if (!whereArg) {
|
||||||
|
whereArg = {
|
||||||
|
kind: Kind.ARGUMENT,
|
||||||
|
name: {kind: Kind.NAME, value: 'where'},
|
||||||
|
value: {kind: Kind.OBJECT, fields: []},
|
||||||
|
};
|
||||||
|
const topLevelSubSelection = node.selectionSet.selections.find(selection =>
|
||||||
|
selection.name.value === fieldPath[0]
|
||||||
|
);
|
||||||
|
if (topLevelSubSelection) {
|
||||||
|
topLevelSubSelection.arguments = topLevelSubSelection.arguments || [];
|
||||||
|
topLevelSubSelection.arguments.push(whereArg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correctly position the nested filter without an extra 'where'
|
||||||
|
if (fieldPath.length > 2) { // More than one level deep
|
||||||
|
let currentField = whereArg.value;
|
||||||
|
fieldPath.slice(1, -1).forEach((path, index) => {
|
||||||
|
let existingField = currentField.fields.find(f => f.name.value === path);
|
||||||
|
if (!existingField) {
|
||||||
|
existingField = {
|
||||||
|
kind: Kind.OBJECT_FIELD,
|
||||||
|
name: {kind: Kind.NAME, value: path},
|
||||||
|
value: {kind: Kind.OBJECT, fields: []}
|
||||||
|
};
|
||||||
|
currentField.fields.push(existingField);
|
||||||
|
}
|
||||||
|
currentField = existingField.value;
|
||||||
|
});
|
||||||
|
currentField.fields.push(filterField);
|
||||||
|
} else { // Directly under the top level
|
||||||
|
whereArg.value.fields.push(filterField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply filters to the AST
|
* Apply filters to the AST
|
||||||
* @param ast
|
* @param ast
|
||||||
* @param filters
|
* @param filters
|
||||||
|
* @returns {ASTNode}
|
||||||
*/
|
*/
|
||||||
export function applyFilters(ast, filters) {
|
export function applyFilters(ast, filters) {
|
||||||
return visit(ast, {
|
return visit(ast, {
|
||||||
@@ -182,192 +272,197 @@ export function applyFilters(ast, filters) {
|
|||||||
filters.forEach(filter => {
|
filters.forEach(filter => {
|
||||||
const fieldPath = filter.field.split('.');
|
const fieldPath = filter.field.split('.');
|
||||||
let topLevel = false;
|
let topLevel = false;
|
||||||
|
let topLevelSub = false;
|
||||||
|
|
||||||
// Determine if the filter should be applied at the top level
|
// Determine if the filter should be applied at the top level
|
||||||
if (fieldPath[0].startsWith('[') && fieldPath[0].endsWith(']')) {
|
if (fieldPath.length === 2) {
|
||||||
fieldPath[0] = fieldPath[0].substring(1, fieldPath[0].length - 1); // Strip the brackets
|
|
||||||
topLevel = true;
|
topLevel = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topLevel) {
|
if (fieldPath.length > 2 && fieldPath[0].startsWith('[') && fieldPath[0].endsWith(']')) {
|
||||||
// Construct the filter for a top-level application
|
fieldPath[0] = fieldPath[0].substring(1, fieldPath[0].length - 1); // Strip the brackets
|
||||||
const targetFieldName = fieldPath[fieldPath.length - 1];
|
topLevelSub = true;
|
||||||
const filterValue = {
|
|
||||||
kind: getGraphQLKind(filter.value),
|
|
||||||
value: filter.value,
|
|
||||||
};
|
|
||||||
|
|
||||||
const nestedFilter = {
|
|
||||||
kind: Kind.OBJECT_FIELD,
|
|
||||||
name: {kind: Kind.NAME, value: targetFieldName},
|
|
||||||
value: {
|
|
||||||
kind: Kind.OBJECT,
|
|
||||||
fields: [{
|
|
||||||
kind: Kind.OBJECT_FIELD,
|
|
||||||
name: {kind: Kind.NAME, value: filter.operator},
|
|
||||||
value: filterValue,
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find or create the where argument for the top-level field
|
|
||||||
let whereArg = node.selectionSet.selections
|
|
||||||
.find(selection => selection.name.value === fieldPath[0])
|
|
||||||
?.arguments.find(arg => arg.name.value === 'where');
|
|
||||||
|
|
||||||
if (!whereArg) {
|
|
||||||
whereArg = {
|
|
||||||
kind: Kind.ARGUMENT,
|
|
||||||
name: {kind: Kind.NAME, value: 'where'},
|
|
||||||
value: {kind: Kind.OBJECT, fields: []},
|
|
||||||
};
|
|
||||||
const topLevelSelection = node.selectionSet.selections.find(selection =>
|
|
||||||
selection.name.value === fieldPath[0]
|
|
||||||
);
|
|
||||||
if (topLevelSelection) {
|
|
||||||
topLevelSelection.arguments = topLevelSelection.arguments || [];
|
|
||||||
topLevelSelection.arguments.push(whereArg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Correctly position the nested filter without an extra 'where'
|
|
||||||
if (fieldPath.length > 2) { // More than one level deep
|
|
||||||
let currentField = whereArg.value;
|
|
||||||
fieldPath.slice(1, -1).forEach((path, index) => {
|
|
||||||
let existingField = currentField.fields.find(f => f.name.value === path);
|
|
||||||
if (!existingField) {
|
|
||||||
existingField = {
|
|
||||||
kind: Kind.OBJECT_FIELD,
|
|
||||||
name: {kind: Kind.NAME, value: path},
|
|
||||||
value: {kind: Kind.OBJECT, fields: []}
|
|
||||||
};
|
|
||||||
currentField.fields.push(existingField);
|
|
||||||
}
|
|
||||||
currentField = existingField.value;
|
|
||||||
});
|
|
||||||
currentField.fields.push(nestedFilter);
|
|
||||||
} else { // Directly under the top level
|
|
||||||
whereArg.value.fields.push(nestedFilter);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Initialize a reference to the current selection to traverse down the AST
|
|
||||||
let currentSelection = node;
|
|
||||||
let whereArgFound = false;
|
|
||||||
|
|
||||||
// Iterate over the fieldPath, except for the last entry, to navigate the structure
|
|
||||||
for (let i = 0; i < fieldPath.length - 1; i++) {
|
|
||||||
const fieldName = fieldPath[i];
|
|
||||||
let fieldFound = false;
|
|
||||||
|
|
||||||
// Check if the current selection has a selectionSet and selections
|
|
||||||
if (currentSelection.selectionSet && currentSelection.selectionSet.selections) {
|
|
||||||
// Look for the field in the current selection's selections
|
|
||||||
const selection = currentSelection.selectionSet.selections.find(sel => sel.name.value === fieldName);
|
|
||||||
if (selection) {
|
|
||||||
// Move down the AST to the found selection
|
|
||||||
currentSelection = selection;
|
|
||||||
fieldFound = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the field was not found in the current path, it's an issue
|
|
||||||
if (!fieldFound) {
|
|
||||||
console.error(`Field ${fieldName} not found in the current selection.`);
|
|
||||||
return; // Exit the loop and function due to error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, currentSelection should be the parent field where the filter needs to be applied
|
|
||||||
// Check if the 'where' argument already exists in the current selection
|
|
||||||
const whereArg = currentSelection.arguments.find(arg => arg.name.value === 'where');
|
|
||||||
if (whereArg) {
|
|
||||||
whereArgFound = true;
|
|
||||||
} else {
|
|
||||||
// If not found, create a new 'where' argument for the current selection
|
|
||||||
currentSelection.arguments.push({
|
|
||||||
kind: Kind.ARGUMENT,
|
|
||||||
name: {kind: Kind.NAME, value: 'where'},
|
|
||||||
value: {kind: Kind.OBJECT, fields: []} // Empty fields array to be populated with the filter
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assuming the last entry in fieldPath is the field to apply the filter on
|
|
||||||
const targetField = fieldPath[fieldPath.length - 1];
|
|
||||||
const filterValue = {
|
|
||||||
kind: getGraphQLKind(filter.value),
|
|
||||||
value: filter.value,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Construct the filter field object
|
|
||||||
const filterField = {
|
|
||||||
kind: Kind.OBJECT_FIELD,
|
|
||||||
name: {kind: Kind.NAME, value: targetField},
|
|
||||||
value: {
|
|
||||||
kind: Kind.OBJECT,
|
|
||||||
fields: [{
|
|
||||||
kind: Kind.OBJECT_FIELD,
|
|
||||||
name: {kind: Kind.NAME, value: filter.operator},
|
|
||||||
value: filterValue,
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add the filter field to the 'where' clause of the current selection
|
|
||||||
if (whereArgFound) {
|
|
||||||
whereArg.value.fields.push(filterField);
|
|
||||||
} else {
|
|
||||||
// If the whereArg was newly created, find it again (since we didn't store its reference) and add the filter
|
|
||||||
currentSelection.arguments.find(arg => arg.name.value === 'where').value.fields.push(filterField);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Construct the filter for a top-level application
|
||||||
|
const targetFieldName = fieldPath[fieldPath.length - 1];
|
||||||
|
|
||||||
|
let filterValue = createFilterValue(filter);
|
||||||
|
let filterField = createFilterField(targetFieldName, filter, filterValue);
|
||||||
|
|
||||||
|
if (topLevel) {
|
||||||
|
applyTopLevelFilter(node, fieldPath, filterField);
|
||||||
|
} else if (topLevelSub) {
|
||||||
|
applyTopLevelSub(node, fieldPath, filterField);
|
||||||
|
} else {
|
||||||
|
applyNestedFilter(node, fieldPath, filterField);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a filter value based on the filter
|
||||||
|
* @param filter
|
||||||
|
* @returns {{kind: (Kind|Kind.INT), value}|{kind: Kind.LIST, values: *}}
|
||||||
|
*/
|
||||||
|
function createFilterValue(filter) {
|
||||||
|
if (Array.isArray(filter.value)) {
|
||||||
|
// If it's an array, create a list value with the array items
|
||||||
|
return {
|
||||||
|
kind: Kind.LIST,
|
||||||
|
values: filter.value.map(item => ({
|
||||||
|
kind: getGraphQLKind(item),
|
||||||
|
value: item,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// If it's not an array, use the existing logic
|
||||||
|
return {
|
||||||
|
kind: getGraphQLKind(filter.value),
|
||||||
|
value: filter.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a filter field based on the target field and filter
|
||||||
|
* @param targetFieldName
|
||||||
|
* @param filter
|
||||||
|
* @param filterValue
|
||||||
|
* @returns {{kind: Kind.OBJECT_FIELD, name: {kind: Kind.NAME, value}, value: {kind: Kind.OBJECT, fields: [{kind: Kind.OBJECT_FIELD, name: {kind: Kind.NAME, value}, value}]}}}
|
||||||
|
*/
|
||||||
|
function createFilterField(targetFieldName, filter, filterValue) {
|
||||||
|
return {
|
||||||
|
kind: Kind.OBJECT_FIELD,
|
||||||
|
name: {kind: Kind.NAME, value: targetFieldName},
|
||||||
|
value: {
|
||||||
|
kind: Kind.OBJECT,
|
||||||
|
fields: [{
|
||||||
|
kind: Kind.OBJECT_FIELD,
|
||||||
|
name: {kind: Kind.NAME, value: filter.operator},
|
||||||
|
value: filterValue,
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a top-level filter to the AST
|
||||||
|
* @param node
|
||||||
|
* @param fieldPath
|
||||||
|
* @param filterField
|
||||||
|
*/
|
||||||
|
function applyTopLevelFilter(node, fieldPath, filterField) {
|
||||||
|
// Find or create the where argument for the top-level field
|
||||||
|
let whereArg = node.selectionSet.selections
|
||||||
|
.find(selection => selection.name.value === fieldPath[0])
|
||||||
|
?.arguments.find(arg => arg.name.value === 'where');
|
||||||
|
|
||||||
|
if (!whereArg) {
|
||||||
|
whereArg = {
|
||||||
|
kind: Kind.ARGUMENT,
|
||||||
|
name: {kind: Kind.NAME, value: 'where'},
|
||||||
|
value: {kind: Kind.OBJECT, fields: []},
|
||||||
|
};
|
||||||
|
const topLevelSelection = node.selectionSet.selections.find(selection =>
|
||||||
|
selection.name.value === fieldPath[0]
|
||||||
|
);
|
||||||
|
if (topLevelSelection) {
|
||||||
|
topLevelSelection.arguments = topLevelSelection.arguments || [];
|
||||||
|
topLevelSelection.arguments.push(whereArg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correctly position the nested filter without an extra 'where'
|
||||||
|
if (fieldPath.length > 2) { // More than one level deep
|
||||||
|
let currentField = whereArg.value;
|
||||||
|
fieldPath.slice(1, -1).forEach((path, index) => {
|
||||||
|
let existingField = currentField.fields.find(f => f.name.value === path);
|
||||||
|
if (!existingField) {
|
||||||
|
existingField = {
|
||||||
|
kind: Kind.OBJECT_FIELD,
|
||||||
|
name: {kind: Kind.NAME, value: path},
|
||||||
|
value: {kind: Kind.OBJECT, fields: []}
|
||||||
|
};
|
||||||
|
currentField.fields.push(existingField);
|
||||||
|
}
|
||||||
|
currentField = existingField.value;
|
||||||
|
});
|
||||||
|
currentField.fields.push(filterField);
|
||||||
|
} else { // Directly under the top level
|
||||||
|
whereArg.value.fields.push(filterField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a nested filter to the AST
|
||||||
|
* @param node
|
||||||
|
* @param fieldPath
|
||||||
|
* @param filterField
|
||||||
|
*/
|
||||||
|
function applyNestedFilter(node, fieldPath, filterField) {
|
||||||
|
// Initialize a reference to the current selection to traverse down the AST
|
||||||
|
let currentSelection = node;
|
||||||
|
|
||||||
|
// Iterate over the fieldPath, except for the last entry, to navigate the structure
|
||||||
|
for (let i = 0; i < fieldPath.length - 1; i++) {
|
||||||
|
const fieldName = fieldPath[i];
|
||||||
|
let fieldFound = false;
|
||||||
|
|
||||||
|
// Check if the current selection has a selectionSet and selections
|
||||||
|
if (currentSelection.selectionSet && currentSelection.selectionSet.selections) {
|
||||||
|
// Look for the field in the current selection's selections
|
||||||
|
const selection = currentSelection.selectionSet.selections.find(sel => sel.name.value === fieldName);
|
||||||
|
if (selection) {
|
||||||
|
// Move down the AST to the found selection
|
||||||
|
currentSelection = selection;
|
||||||
|
fieldFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the field was not found in the current path, it's an issue
|
||||||
|
if (!fieldFound) {
|
||||||
|
console.error(`Field ${fieldName} not found in the current selection.`);
|
||||||
|
return; // Exit the loop and function due to error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, currentSelection should be the parent field where the filter needs to be applied
|
||||||
|
// Check if the 'where' argument already exists in the current selection
|
||||||
|
const whereArg = currentSelection.arguments.find(arg => arg.name.value === 'where');
|
||||||
|
if (!whereArg) {
|
||||||
|
// If not found, create a new 'where' argument for the current selection
|
||||||
|
currentSelection.arguments.push({
|
||||||
|
kind: Kind.ARGUMENT,
|
||||||
|
name: {kind: Kind.NAME, value: 'where'},
|
||||||
|
value: {kind: Kind.OBJECT, fields: []} // Empty fields array to be populated with the filter
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the filter field to the 'where' clause of the current selection
|
||||||
|
currentSelection.arguments.find(arg => arg.name.value === 'where').value.fields.push(filterField);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the GraphQL kind for a value
|
* Get the GraphQL kind for a value
|
||||||
* @param value
|
* @param value
|
||||||
* @returns {Kind|Kind.INT}
|
* @returns {Kind|Kind.INT}
|
||||||
*/
|
*/
|
||||||
function getGraphQLKind(value) {
|
function getGraphQLKind(value) {
|
||||||
if (typeof value === 'number') {
|
if (Array.isArray(value)) {
|
||||||
|
return Kind.LIST;
|
||||||
|
} else if (typeof value === 'number') {
|
||||||
return value % 1 === 0 ? Kind.INT : Kind.FLOAT;
|
return value % 1 === 0 ? Kind.INT : Kind.FLOAT;
|
||||||
} else if (typeof value === 'boolean') {
|
} else if (typeof value === 'boolean') {
|
||||||
return Kind.BOOLEAN;
|
return Kind.BOOLEAN;
|
||||||
} else if (typeof value === 'string') {
|
} else if (typeof value === 'string') {
|
||||||
return Kind.STRING;
|
return Kind.STRING;
|
||||||
|
} else if (value instanceof Date) {
|
||||||
|
return Kind.STRING; // GraphQL does not have a Date type, so we return it as a string
|
||||||
}
|
}
|
||||||
// Extend with more types as needed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* eslint-enable no-loop-func */
|
||||||
* Wrap filters in an 'and' object
|
|
||||||
* @param ast
|
|
||||||
* @param filterFields
|
|
||||||
*/
|
|
||||||
export function wrapFiltersInAnd(ast, filterFields) {
|
|
||||||
visit(ast, {
|
|
||||||
OperationDefinition: {
|
|
||||||
enter(node) {
|
|
||||||
node.selectionSet.selections.forEach((selection) => {
|
|
||||||
let whereArg = selection.arguments.find(arg => arg.name.value === 'where');
|
|
||||||
if (filterFields.length > 1) {
|
|
||||||
const andFilter = {
|
|
||||||
kind: Kind.OBJECT_FIELD,
|
|
||||||
name: {kind: Kind.NAME, value: '_and'},
|
|
||||||
value: {kind: Kind.LIST, values: filterFields}
|
|
||||||
};
|
|
||||||
whereArg.value.fields.push(andFilter);
|
|
||||||
} else if (filterFields.length === 1) {
|
|
||||||
whereArg.value.fields.push(filterFields[0].fields[0]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-enable no-loop-func */
|
|
||||||
|
|||||||
1878
package-lock.json
generated
1878
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@@ -18,49 +18,51 @@
|
|||||||
"start": "node server.js"
|
"start": "node server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-secrets-manager": "^3.515.0",
|
"@aws-sdk/client-secrets-manager": "^3.525.0",
|
||||||
"@aws-sdk/client-ses": "^3.515.0",
|
"@aws-sdk/client-ses": "^3.525.0",
|
||||||
"@aws-sdk/credential-provider-node": "^3.515.0",
|
"@aws-sdk/credential-provider-node": "^3.525.0",
|
||||||
|
"@azure/storage-blob": "^12.17.0",
|
||||||
"@opensearch-project/opensearch": "^2.5.0",
|
"@opensearch-project/opensearch": "^2.5.0",
|
||||||
"aws4": "^1.12.0",
|
"aws4": "^1.12.0",
|
||||||
"axios": "^1.6.5",
|
"axios": "^1.6.5",
|
||||||
"bluebird": "^3.7.2",
|
"bluebird": "^3.7.2",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"cloudinary": "^2.0.1",
|
"cloudinary": "^2.0.2",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"csrf": "^3.1.0",
|
"csrf": "^3.1.0",
|
||||||
"dinero.js": "^1.9.1",
|
"dinero.js": "^1.9.1",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.3",
|
||||||
"firebase-admin": "^12.0.0",
|
"firebase-admin": "^12.0.0",
|
||||||
"graphql": "^16.8.1",
|
"graphql": "^16.8.1",
|
||||||
"graphql-request": "^6.1.0",
|
"graphql-request": "^6.1.0",
|
||||||
"graylog2": "^0.2.1",
|
"graylog2": "^0.2.1",
|
||||||
"inline-css": "^4.0.2",
|
"inline-css": "^4.0.2",
|
||||||
"intuit-oauth": "^4.0.0",
|
"intuit-oauth": "^4.0.0",
|
||||||
"json-2-csv": "^5.2.0",
|
"json-2-csv": "^5.5.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"moment-timezone": "^0.5.45",
|
"moment-timezone": "^0.5.45",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"node-mailjet": "^6.0.5",
|
"node-mailjet": "^6.0.5",
|
||||||
"node-persist": "^4.0.1",
|
"node-persist": "^4.0.1",
|
||||||
"node-quickbooks": "^2.0.43",
|
"node-quickbooks": "^2.0.44",
|
||||||
"nodemailer": "^6.9.10",
|
"nodemailer": "^6.9.11",
|
||||||
"phone": "^3.1.42",
|
"phone": "^3.1.42",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"soap": "^1.0.0",
|
"soap": "^1.0.0",
|
||||||
"socket.io": "^4.7.4",
|
"socket.io": "^4.7.4",
|
||||||
"ssh2-sftp-client": "^10.0.3",
|
"ssh2-sftp-client": "^10.0.3",
|
||||||
"stripe": "^14.18.0",
|
"stripe": "^14.19.0",
|
||||||
"twilio": "^4.22.0",
|
"twilio": "^4.23.0",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"xml2js": "^0.6.2",
|
"xml2js": "^0.6.2",
|
||||||
"xmlbuilder2": "^3.1.1"
|
"xmlbuilder2": "^3.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"source-map-explorer": "^2.5.2"
|
"source-map-explorer": "^2.5.2"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user