Merge branch 'feature/IO-1828-Front-End-Package-Updates' into master-AIO
This commit is contained in:
175
_reference/reportFiltersAndSorters.md
Normal file
175
_reference/reportFiltersAndSorters.md
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
# Filters and Sorters
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
## High level Schema Overview
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const schema = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "jobs.joblines.mod_lb_hrs", // Name and path of the field in the graphQL query
|
||||||
|
"translation": "jobs.joblines.mod_lb_hrs_1", // Translation key for the label used in the GUI
|
||||||
|
"label": "mod_lb_hrs_1", // Label used in the case the GUI does not contain a translation
|
||||||
|
"type": "number" // Type of field, can be number or string currently
|
||||||
|
},
|
||||||
|
// ... more filters
|
||||||
|
],
|
||||||
|
"sorters": [
|
||||||
|
{
|
||||||
|
"name": "jobs.joblines.mod_lb_hrs", // Name and path of the field in the graphQL query
|
||||||
|
"translation": "jobs.joblines.mod_lb_hrs_1", // Translation key for the label used in the GUI
|
||||||
|
"label": "mod_lb_hrs_1", // Label used in the case the GUI does not contain a translation
|
||||||
|
"type": "number" // Type of field, can be number or string currently
|
||||||
|
},
|
||||||
|
// ... more sorters
|
||||||
|
],
|
||||||
|
"dates": {
|
||||||
|
// This is not yet implemented and will be added in a future release
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Filters
|
||||||
|
|
||||||
|
Filters effect the where clause of the graphQL query. They are used to filter the data returned from the server.
|
||||||
|
A note on special notation used in the `name` field.
|
||||||
|
|
||||||
|
## Reflection
|
||||||
|
Filters can make use of reflection to pre-fill select boxes, the following is an example of that in the filters file.
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"name": "jobs.status",
|
||||||
|
"translation": "jobs.fields.status",
|
||||||
|
"label": "Status",
|
||||||
|
"type": "string",
|
||||||
|
"reflector": {
|
||||||
|
"type": "internal",
|
||||||
|
"name": "special.job_statuses"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
in this example, a reflector with the type 'internal' (all types at the moment require this, and it is used for future functionality), with a name of `special.job_statuses`
|
||||||
|
|
||||||
|
The following cases are available
|
||||||
|
|
||||||
|
- `special.job_statuses` - This will reflect the statuses of the jobs table `bodyshop.md_ro_statuses.statuses'`
|
||||||
|
- `special.cost_centers` - This will reflect the cost centers `bodyshop.md_responsibility_centers.costs`
|
||||||
|
- `special.categories` - This will reflect the categories `bodyshop.md_categories`
|
||||||
|
- `special.insurance_companies` - This will reflect the insurance companies `bodyshop.md_ins_cos`'
|
||||||
|
- `special.employee_teams` - This will reflect the employee teams `bodyshop.employee_teams`
|
||||||
|
- `special.employees` - This will reflect the employees `bodyshop.employees`
|
||||||
|
- `special.first_names` - This will reflect the first names `bodyshop.employees`
|
||||||
|
- `special.last_names` - This will reflect the last names `bodyshop.employees`
|
||||||
|
-
|
||||||
|
### Path without brackets, multi level
|
||||||
|
|
||||||
|
`"name": "jobs.joblines.mod_lb_hrs",`
|
||||||
|
This will produce a where clause at the `joblines` level of the graphQL query,
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz!) {
|
||||||
|
jobs(
|
||||||
|
where: {date_invoiced: {_is_null: true}, date_open: {_gte: $starttz, _lte: $endtz}, ro_number: {_is_null: false}, voided: {_eq: false}}
|
||||||
|
) {
|
||||||
|
joblines(
|
||||||
|
order_by: {line_no: asc}
|
||||||
|
where: {removed: {_eq: false}, mod_lb_hrs: {_lt: 3}}
|
||||||
|
) {
|
||||||
|
line_no
|
||||||
|
mod_lbr_ty
|
||||||
|
mod_lb_hrs
|
||||||
|
convertedtolbr
|
||||||
|
convertedtolbr_data
|
||||||
|
}
|
||||||
|
ownr_co_nm
|
||||||
|
ownr_fn
|
||||||
|
ownr_ln
|
||||||
|
plate_no
|
||||||
|
ro_number
|
||||||
|
status
|
||||||
|
v_make_desc
|
||||||
|
v_model_desc
|
||||||
|
v_model_yr
|
||||||
|
v_vin
|
||||||
|
v_color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Path with brackets,top level
|
||||||
|
|
||||||
|
`"name": "[jobs].joblines.mod_lb_hrs",`
|
||||||
|
This will produce a where clause at the `jobs` level of the graphQL query.
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz!) {
|
||||||
|
jobs(
|
||||||
|
where: {date_invoiced: {_is_null: true}, date_open: {_gte: $starttz, _lte: $endtz}, ro_number: {_is_null: false}, voided: {_eq: false}, joblines: {mod_lb_hrs: {_gt: 4}}}
|
||||||
|
) {
|
||||||
|
joblines(
|
||||||
|
order_by: {line_no: asc}
|
||||||
|
where: {removed: {_eq: false}}
|
||||||
|
) {
|
||||||
|
line_no
|
||||||
|
mod_lbr_ty
|
||||||
|
mod_lb_hrs
|
||||||
|
convertedtolbr
|
||||||
|
convertedtolbr_data
|
||||||
|
}
|
||||||
|
ownr_co_nm
|
||||||
|
ownr_fn
|
||||||
|
ownr_ln
|
||||||
|
plate_no
|
||||||
|
ro_number
|
||||||
|
status
|
||||||
|
v_make_desc
|
||||||
|
v_model_desc
|
||||||
|
v_model_yr
|
||||||
|
v_vin
|
||||||
|
v_color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Known Caveats
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
- The `dates` object is not yet implemented and will be added in a future release.
|
||||||
|
- 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.
|
||||||
|
- 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.
|
||||||
|
- Do not add the ability to filter on things like FK constraints, must like the above example.
|
||||||
|
|
||||||
|
## Sorters
|
||||||
|
|
||||||
|
- Sorters follow the same schema as filters, however, they do not do square bracket wrapping to indicate level hoisting,
|
||||||
|
a filter added on `job.md_status` would be added at the top level, and a filter added on `jobs.joblines.mod_lb_hrs`
|
||||||
|
would be added at the `joblines` level.
|
||||||
|
- Most of the reports currently do sorting on a template level, this will need to change to actually see the results
|
||||||
|
using the 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.
|
||||||
|
- 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`.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "jobs.joblines.mod_lb_hrs",
|
||||||
|
"translation": "jobs.joblines.mod_lb_hrs_1",
|
||||||
|
"label": "mod_lb_hrs_1",
|
||||||
|
"type": "number",
|
||||||
|
"default": {
|
||||||
|
"order": 1,
|
||||||
|
"direction": "asc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
725
client/package-lock.json
generated
725
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,13 +11,13 @@
|
|||||||
"@craco/craco": "^7.1.0",
|
"@craco/craco": "^7.1.0",
|
||||||
"@fingerprintjs/fingerprintjs": "^4.2.2",
|
"@fingerprintjs/fingerprintjs": "^4.2.2",
|
||||||
"@jsreport/browser-client": "^3.1.0",
|
"@jsreport/browser-client": "^3.1.0",
|
||||||
"@reduxjs/toolkit": "^2.1.0",
|
"@reduxjs/toolkit": "^2.2.1",
|
||||||
"@sentry/cli": "^2.28.0",
|
"@sentry/cli": "^2.28.6",
|
||||||
"@sentry/react": "^7.100.0",
|
"@sentry/react": "^7.102.1",
|
||||||
"@sentry/tracing": "^7.100.0",
|
"@sentry/tracing": "^7.102.1",
|
||||||
"@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.0",
|
"antd": "^5.14.2",
|
||||||
"apollo-link-logger": "^2.0.1",
|
"apollo-link-logger": "^2.0.1",
|
||||||
"apollo-link-sentry": "^3.3.0",
|
"apollo-link-sentry": "^3.3.0",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
@@ -25,18 +25,18 @@
|
|||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"dayjs-business-days2": "^1.2.2",
|
"dayjs-business-days2": "^1.2.2",
|
||||||
"dinero.js": "^1.9.1",
|
"dinero.js": "^1.9.1",
|
||||||
"dotenv": "^16.4.1",
|
"dotenv": "^16.4.5",
|
||||||
"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.0",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
"i18next": "^23.8.2",
|
"i18next": "^23.10.0",
|
||||||
"i18next-browser-languagedetector": "^7.0.2",
|
"i18next-browser-languagedetector": "^7.0.2",
|
||||||
"jsoneditor": "^10.0.0",
|
"jsoneditor": "^10.0.1",
|
||||||
"jsreport-browser-client-dist": "^1.3.0",
|
"jsreport-browser-client-dist": "^1.3.0",
|
||||||
"libphonenumber-js": "^1.10.55",
|
"libphonenumber-js": "^1.10.57",
|
||||||
"logrocket": "^7.0.0",
|
"logrocket": "^8.0.1",
|
||||||
"markerjs2": "^2.32.0",
|
"markerjs2": "^2.32.0",
|
||||||
"normalize-url": "^8.0.0",
|
"normalize-url": "^8.0.0",
|
||||||
"phone": "^3.1.42",
|
"phone": "^3.1.42",
|
||||||
@@ -46,33 +46,33 @@
|
|||||||
"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.8.7",
|
"react-big-calendar": "^1.10.3",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
"react-cookie": "^7.0.2",
|
"react-cookie": "^7.1.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-drag-listview": "^2.0.0",
|
"react-drag-listview": "^2.0.0",
|
||||||
"react-grid-gallery": "^1.0.0",
|
"react-grid-gallery": "^1.0.0",
|
||||||
"react-grid-layout": "1.3.4",
|
"react-grid-layout": "1.3.4",
|
||||||
"react-i18next": "^14.0.4",
|
"react-i18next": "^14.0.5",
|
||||||
"react-icons": "^5.0.1",
|
"react-icons": "^5.0.1",
|
||||||
"react-image-lightbox": "^5.1.4",
|
"react-image-lightbox": "^5.1.4",
|
||||||
"react-intersection-observer": "^9.7.0",
|
"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.1.4",
|
||||||
"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.0",
|
"react-router-dom": "^6.22.1",
|
||||||
"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.11.0",
|
"recharts": "^2.12.1",
|
||||||
"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",
|
||||||
"redux-state-sync": "^3.1.4",
|
"redux-state-sync": "^3.1.4",
|
||||||
"reselect": "^5.1.0",
|
"reselect": "^5.1.0",
|
||||||
"sass": "^1.70.0",
|
"sass": "^1.71.1",
|
||||||
"socket.io-client": "^4.7.4",
|
"socket.io-client": "^4.7.4",
|
||||||
"styled-components": "^6.1.8",
|
"styled-components": "^6.1.8",
|
||||||
"subscriptions-transport-ws": "^0.11.0",
|
"subscriptions-transport-ws": "^0.11.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": "^2.10.0"
|
"yauzl": "^3.1.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
||||||
@@ -130,9 +130,9 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||||
"@dotenvx/dotenvx": "^0.15.0",
|
"@dotenvx/dotenvx": "^0.15.0",
|
||||||
"@sentry/webpack-plugin": "^2.14.0",
|
"@sentry/webpack-plugin": "^2.14.2",
|
||||||
"@testing-library/cypress": "^10.0.1",
|
"@testing-library/cypress": "^10.0.1",
|
||||||
"cypress": "^13.6.4",
|
"cypress": "^13.6.6",
|
||||||
"eslint-plugin-cypress": "^2.15.1",
|
"eslint-plugin-cypress": "^2.15.1",
|
||||||
"react-error-overlay": "6.0.11",
|
"react-error-overlay": "6.0.11",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
|
|||||||
@@ -66,7 +66,30 @@ export default function ContractFormComponent({
|
|||||||
<FormDateTimePicker/>
|
<FormDateTimePicker/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
</LayoutFormRow>
|
{create && (
|
||||||
|
<Form.Item
|
||||||
|
shouldUpdate={(p, c) => p.scheduledreturn !== c.scheduledreturn}
|
||||||
|
>
|
||||||
|
{() => {
|
||||||
|
const insuranceOver =
|
||||||
|
selectedCar &&
|
||||||
|
selectedCar.insuranceexpires &&
|
||||||
|
dayjs(selectedCar.insuranceexpires)
|
||||||
|
.endOf("day")
|
||||||
|
.isBefore(dayjs(form.getFieldValue("scheduledreturn")));
|
||||||
|
if (insuranceOver)
|
||||||
|
return (
|
||||||
|
<Space direction="vertical" style={{color: "tomato"}}>
|
||||||
|
<span>
|
||||||
|
<WarningFilled style={{marginRight: ".3rem"}}/>
|
||||||
|
{t("contracts.labels.insuranceexpired")}
|
||||||
|
</span>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
return <></>;
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
)}</LayoutFormRow>
|
||||||
<LayoutFormRow grow>
|
<LayoutFormRow grow>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("contracts.fields.kmstart")}
|
label={t("contracts.fields.kmstart")}
|
||||||
@@ -88,16 +111,17 @@ export default function ContractFormComponent({
|
|||||||
>
|
>
|
||||||
{() => {
|
{() => {
|
||||||
const mileageOver =
|
const mileageOver =
|
||||||
selectedCar &&
|
selectedCar && selectedCar.nextservicekm
|
||||||
selectedCar.nextservicekm <= form.getFieldValue("kmstart");
|
? selectedCar.nextservicekm <= form.getFieldValue("kmstart")
|
||||||
|
: false;
|
||||||
const dueForService =
|
const dueForService =
|
||||||
selectedCar &&
|
selectedCar &&
|
||||||
selectedCar.nextservicedate &&
|
selectedCar.nextservicedate &&
|
||||||
dayjs(selectedCar.nextservicedate).isBefore(
|
dayjs(selectedCar.nextservicedate)
|
||||||
|
.endOf("day")
|
||||||
|
.isSameOrBefore(
|
||||||
dayjs(form.getFieldValue("scheduledreturn"))
|
dayjs(form.getFieldValue("scheduledreturn"))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (mileageOver || dueForService)
|
if (mileageOver || dueForService)
|
||||||
return (
|
return (
|
||||||
<Space direction="vertical" style={{color: "tomato"}}>
|
<Space direction="vertical" style={{color: "tomato"}}>
|
||||||
|
|||||||
@@ -64,18 +64,29 @@ 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} = record;
|
const {nextservicedate, nextservicekm, mileage, insuranceexpires} =
|
||||||
|
record;
|
||||||
|
|
||||||
const mileageOver = nextservicekm ? nextservicekm <= mileage : false;
|
const mileageOver = nextservicekm ? nextservicekm <= mileage : false;
|
||||||
|
|
||||||
const dueForService =
|
const dueForService =
|
||||||
nextservicedate && dayjs(nextservicedate).endOf('day').isSameOrBefore(dayjs());
|
nextservicedate && dayjs(nextservicedate).endOf('day').isSameOrBefore(dayjs());
|
||||||
|
|
||||||
|
const insuranceOver =
|
||||||
|
insuranceexpires &&
|
||||||
|
dayjs(insuranceexpires).endOf("day").isBefore(dayjs());
|
||||||
return (
|
return (
|
||||||
<Space>
|
<Space>
|
||||||
{t(record.status)}
|
{t(record.status)}
|
||||||
{(mileageOver || dueForService) && (
|
{(mileageOver || dueForService || insuranceOver) && (
|
||||||
<Tooltip title={t("contracts.labels.cardueforservice")}>
|
<Tooltip title={(mileageOver || dueForService) && insuranceOver
|
||||||
|
? t("contracts.labels.insuranceexpired") +
|
||||||
|
" / " +
|
||||||
|
t("contracts.labels.cardueforservice")
|
||||||
|
: insuranceOver
|
||||||
|
? t("contracts.labels.insuranceexpired")
|
||||||
|
: t("contracts.labels.cardueforservice")
|
||||||
|
}>
|
||||||
<WarningFilled style={{color: "tomato"}}/>
|
<WarningFilled style={{color: "tomato"}}/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,221 +1,469 @@
|
|||||||
import {BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined,} from "@ant-design/icons";
|
import {
|
||||||
import {Card, Space, Table, Tooltip} from "antd";
|
BranchesOutlined,
|
||||||
import dayjs from "../../../utils/day";
|
ExclamationCircleFilled,
|
||||||
import React, {useState} from "react";
|
PauseCircleOutlined,
|
||||||
import {useTranslation} from "react-i18next";
|
} from "@ant-design/icons";
|
||||||
import {Link} from "react-router-dom";
|
import { Card, Space, Switch, Table, Tooltip, Typography } from "antd";
|
||||||
|
import moment from "moment";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { TimeFormatter } from "../../../utils/DateFormatter";
|
||||||
|
import { onlyUnique } from "../../../utils/arrayHelper";
|
||||||
|
import { alphaSort, dateSort } from "../../../utils/sorters";
|
||||||
|
import useLocalStorage from "../../../utils/useLocalStorage";
|
||||||
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
||||||
import OwnerNameDisplay from "../../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay, {
|
||||||
|
OwnerNameDisplayFunction,
|
||||||
|
} from "../../owner-name-display/owner-name-display.component";
|
||||||
import DashboardRefreshRequired from "../refresh-required.component";
|
import DashboardRefreshRequired from "../refresh-required.component";
|
||||||
import {pageLimit} from "../../../utils/config";
|
|
||||||
|
|
||||||
export default function DashboardScheduledInToday({data, ...cardProps}) {
|
export default function DashboardScheduledInToday({ data, ...cardProps }) {
|
||||||
const {t} = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
});
|
filteredInfo: {},
|
||||||
if (!data) return null;
|
});
|
||||||
if (!data.scheduled_in_today)
|
|
||||||
return <DashboardRefreshRequired {...cardProps} />;
|
|
||||||
|
|
||||||
const appt = []; // Flatten Data
|
const [isTvModeScheduledIn, setIsTvModeScheduledIn] = useLocalStorage(
|
||||||
data.scheduled_in_today.forEach((item) => {
|
"isTvModeScheduledIn",
|
||||||
if (item.job) {
|
false
|
||||||
var i = {
|
);
|
||||||
canceled: item.canceled,
|
|
||||||
id: item.id,
|
|
||||||
alt_transport: item.job.alt_transport,
|
|
||||||
clm_no: item.job.clm_no,
|
|
||||||
jobid: item.job.jobid,
|
|
||||||
ins_co_nm: item.job.ins_co_nm,
|
|
||||||
iouparent: item.job.iouparent,
|
|
||||||
ownerid: item.job.ownerid,
|
|
||||||
ownr_co_nm: item.job.ownr_co_nm,
|
|
||||||
ownr_ea: item.job.ownr_ea,
|
|
||||||
ownr_fn: item.job.ownr_fn,
|
|
||||||
ownr_ln: item.job.ownr_ln,
|
|
||||||
ownr_ph1: item.job.ownr_ph1,
|
|
||||||
ownr_ph2: item.job.ownr_ph2,
|
|
||||||
production_vars: item.job.production_vars,
|
|
||||||
ro_number: item.job.ro_number,
|
|
||||||
suspended: item.job.suspended,
|
|
||||||
v_make_desc: item.job.v_make_desc,
|
|
||||||
v_model_desc: item.job.v_model_desc,
|
|
||||||
v_model_yr: item.job.v_model_yr,
|
|
||||||
v_vin: item.job.v_vin,
|
|
||||||
vehicleid: item.job.vehicleid,
|
|
||||||
note: item.note,
|
|
||||||
start: dayjs(item.start).format("hh:mm a"),
|
|
||||||
title: item.title,
|
|
||||||
};
|
|
||||||
appt.push(i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
appt.sort(function (a, b) {
|
|
||||||
return new dayjs(a.start) - new dayjs(b.start);
|
|
||||||
});
|
|
||||||
|
|
||||||
const columns = [
|
if (!data) return null;
|
||||||
{
|
if (!data.scheduled_in_today)
|
||||||
title: t("jobs.fields.ro_number"),
|
return <DashboardRefreshRequired {...cardProps} />;
|
||||||
dataIndex: "ro_number",
|
|
||||||
key: "ro_number",
|
|
||||||
render: (text, record) => (
|
|
||||||
<Link
|
|
||||||
to={"/manage/jobs/" + record.jobid}
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
<Space>
|
|
||||||
{record.ro_number || t("general.labels.na")}
|
|
||||||
{record.production_vars && record.production_vars.alert ? (
|
|
||||||
<ExclamationCircleFilled className="production-alert"/>
|
|
||||||
) : null}
|
|
||||||
{record.suspended && (
|
|
||||||
<PauseCircleOutlined style={{color: "orangered"}}/>
|
|
||||||
)}
|
|
||||||
{record.iouparent && (
|
|
||||||
<Tooltip title={t("jobs.labels.iou")}>
|
|
||||||
<BranchesOutlined style={{color: "orangered"}}/>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</Space>
|
|
||||||
</Link>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("jobs.fields.owner"),
|
|
||||||
dataIndex: "owner",
|
|
||||||
key: "owner",
|
|
||||||
ellipsis: true,
|
|
||||||
responsive: ["md"],
|
|
||||||
render: (text, record) => {
|
|
||||||
return record.ownerid ? (
|
|
||||||
<Link
|
|
||||||
to={"/manage/owners/" + record.ownerid}
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
<OwnerNameDisplay ownerObject={record}/>
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<span>
|
|
||||||
<OwnerNameDisplay ownerObject={record}/>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("jobs.fields.ownr_ph1"),
|
|
||||||
dataIndex: "ownr_ph1",
|
|
||||||
key: "ownr_ph1",
|
|
||||||
ellipsis: true,
|
|
||||||
responsive: ["md"],
|
|
||||||
render: (text, record) => (
|
|
||||||
<ChatOpenButton phone={record.ownr_ph1} jobid={record.jobid}/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("jobs.fields.ownr_ph2"),
|
|
||||||
dataIndex: "ownr_ph2",
|
|
||||||
key: "ownr_ph2",
|
|
||||||
ellipsis: true,
|
|
||||||
responsive: ["md"],
|
|
||||||
render: (text, record) => (
|
|
||||||
<ChatOpenButton phone={record.ownr_ph2} jobid={record.jobid}/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("jobs.fields.ownr_ea"),
|
|
||||||
dataIndex: "ownr_ea",
|
|
||||||
key: "ownr_ea",
|
|
||||||
ellipsis: true,
|
|
||||||
responsive: ["md"],
|
|
||||||
render: (text, record) => (
|
|
||||||
<ChatOpenButton phone={record.ownr_ea} jobid={record.jobid}/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("jobs.fields.vehicle"),
|
|
||||||
dataIndex: "vehicle",
|
|
||||||
key: "vehicle",
|
|
||||||
ellipsis: true,
|
|
||||||
render: (text, record) => {
|
|
||||||
return record.vehicleid ? (
|
|
||||||
<Link
|
|
||||||
to={"/manage/vehicles/" + record.vehicleid}
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
|
||||||
record.v_model_desc || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
|
||||||
record.v_model_desc || ""
|
|
||||||
}`}</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("jobs.fields.ins_co_nm"),
|
|
||||||
dataIndex: "ins_co_nm",
|
|
||||||
key: "ins_co_nm",
|
|
||||||
ellipsis: true,
|
|
||||||
responsive: ["md"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("appointments.fields.time"),
|
|
||||||
dataIndex: "start",
|
|
||||||
key: "start",
|
|
||||||
ellipsis: true,
|
|
||||||
responsive: ["md"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("appointments.fields.alt_transport"),
|
|
||||||
dataIndex: "alt_transport",
|
|
||||||
key: "alt_transport",
|
|
||||||
ellipsis: true,
|
|
||||||
responsive: ["md"],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const handleTableChange = (sorter) => {
|
const appt = []; // Flatten Data
|
||||||
setState({...state, sortedInfo: sorter});
|
data.scheduled_in_today.forEach((item) => {
|
||||||
};
|
if (item.job) {
|
||||||
|
var i = {
|
||||||
|
canceled: item.canceled,
|
||||||
|
id: item.id,
|
||||||
|
alt_transport: item.job.alt_transport,
|
||||||
|
clm_no: item.job.clm_no,
|
||||||
|
jobid: item.job.jobid,
|
||||||
|
joblines_body: item.job.joblines
|
||||||
|
.filter((l) => l.mod_lbr_ty !== "LAR")
|
||||||
|
.reduce((acc, val) => acc + val.mod_lb_hrs, 0),
|
||||||
|
joblines_ref: item.job.joblines
|
||||||
|
.filter((l) => l.mod_lbr_ty === "LAR")
|
||||||
|
.reduce((acc, val) => acc + val.mod_lb_hrs, 0),
|
||||||
|
ins_co_nm: item.job.ins_co_nm,
|
||||||
|
iouparent: item.job.iouparent,
|
||||||
|
ownerid: item.job.ownerid,
|
||||||
|
ownr_co_nm: item.job.ownr_co_nm,
|
||||||
|
ownr_ea: item.job.ownr_ea,
|
||||||
|
ownr_fn: item.job.ownr_fn,
|
||||||
|
ownr_ln: item.job.ownr_ln,
|
||||||
|
ownr_ph1: item.job.ownr_ph1,
|
||||||
|
ownr_ph2: item.job.ownr_ph2,
|
||||||
|
production_vars: item.job.production_vars,
|
||||||
|
ro_number: item.job.ro_number,
|
||||||
|
suspended: item.job.suspended,
|
||||||
|
v_make_desc: item.job.v_make_desc,
|
||||||
|
v_model_desc: item.job.v_model_desc,
|
||||||
|
v_model_yr: item.job.v_model_yr,
|
||||||
|
v_vin: item.job.v_vin,
|
||||||
|
vehicleid: item.job.vehicleid,
|
||||||
|
note: item.note,
|
||||||
|
start: item.start,
|
||||||
|
title: item.title,
|
||||||
|
};
|
||||||
|
appt.push(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
appt.sort(function (a, b) {
|
||||||
|
return new moment(a.start) - new moment(b.start);
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
const tvFontSize = 16;
|
||||||
<Card
|
const tvFontWeight = "bold";
|
||||||
title={t("dashboard.titles.scheduledintoday", {
|
|
||||||
date: dayjs().startOf("day").format("MM/DD/YYYY"),
|
const tvColumns = [
|
||||||
})}
|
{
|
||||||
{...cardProps}
|
title: t("appointments.fields.time"),
|
||||||
|
dataIndex: "start",
|
||||||
|
key: "start",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => dateSort(a.start, b.start),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "start" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
<TimeFormatter>{record.start}</TimeFormatter>
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ro_number"),
|
||||||
|
dataIndex: "ro_number",
|
||||||
|
key: "ro_number",
|
||||||
|
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<Link
|
||||||
|
to={"/manage/jobs/" + record.jobid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<div style={{height: "100%"}}>
|
<Space>
|
||||||
<Table
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
onChange={handleTableChange}
|
{record.ro_number || t("general.labels.na")}
|
||||||
pagination={{position: "top", defaultPageSize: pageLimit}}
|
{record.production_vars && record.production_vars.alert ? (
|
||||||
columns={columns}
|
<ExclamationCircleFilled className="production-alert" />
|
||||||
scroll={{x: true, y: "calc(100% - 2em)"}}
|
) : null}
|
||||||
rowKey="id"
|
{record.suspended && (
|
||||||
style={{height: "85%"}}
|
<PauseCircleOutlined style={{ color: "orangered" }} />
|
||||||
dataSource={appt}
|
)}
|
||||||
/>
|
{record.iouparent && (
|
||||||
</div>
|
<Tooltip title={t("jobs.labels.iou")}>
|
||||||
</Card>
|
<BranchesOutlined style={{ color: "orangered" }} />
|
||||||
);
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</Space>
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.owner"),
|
||||||
|
dataIndex: "owner",
|
||||||
|
key: "owner",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.ownerid ? (
|
||||||
|
<Link
|
||||||
|
to={"/manage/owners/" + record.ownerid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.vehicle"),
|
||||||
|
dataIndex: "vehicle",
|
||||||
|
key: "vehicle",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
alphaSort(
|
||||||
|
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${
|
||||||
|
a.v_model_desc || ""
|
||||||
|
}`,
|
||||||
|
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
|
||||||
|
),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.vehicleid ? (
|
||||||
|
<Link
|
||||||
|
to={"/manage/vehicles/" + record.vehicleid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||||
|
record.v_model_desc || ""
|
||||||
|
}`}
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>{`${
|
||||||
|
record.v_model_yr || ""
|
||||||
|
} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`}</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("appointments.fields.alt_transport"),
|
||||||
|
dataIndex: "alt_transport",
|
||||||
|
key: "alt_transport",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => alphaSort(a.alt_transport, b.alt_transport),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "alt_transport" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
(appt &&
|
||||||
|
appt
|
||||||
|
.map((j) => j.alt_transport)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || "No Alt. Transport",
|
||||||
|
value: [s],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.alt_transport),
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
{record.alt_transport}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.lab"),
|
||||||
|
dataIndex: "joblines_body",
|
||||||
|
key: "joblines_body",
|
||||||
|
sorter: (a, b) => a.joblines_body - b.joblines_body,
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "joblines_body" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
align: "right",
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
{record.joblines_body.toFixed(1)}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.lar"),
|
||||||
|
dataIndex: "joblines_ref",
|
||||||
|
key: "joblines_ref",
|
||||||
|
sorter: (a, b) => a.joblines_ref - b.joblines_ref,
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "joblines_ref" && state.sortedInfo.order,
|
||||||
|
align: "right",
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
{record.joblines_ref.toFixed(1)}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: t("appointments.fields.time"),
|
||||||
|
dataIndex: "start",
|
||||||
|
key: "start",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => dateSort(a.start, b.start),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "start" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => <TimeFormatter>{record.start}</TimeFormatter>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ro_number"),
|
||||||
|
dataIndex: "ro_number",
|
||||||
|
key: "ro_number",
|
||||||
|
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<Link
|
||||||
|
to={"/manage/jobs/" + record.jobid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<Space>
|
||||||
|
{record.ro_number || t("general.labels.na")}
|
||||||
|
{record.production_vars && record.production_vars.alert ? (
|
||||||
|
<ExclamationCircleFilled className="production-alert" />
|
||||||
|
) : null}
|
||||||
|
{record.suspended && (
|
||||||
|
<PauseCircleOutlined style={{ color: "orangered" }} />
|
||||||
|
)}
|
||||||
|
{record.iouparent && (
|
||||||
|
<Tooltip title={t("jobs.labels.iou")}>
|
||||||
|
<BranchesOutlined style={{ color: "orangered" }} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.owner"),
|
||||||
|
dataIndex: "owner",
|
||||||
|
key: "owner",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.ownerid ? (
|
||||||
|
<Link
|
||||||
|
to={"/manage/owners/" + record.ownerid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("dashboard.labels.phone"),
|
||||||
|
dataIndex: "ownr_ph",
|
||||||
|
key: "ownr_ph",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => (
|
||||||
|
<Space size="small" wrap>
|
||||||
|
<ChatOpenButton phone={record.ownr_ph1} jobid={record.jobid} />
|
||||||
|
<ChatOpenButton phone={record.ownr_ph2} jobid={record.jobid} />
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ownr_ea"),
|
||||||
|
dataIndex: "ownr_ea",
|
||||||
|
key: "ownr_ea",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => (
|
||||||
|
<a href={`mailto:${record.ownr_ea}`}>{record.ownr_ea}</a>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.vehicle"),
|
||||||
|
dataIndex: "vehicle",
|
||||||
|
key: "vehicle",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
alphaSort(
|
||||||
|
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${
|
||||||
|
a.v_model_desc || ""
|
||||||
|
}`,
|
||||||
|
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
|
||||||
|
),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.vehicleid ? (
|
||||||
|
<Link
|
||||||
|
to={"/manage/vehicles/" + record.vehicleid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||||
|
record.v_model_desc || ""
|
||||||
|
}`}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||||
|
record.v_model_desc || ""
|
||||||
|
}`}</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ins_co_nm"),
|
||||||
|
dataIndex: "ins_co_nm",
|
||||||
|
key: "ins_co_nm",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
(appt &&
|
||||||
|
appt
|
||||||
|
.map((j) => j.ins_co_nm)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || "No Ins. Co.*",
|
||||||
|
value: [s],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.ins_co_nm),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("appointments.fields.alt_transport"),
|
||||||
|
dataIndex: "alt_transport",
|
||||||
|
key: "alt_transport",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => alphaSort(a.alt_transport, b.alt_transport),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "alt_transport" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
(appt &&
|
||||||
|
appt
|
||||||
|
.map((j) => j.alt_transport)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || "No Alt. Transport",
|
||||||
|
value: [s],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.alt_transport),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
title={t("dashboard.titles.scheduledindate", {
|
||||||
|
date: moment().startOf("day").format("MM/DD/YYYY"),
|
||||||
|
})}
|
||||||
|
extra={
|
||||||
|
<Space>
|
||||||
|
<Typography.Text>{t("general.labels.tvmode")}</Typography.Text>
|
||||||
|
<Switch
|
||||||
|
onClick={() => setIsTvModeScheduledIn(!isTvModeScheduledIn)}
|
||||||
|
defaultChecked={isTvModeScheduledIn}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
{...cardProps}
|
||||||
|
>
|
||||||
|
<div style={{ height: "100%" }}>
|
||||||
|
<Table
|
||||||
|
onChange={handleTableChange}
|
||||||
|
pagination={false}
|
||||||
|
columns={isTvModeScheduledIn ? tvColumns : columns}
|
||||||
|
scroll={{ x: true, y: "calc(100% - 2em)" }}
|
||||||
|
rowKey="id"
|
||||||
|
style={{ height: "85%" }}
|
||||||
|
dataSource={appt}
|
||||||
|
size={isTvModeScheduledIn ? "small" : "middle"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DashboardScheduledInTodayGql = `
|
export const DashboardScheduledInTodayGql = `
|
||||||
scheduled_in_today: appointments(where: {start: {_gte: "${dayjs()
|
scheduled_in_today: appointments(where: {start: {_gte: "${moment()
|
||||||
.startOf("day")
|
.startOf("day")
|
||||||
.toISOString()}", _lte: "${dayjs()
|
.toISOString()}", _lte: "${moment()
|
||||||
.endOf("day")
|
.endOf("day")
|
||||||
.toISOString()}"}, canceled: {_eq: false}, block: {_neq: true}}) {
|
.toISOString()}"}, canceled: {_eq: false}, block: {_neq: true}}) {
|
||||||
canceled
|
canceled
|
||||||
id
|
id
|
||||||
job {
|
job {
|
||||||
alt_transport
|
alt_transport
|
||||||
clm_no
|
clm_no
|
||||||
jobid: id
|
jobid: id
|
||||||
|
joblines(where: {removed: {_eq: false}}) {
|
||||||
|
mod_lb_hrs
|
||||||
|
mod_lbr_ty
|
||||||
|
}
|
||||||
ins_co_nm
|
ins_co_nm
|
||||||
iouparent
|
iouparent
|
||||||
ownerid
|
ownerid
|
||||||
|
|||||||
@@ -1,37 +1,273 @@
|
|||||||
import {BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined,} from "@ant-design/icons";
|
import {BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined,} from "@ant-design/icons";
|
||||||
import {Card, Space, Table, Tooltip} from "antd";
|
import {Card, Space, Switch, Table, Tooltip, Typography} 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 {TimeFormatter} from "../../../utils/DateFormatter";
|
||||||
|
import {onlyUnique} from "../../../utils/arrayHelper";
|
||||||
|
import {alphaSort, dateSort} from "../../../utils/sorters";
|
||||||
|
import useLocalStorage from "../../../utils/useLocalStorage";
|
||||||
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
||||||
import OwnerNameDisplay from "../../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay, {OwnerNameDisplayFunction,} from "../../owner-name-display/owner-name-display.component";
|
||||||
import DashboardRefreshRequired from "../refresh-required.component";
|
import DashboardRefreshRequired from "../refresh-required.component";
|
||||||
import {pageLimit} from "../../../utils/config";
|
|
||||||
|
|
||||||
export default function DashboardScheduledOutToday({data, ...cardProps}) {
|
export default function DashboardScheduledOutToday({data, ...cardProps}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
});
|
filteredInfo: {},});
|
||||||
|
const [isTvModeScheduledOut, setIsTvModeScheduledOut] = useLocalStorage(
|
||||||
|
"isTvModeScheduledOut",
|
||||||
|
false
|
||||||
|
);
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
if (!data.scheduled_out_today)
|
if (!data.scheduled_out_today)
|
||||||
return <DashboardRefreshRequired {...cardProps} />;
|
return <DashboardRefreshRequired {...cardProps} />;
|
||||||
|
|
||||||
const filteredScheduledOutToday = data.scheduled_out_today.map((item) => {
|
const scheduledOutToday = data.scheduled_out_today.map((item) => {
|
||||||
|
const joblines_body = item.joblines
|
||||||
|
? item.joblines
|
||||||
|
.filter((l) => l.mod_lbr_ty !== "LAR")
|
||||||
|
.reduce((acc, val) => acc + val.mod_lb_hrs, 0)
|
||||||
|
: 0;
|
||||||
|
const joblines_ref = item.joblines
|
||||||
|
? item.joblines
|
||||||
|
.filter((l) => l.mod_lbr_ty === "LAR")
|
||||||
|
.reduce((acc, val) => acc + val.mod_lb_hrs, 0)
|
||||||
|
: 0;
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
scheduled_completion: dayjs(item.scheduled_completion).format("hh:mm a"),
|
joblines_body,
|
||||||
timestamp: dayjs(item.scheduled_completion).valueOf(),
|
joblines_ref,
|
||||||
}
|
};
|
||||||
}).sort((a, b) => a.timestamp - b.timestamp);
|
});
|
||||||
|
|
||||||
const columns = [
|
console.log('Scheduled Out Today')
|
||||||
|
console.dir(scheduledOutToday);
|
||||||
|
|
||||||
|
const tvFontSize = 18;
|
||||||
|
const tvFontWeight = "bold";
|
||||||
|
|
||||||
|
const tvColumns = [
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.scheduled_completion"),
|
||||||
|
dataIndex: "scheduled_completion",
|
||||||
|
key: "scheduled_completion",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
dateSort(a.scheduled_completion, b.scheduled_completion),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "scheduled_completion" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{fontSize: tvFontSize, fontWeight: tvFontWeight}}>
|
||||||
|
<TimeFormatter>{record.scheduled_completion}</TimeFormatter>
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.ro_number"),
|
title: t("jobs.fields.ro_number"),
|
||||||
dataIndex: "ro_number",
|
dataIndex: "ro_number",
|
||||||
key: "ro_number",
|
key: "ro_number",
|
||||||
|
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
|
<Link
|
||||||
|
to={"/manage/jobs/" + record.jobid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<Space>
|
||||||
|
<span style={{fontSize: tvFontSize, fontWeight: tvFontWeight}}>
|
||||||
|
{record.ro_number || t("general.labels.na")}
|
||||||
|
{record.production_vars && record.production_vars.alert ? (
|
||||||
|
<ExclamationCircleFilled className="production-alert"/>
|
||||||
|
) : null}
|
||||||
|
{record.suspended && (
|
||||||
|
<PauseCircleOutlined style={{color: "orangered"}}/>
|
||||||
|
)}
|
||||||
|
{record.iouparent && (
|
||||||
|
<Tooltip title={t("jobs.labels.iou")}>
|
||||||
|
<BranchesOutlined style={{color: "orangered"}}/>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</Space>
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.owner"),
|
||||||
|
dataIndex: "owner",
|
||||||
|
key: "owner",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => {
|
||||||
|
console.log('Render record out today');
|
||||||
|
console.dir(record);
|
||||||
|
return record.ownerid ? (
|
||||||
|
<Link
|
||||||
|
to={"/manage/owners/" + record.ownerid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<span style={{fontSize: tvFontSize, fontWeight: tvFontWeight}}>
|
||||||
|
<OwnerNameDisplay ownerObject={record}/>
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span style={{fontSize: tvFontSize, fontWeight: tvFontWeight}}>
|
||||||
|
<OwnerNameDisplay ownerObject={record}/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.vehicle"),
|
||||||
|
dataIndex: "vehicle",
|
||||||
|
key: "vehicle",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
alphaSort(
|
||||||
|
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${
|
||||||
|
a.v_model_desc || ""
|
||||||
|
}`,
|
||||||
|
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
|
||||||
|
),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.vehicleid ? (
|
||||||
|
<Link
|
||||||
|
to={"/manage/vehicles/" + record.vehicleid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<span style={{fontSize: tvFontSize, fontWeight: tvFontWeight}}>
|
||||||
|
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||||
|
record.v_model_desc || ""
|
||||||
|
}`}
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span
|
||||||
|
style={{fontSize: tvFontSize, fontWeight: tvFontWeight}}>{`${
|
||||||
|
record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||||
|
record.v_model_desc || ""
|
||||||
|
}`}</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("appointments.fields.alt_transport"),
|
||||||
|
dataIndex: "alt_transport",
|
||||||
|
key: "alt_transport",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => alphaSort(a.alt_transport, b.alt_transport),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "alt_transport" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
(scheduledOutToday &&
|
||||||
|
scheduledOutToday
|
||||||
|
.map((j) => j.alt_transport)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || "No Alt. Transport*",
|
||||||
|
value: [s],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],onFilter: (value, record) => value.includes(record.alt_transport),
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{fontSize: tvFontSize, fontWeight: tvFontWeight}}>
|
||||||
|
{record.alt_transport}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.status"),
|
||||||
|
dataIndex: "status",
|
||||||
|
key: "status",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => alphaSort(a.alt_transport, b.alt_transport),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
(scheduledOutToday &&
|
||||||
|
scheduledOutToday
|
||||||
|
.map((j) => j.status)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || "No Status*",
|
||||||
|
value: [s],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.status),render: (text, record) => (
|
||||||
|
<span style={{fontSize: tvFontSize, fontWeight: tvFontWeight}}>
|
||||||
|
{record.status}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.lab"),
|
||||||
|
dataIndex: "joblines_body",
|
||||||
|
key: "joblines_body",
|
||||||
|
sorter: (a, b) => a.joblines_body - b.joblines_body,
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "joblines_body" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
align: "right",
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{fontSize: tvFontSize, fontWeight: tvFontWeight}}>
|
||||||
|
{record.joblines_body.toFixed(1)}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.lar"),
|
||||||
|
dataIndex: "joblines_ref",
|
||||||
|
key: "joblines_ref",
|
||||||
|
sorter: (a, b) => a.joblines_ref - b.joblines_ref,
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "joblines_ref" && state.sortedInfo.order,
|
||||||
|
align: "right",
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{fontSize: tvFontSize, fontWeight: tvFontWeight}}>
|
||||||
|
{record.joblines_ref.toFixed(1)}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.scheduled_completion"),
|
||||||
|
dataIndex: "scheduled_completion",
|
||||||
|
key: "scheduled_completion",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
dateSort(a.scheduled_completion, b.scheduled_completion),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "scheduled_completion" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<TimeFormatter>{record.scheduled_completion}</TimeFormatter>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ro_number"),
|
||||||
|
dataIndex: "ro_number",
|
||||||
|
key: "ro_number",
|
||||||
|
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order, render: (text, record) => (
|
||||||
<Link
|
<Link
|
||||||
to={"/manage/jobs/" + record.jobid}
|
to={"/manage/jobs/" + record.jobid}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
@@ -58,7 +294,10 @@ export default function DashboardScheduledOutToday({data, ...cardProps}) {
|
|||||||
dataIndex: "owner",
|
dataIndex: "owner",
|
||||||
key: "owner",
|
key: "owner",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
responsive: ["md"],
|
sorter: (a, b) =>
|
||||||
|
alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.ownerid ? (
|
return record.ownerid ? (
|
||||||
<Link
|
<Link
|
||||||
@@ -75,24 +314,16 @@ export default function DashboardScheduledOutToday({data, ...cardProps}) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.ownr_ph1"),
|
title: t("dashboard.labels.phone"),
|
||||||
dataIndex: "ownr_ph1",
|
dataIndex: "ownr_ph",
|
||||||
key: "ownr_ph1",
|
key: "ownr_ph",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
render: (text, record) => (
|
render: (text, record) => (<Space size="small" wrap>
|
||||||
<ChatOpenButton phone={record.ownr_ph1} jobid={record.jobid}/>
|
<ChatOpenButton phone={record.ownr_ph1} jobid={record.jobid}/>
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("jobs.fields.ownr_ph2"),
|
|
||||||
dataIndex: "ownr_ph2",
|
|
||||||
key: "ownr_ph2",
|
|
||||||
ellipsis: true,
|
|
||||||
responsive: ["md"],
|
|
||||||
render: (text, record) => (
|
|
||||||
<ChatOpenButton phone={record.ownr_ph2} jobid={record.jobid}/>
|
<ChatOpenButton phone={record.ownr_ph2} jobid={record.jobid}/>
|
||||||
),
|
</Space>),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.ownr_ea"),
|
title: t("jobs.fields.ownr_ea"),
|
||||||
@@ -101,7 +332,7 @@ export default function DashboardScheduledOutToday({data, ...cardProps}) {
|
|||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<ChatOpenButton phone={record.ownr_ea} jobid={record.jobid}/>
|
<a href={`mailto:${record.ownr_ea}`}>{record.ownr_ea}</a>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -109,7 +340,15 @@ export default function DashboardScheduledOutToday({data, ...cardProps}) {
|
|||||||
dataIndex: "vehicle",
|
dataIndex: "vehicle",
|
||||||
key: "vehicle",
|
key: "vehicle",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
render: (text, record) => {
|
sorter: (a, b) =>
|
||||||
|
alphaSort(
|
||||||
|
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${
|
||||||
|
a.v_model_desc || ""
|
||||||
|
}`,
|
||||||
|
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
|
||||||
|
),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order, render: (text, record) => {
|
||||||
return record.vehicleid ? (
|
return record.vehicleid ? (
|
||||||
<Link
|
<Link
|
||||||
to={"/manage/vehicles/" + record.vehicleid}
|
to={"/manage/vehicles/" + record.vehicleid}
|
||||||
@@ -132,43 +371,78 @@ export default function DashboardScheduledOutToday({data, ...cardProps}) {
|
|||||||
key: "ins_co_nm",
|
key: "ins_co_nm",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
},
|
sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm),
|
||||||
{
|
sortOrder:
|
||||||
title: t("jobs.fields.scheduled_completion"),
|
state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order,
|
||||||
dataIndex: "scheduled_completion",
|
filters:
|
||||||
key: "scheduled_completion",
|
(scheduledOutToday &&
|
||||||
ellipsis: true,
|
scheduledOutToday
|
||||||
responsive: ["md"],
|
.map((j) => j.ins_co_nm)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || "No Ins. Co.*",
|
||||||
|
value: [s],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.ins_co_nm),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("appointments.fields.alt_transport"),
|
title: t("appointments.fields.alt_transport"),
|
||||||
dataIndex: "alt_transport",
|
dataIndex: "alt_transport",
|
||||||
key: "alt_transport",
|
key: "alt_transport",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
responsive: ["md"],
|
sorter: (a, b) => alphaSort(a.alt_transport, b.alt_transport),
|
||||||
},
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "alt_transport" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
(scheduledOutToday &&
|
||||||
|
scheduledOutToday
|
||||||
|
.map((j) => j.alt_transport)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || "No Alt. Transport*",
|
||||||
|
value: [s],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.alt_transport),},
|
||||||
];
|
];
|
||||||
|
|
||||||
const handleTableChange = (sorter) => {
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
setState({...state, sortedInfo: sorter});
|
setState({...state, filteredInfo: filters, sortedInfo: sorter});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={t("dashboard.titles.scheduledouttoday", {
|
title={t("dashboard.titles.scheduledoutdate", {
|
||||||
date: dayjs().startOf("day").format("MM/DD/YYYY"),
|
date: dayjs().startOf("day").format("MM/DD/YYYY"),
|
||||||
})}
|
})}
|
||||||
{...cardProps}
|
extra={
|
||||||
|
<Space>
|
||||||
|
<Typography.Text>{t("general.labels.tvmode")}</Typography.Text>
|
||||||
|
<Switch
|
||||||
|
onClick={() => setIsTvModeScheduledOut(!isTvModeScheduledOut)}
|
||||||
|
defaultChecked={isTvModeScheduledOut}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
}{...cardProps}
|
||||||
>
|
>
|
||||||
<div style={{height: "100%"}}>
|
<div style={{height: "100%"}}>
|
||||||
<Table
|
<Table
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{position: "top", defaultPageSize: pageLimit}}
|
pagination={false}
|
||||||
columns={columns}
|
columns={isTvModeScheduledOut ? tvColumns : columns}
|
||||||
scroll={{x: true, y: "calc(100% - 2em)"}}
|
scroll={{x: true, y: "calc(100% - 2em)"}}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
style={{height: "85%"}}
|
style={{height: "85%"}}
|
||||||
dataSource={filteredScheduledOutToday}
|
dataSource={scheduledOutToday}
|
||||||
|
size={isTvModeScheduledOut ? "small" : "middle"}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -185,6 +459,10 @@ export const DashboardScheduledOutTodayGql = `
|
|||||||
alt_transport
|
alt_transport
|
||||||
clm_no
|
clm_no
|
||||||
jobid: id
|
jobid: id
|
||||||
|
joblines(where: {removed: {_eq: false}}) {
|
||||||
|
mod_lb_hrs
|
||||||
|
mod_lbr_ty
|
||||||
|
}
|
||||||
ins_co_nm
|
ins_co_nm
|
||||||
iouparent
|
iouparent
|
||||||
ownerid
|
ownerid
|
||||||
@@ -197,6 +475,7 @@ export const DashboardScheduledOutTodayGql = `
|
|||||||
production_vars
|
production_vars
|
||||||
ro_number
|
ro_number
|
||||||
scheduled_completion
|
scheduled_completion
|
||||||
|
status
|
||||||
suspended
|
suspended
|
||||||
v_make_desc
|
v_make_desc
|
||||||
v_model_desc
|
v_model_desc
|
||||||
|
|||||||
@@ -270,26 +270,22 @@ const componentList = {
|
|||||||
h: 2,
|
h: 2,
|
||||||
},
|
},
|
||||||
ScheduleInToday: {
|
ScheduleInToday: {
|
||||||
label: i18next.t("dashboard.titles.scheduledintoday", {
|
label: i18next.t("dashboard.titles.scheduledintoday"),
|
||||||
date: dayjs().startOf("day").format("MM/DD/YYYY"),
|
|
||||||
}),
|
|
||||||
component: DashboardScheduledInToday,
|
component: DashboardScheduledInToday,
|
||||||
gqlFragment: DashboardScheduledInTodayGql,
|
gqlFragment: DashboardScheduledInTodayGql,
|
||||||
minW: 10,
|
minW: 6,
|
||||||
minH: 2,
|
minH: 2,
|
||||||
w: 10,
|
w: 10,
|
||||||
h: 2,
|
h: 3,
|
||||||
},
|
},
|
||||||
ScheduleOutToday: {
|
ScheduleOutToday: {
|
||||||
label: i18next.t("dashboard.titles.scheduledouttoday", {
|
label: i18next.t("dashboard.titles.scheduledouttoday"),
|
||||||
date: dayjs().startOf("day").format("MM/DD/YYYY"),
|
|
||||||
}),
|
|
||||||
component: DashboardScheduledOutToday,
|
component: DashboardScheduledOutToday,
|
||||||
gqlFragment: DashboardScheduledOutTodayGql,
|
gqlFragment: DashboardScheduledOutTodayGql,
|
||||||
minW: 10,
|
minW: 6,
|
||||||
minH: 2,
|
minH: 2,
|
||||||
w: 10,
|
w: 10,
|
||||||
h: 2,
|
h: 3,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -301,8 +297,7 @@ const createDashboardQuery = (state) => {
|
|||||||
.map((item, index) => componentList[item.i].gqlFragment || "")
|
.map((item, index) => componentList[item.i].gqlFragment || "")
|
||||||
.join("");
|
.join("");
|
||||||
return gql`
|
return gql`
|
||||||
query QUERY_DASHBOARD_DETAILS {
|
query QUERY_DASHBOARD_DETAILS { ${componentBasedAdditions || ""}
|
||||||
${componentBasedAdditions || ""}
|
|
||||||
monthly_sales: jobs(where: {_and: [
|
monthly_sales: jobs(where: {_and: [
|
||||||
{ voided: {_eq: false}},
|
{ voided: {_eq: false}},
|
||||||
{date_invoiced: {_gte: "${dayjs()
|
{date_invoiced: {_gte: "${dayjs()
|
||||||
@@ -312,7 +307,7 @@ const createDashboardQuery = (state) => {
|
|||||||
.endOf("month")
|
.endOf("month")
|
||||||
.endOf("day")
|
.endOf("day")
|
||||||
.toISOString()}"}}]}) {
|
.toISOString()}"}}]}) {
|
||||||
id
|
id
|
||||||
ro_number
|
ro_number
|
||||||
date_invoiced
|
date_invoiced
|
||||||
job_totals
|
job_totals
|
||||||
@@ -376,6 +371,5 @@ const createDashboardQuery = (state) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -145,7 +145,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.ant-card-body {
|
.ant-card-body {
|
||||||
height: 80%;
|
height: calc(100% - 2rem);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
// // background-color: red;
|
// // background-color: red;
|
||||||
// height: 90%;
|
// height: 90%;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const DateTimePicker = (
|
|||||||
disabledDate: (d) => dayjs().isAfter(d),
|
disabledDate: (d) => dayjs().isAfter(d),
|
||||||
})}
|
})}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
showSecond={false}
|
disableSeconds={true}
|
||||||
minuteStep={15}
|
minuteStep={15}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
format="hh:mm a"
|
format="hh:mm a"
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export default function ScoreboardAddButton({
|
|||||||
|
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async (values) => {
|
||||||
logImEXEvent("job_close_add_to_scoreboard");
|
logImEXEvent("job_close_add_to_scoreboard");
|
||||||
|
values.date = dayjs(values.date).format("YYYY-MM-DD");
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
let result;
|
let result;
|
||||||
@@ -169,7 +170,7 @@ export default function ScoreboardAddButton({
|
|||||||
return acc + job.lbr_adjustments[val];
|
return acc + job.lbr_adjustments[val];
|
||||||
}, 0);
|
}, 0);
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
date: new dayjs(),
|
date: dayjs(),
|
||||||
bodyhrs: Math.round(v.bodyhrs * 10) / 10,
|
bodyhrs: Math.round(v.bodyhrs * 10) / 10,
|
||||||
painthrs: Math.round(v.painthrs * 10) / 10,
|
painthrs: Math.round(v.painthrs * 10) / 10,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {gql, useApolloClient, useLazyQuery, useMutation, useQuery,} from "@apollo/client";
|
import {gql, useApolloClient, useLazyQuery, useMutation, useQuery,} from "@apollo/client";
|
||||||
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||||
import {Col, notification, Row} from "antd";
|
import {Col, Row, notification} from "antd";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
@@ -21,8 +21,8 @@ import {INSERT_NEW_NOTE} from "../../graphql/notes.queries";
|
|||||||
import {SEARCH_VEHICLE_BY_VIN} from "../../graphql/vehicles.queries";
|
import {SEARCH_VEHICLE_BY_VIN} from "../../graphql/vehicles.queries";
|
||||||
import {insertAuditTrail} from "../../redux/application/application.actions";
|
import {insertAuditTrail} from "../../redux/application/application.actions";
|
||||||
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
||||||
import confirmDialog from "../../utils/asyncConfirm";
|
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
import confirmDialog from "../../utils/asyncConfirm";
|
||||||
import CriticalPartsScan from "../../utils/criticalPartsScan";
|
import CriticalPartsScan from "../../utils/criticalPartsScan";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import JobsAvailableScan from "../jobs-available-scan/jobs-available-scan.component";
|
import JobsAvailableScan from "../jobs-available-scan/jobs-available-scan.component";
|
||||||
@@ -64,7 +64,15 @@ export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail,
|
|||||||
|
|
||||||
const [selectedJob, setSelectedJob] = useState(null);
|
const [selectedJob, setSelectedJob] = useState(null);
|
||||||
const [selectedOwner, setSelectedOwner] = useState(null);
|
const [selectedOwner, setSelectedOwner] = useState(null);
|
||||||
const [partsQueueToggle, setPartsQueueToggle] = useState(bodyshop.md_functionality_toggles.parts_queue_toggle);
|
const [partsQueueToggle, setPartsQueueToggle] = useState(
|
||||||
|
bodyshop.md_functionality_toggles.parts_queue_toggle
|
||||||
|
);
|
||||||
|
const [updateSchComp, setSchComp] = useState({
|
||||||
|
actual_in: dayjs(),
|
||||||
|
checked: false,
|
||||||
|
scheduled_completion: dayjs(),
|
||||||
|
automatic: false,
|
||||||
|
});
|
||||||
|
|
||||||
const [insertLoading, setInsertLoading] = useState(false);
|
const [insertLoading, setInsertLoading] = useState(false);
|
||||||
|
|
||||||
@@ -202,7 +210,9 @@ export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail,
|
|||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.creating", {error: r.message}),
|
message: t("jobs.errors.creating", {error: r.message}),
|
||||||
});
|
});
|
||||||
refetch();
|
refetch().catch(err => {
|
||||||
|
console.error(`Something went wrong in jobs available table container - ${err.message || ''}`)
|
||||||
|
});
|
||||||
setInsertLoading(false);
|
setInsertLoading(false);
|
||||||
setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
|
setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
|
||||||
}
|
}
|
||||||
@@ -404,6 +414,8 @@ export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail,
|
|||||||
modalSearchState={modalSearchState}
|
modalSearchState={modalSearchState}
|
||||||
partsQueueToggle={partsQueueToggle}
|
partsQueueToggle={partsQueueToggle}
|
||||||
setPartsQueueToggle={setPartsQueueToggle}
|
setPartsQueueToggle={setPartsQueueToggle}
|
||||||
|
updateSchComp={updateSchComp}
|
||||||
|
setSchComp={setSchComp}
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -119,11 +119,14 @@ export function JobsDetailHeader({job, bodyshop, disabled}) {
|
|||||||
</DataLabel>
|
</DataLabel>
|
||||||
{job?.cccontracts?.length > 0 && (
|
{job?.cccontracts?.length > 0 && (
|
||||||
<DataLabel label={t("jobs.labels.contracts")}>
|
<DataLabel label={t("jobs.labels.contracts")}>
|
||||||
{job.cccontracts.map((c) => (
|
{job.cccontracts.map((c, index) => (
|
||||||
|
<Space wrap>
|
||||||
<Link
|
<Link
|
||||||
key={c.id}
|
key={c.id}
|
||||||
to={`/manage/courtesycars/contracts/${c.id}`}
|
to={`/manage/courtesycars/contracts/${c.id}`}
|
||||||
>{`${c.agreementnumber} - ${c.courtesycar.fleetnumber} ${c.courtesycar.year} ${c.courtesycar.make} ${c.courtesycar.model}`}</Link>
|
>{`${c.agreementnumber} - ${c.courtesycar.fleetnumber} ${c.courtesycar.year} ${c.courtesycar.make} ${c.courtesycar.model}`}{index !== job.cccontracts.length - 1 ? "," : null}
|
||||||
|
</Link>
|
||||||
|
</Space>
|
||||||
))}
|
))}
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
)}
|
)}
|
||||||
@@ -132,7 +135,7 @@ export function JobsDetailHeader({job, bodyshop, disabled}) {
|
|||||||
<ProductionListColumnProductionNote record={job}/>
|
<ProductionListColumnProductionNote record={job}/>
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
|
|
||||||
<Space>
|
<Space wrap>
|
||||||
{job.special_coverage_policy && (
|
{job.special_coverage_policy && (
|
||||||
<Tag color="tomato">
|
<Tag color="tomato">
|
||||||
<Space>
|
<Space>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import {SyncOutlined} from "@ant-design/icons";
|
import {SyncOutlined} from "@ant-design/icons";
|
||||||
import {Button, Checkbox, Divider, Input, Table} from "antd";
|
import {Button, Checkbox, Divider, Input, Space, Table} from "antd";
|
||||||
import React from "react";
|
import dayjs from "../../utils/day";
|
||||||
|
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 PhoneFormatter from "../../utils/PhoneFormatter";
|
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||||
|
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function JobsFindModalComponent({
|
export default function JobsFindModalComponent({
|
||||||
@@ -16,11 +18,13 @@ export default function JobsFindModalComponent({
|
|||||||
jobsListRefetch,
|
jobsListRefetch,
|
||||||
partsQueueToggle,
|
partsQueueToggle,
|
||||||
setPartsQueueToggle,
|
setPartsQueueToggle,
|
||||||
|
updateSchComp,
|
||||||
|
setSchComp,
|
||||||
}) {
|
}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const [modalSearch, setModalSearch] = modalSearchState;
|
const [modalSearch, setModalSearch] = modalSearchState;
|
||||||
const [importOptions, setImportOptions] = importOptionsState;
|
const [importOptions, setImportOptions] = importOptionsState;
|
||||||
|
const [checkUTT, setCheckUTT] = useState(false);
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.ro_number"),
|
title: t("jobs.fields.ro_number"),
|
||||||
@@ -142,6 +146,35 @@ export default function JobsFindModalComponent({
|
|||||||
if (record) {
|
if (record) {
|
||||||
if (record.id) {
|
if (record.id) {
|
||||||
setSelectedJob(record.id);
|
setSelectedJob(record.id);
|
||||||
|
if (record.actual_in && record.scheduled_completion) {
|
||||||
|
setSchComp({
|
||||||
|
...updateSchComp,
|
||||||
|
actual_in: record.actual_in,
|
||||||
|
scheduled_completion: record.scheduled_completion,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (record.actual_in && !record.scheduled_completion) {
|
||||||
|
setSchComp({
|
||||||
|
...updateSchComp,
|
||||||
|
actual_in: record.actual_in,
|
||||||
|
scheduled_completion: dayjs(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!record.actual_in && record.scheduled_completion) {
|
||||||
|
setSchComp({
|
||||||
|
...updateSchComp,
|
||||||
|
actual_in: dayjs(),
|
||||||
|
scheduled_completion: dayjs(record.scheduled_completion),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!record.actual_in && !record.scheduled_completion) {
|
||||||
|
setSchComp({
|
||||||
|
...updateSchComp,
|
||||||
|
actual_in: dayjs(),
|
||||||
|
scheduled_completion: dayjs(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,6 +210,35 @@ export default function JobsFindModalComponent({
|
|||||||
rowSelection={{
|
rowSelection={{
|
||||||
onSelect: (props) => {
|
onSelect: (props) => {
|
||||||
setSelectedJob(props.id);
|
setSelectedJob(props.id);
|
||||||
|
if (props.actual_in && props.scheduled_completion) {
|
||||||
|
setSchComp({
|
||||||
|
...updateSchComp,
|
||||||
|
actual_in: props.actual_in,
|
||||||
|
scheduled_completion: props.scheduled_completion,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (props.actual_in && !props.scheduled_completion) {
|
||||||
|
setSchComp({
|
||||||
|
...updateSchComp,
|
||||||
|
actual_in: props.actual_in,
|
||||||
|
scheduled_completion: dayjs(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!props.actual_in && props.scheduled_completion) {
|
||||||
|
setSchComp({
|
||||||
|
...updateSchComp,
|
||||||
|
actual_in: dayjs(),
|
||||||
|
scheduled_completion: dayjs(props.scheduled_completion),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!props.actual_in && !props.scheduled_completion) {
|
||||||
|
setSchComp({
|
||||||
|
...updateSchComp,
|
||||||
|
actual_in: dayjs(),
|
||||||
|
scheduled_completion: dayjs(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
type: "radio",
|
type: "radio",
|
||||||
selectedRowKeys: [selectedJob],
|
selectedRowKeys: [selectedJob],
|
||||||
@@ -189,7 +251,7 @@ export default function JobsFindModalComponent({
|
|||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Divider/>
|
<Divider/><Space>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
defaultChecked={importOptions.overrideHeader}
|
defaultChecked={importOptions.overrideHeader}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
@@ -206,7 +268,40 @@ export default function JobsFindModalComponent({
|
|||||||
onChange={(e) => setPartsQueueToggle(e.target.checked)}
|
onChange={(e) => setPartsQueueToggle(e.target.checked)}
|
||||||
>
|
>
|
||||||
{t("bodyshop.fields.md_functionality_toggles.parts_queue_toggle")}
|
{t("bodyshop.fields.md_functionality_toggles.parts_queue_toggle")}
|
||||||
</Checkbox>
|
</Checkbox><Checkbox
|
||||||
|
checked={updateSchComp.checked}
|
||||||
|
onChange={(e) =>
|
||||||
|
setSchComp({...updateSchComp, checked: e.target.checked})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t("jobs.labels.update_scheduled_completion")}
|
||||||
|
</Checkbox>
|
||||||
|
{updateSchComp.checked === true ? (
|
||||||
|
<>
|
||||||
|
{checkUTT === false ? (
|
||||||
|
<FormDateTimePickerComponent
|
||||||
|
value={updateSchComp.scheduled_completion}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSchComp({...updateSchComp, scheduled_completion: e});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<Checkbox
|
||||||
|
checked={checkUTT}
|
||||||
|
onChange={(e) => {
|
||||||
|
setCheckUTT(e.target.checked);
|
||||||
|
setSchComp({
|
||||||
|
...updateSchComp,
|
||||||
|
scheduled_completion: null,
|
||||||
|
automatic: true,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("jobs.labels.calc_scheuled_completion")}
|
||||||
|
</Checkbox>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ export default connect(
|
|||||||
modalSearchState,
|
modalSearchState,
|
||||||
partsQueueToggle,
|
partsQueueToggle,
|
||||||
setPartsQueueToggle,
|
setPartsQueueToggle,
|
||||||
...modalProps
|
updateSchComp,
|
||||||
|
setSchComp, ...modalProps
|
||||||
}) {
|
}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
|
|
||||||
@@ -95,7 +96,8 @@ export default connect(
|
|||||||
modalSearchState={modalSearchState}
|
modalSearchState={modalSearchState}
|
||||||
partsQueueToggle={partsQueueToggle}
|
partsQueueToggle={partsQueueToggle}
|
||||||
setPartsQueueToggle={setPartsQueueToggle}
|
setPartsQueueToggle={setPartsQueueToggle}
|
||||||
/>
|
updateSchComp={updateSchComp}
|
||||||
|
setSchComp={setSchComp}/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,373 @@
|
|||||||
|
import {Button, Card, Checkbox, Col, Form, Input, InputNumber, Row, Select} from "antd";
|
||||||
|
import React, {useCallback, useEffect, useMemo, useState} from "react";
|
||||||
|
import {fetchFilterData} from "../../utils/RenderTemplate";
|
||||||
|
import {DeleteFilled} from "@ant-design/icons";
|
||||||
|
import {useTranslation} from "react-i18next";
|
||||||
|
import {getOrderOperatorsByType, getWhereOperatorsByType} from "../../utils/graphQLmodifier";
|
||||||
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
|
import {generateInternalReflections} from "./report-center-modal-utils";
|
||||||
|
|
||||||
|
|
||||||
|
export default function ReportCenterModalFiltersSortersComponent({form, bodyshop}) {
|
||||||
|
return (
|
||||||
|
<Form.Item style={{margin: 0, padding: 0}} dependencies={["key"]}>
|
||||||
|
{() => {
|
||||||
|
const key = form.getFieldValue("key");
|
||||||
|
return <RenderFilters form={form} templateId={key} bodyshop={bodyshop}/>;
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters Section
|
||||||
|
* @param filters
|
||||||
|
* @param form
|
||||||
|
* @param bodyshop
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function FiltersSection({filters, form, bodyshop}) {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card type='inner' title={t('reportcenter.labels.advanced_filters_filters')}
|
||||||
|
style={{marginTop: '10px'}}>
|
||||||
|
<Form.List name={["filters"]}>
|
||||||
|
{(fields, {add, remove, move}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<Form.Item key={field.key}>
|
||||||
|
<Row gutter={[16, 16]}>
|
||||||
|
<Col span={10}>
|
||||||
|
<Form.Item
|
||||||
|
key={`${index}field`}
|
||||||
|
label={t('reportcenter.labels.advanced_filters_filter_field')}
|
||||||
|
name={[field.name, "field"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
getPopupContainer={trigger => trigger.parentNode}
|
||||||
|
onChange={() => {
|
||||||
|
// Clear related Fields
|
||||||
|
form.setFieldValue(['filters', field.name, 'value'], null);
|
||||||
|
form.setFieldValue(['filters', field.name, 'operator'], null);
|
||||||
|
}}
|
||||||
|
options={
|
||||||
|
filters.map((f) => {
|
||||||
|
return {
|
||||||
|
value: f.name,
|
||||||
|
label: f?.translation ? (t(f.translation) === f.translation ? f.label : t(f.translation)) : f.label,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Form.Item
|
||||||
|
dependencies={[['filters', field.name, "field"]]}>
|
||||||
|
{
|
||||||
|
() => {
|
||||||
|
const name = form.getFieldValue(['filters', field.name, "field"]);
|
||||||
|
const type = filters.find(f => f.name === name)?.type;
|
||||||
|
|
||||||
|
return <Form.Item
|
||||||
|
key={`${index}operator`}
|
||||||
|
label={t('reportcenter.labels.advanced_filters_filter_operator')}
|
||||||
|
name={[field.name, "operator"]}
|
||||||
|
dependencies={[]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
getPopupContainer={trigger => trigger.parentNode}
|
||||||
|
options={getWhereOperatorsByType(type)}/>
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Form.Item
|
||||||
|
dependencies={[['filters', field.name, "field"]]}>
|
||||||
|
{
|
||||||
|
() => {
|
||||||
|
const name = form.getFieldValue(['filters', field.name, "field"]);
|
||||||
|
const type = filters.find(f => f.name === name)?.type;
|
||||||
|
const reflector = filters.find(f => f.name === name)?.reflector;
|
||||||
|
|
||||||
|
return <Form.Item
|
||||||
|
key={`${index}value`}
|
||||||
|
label={t('reportcenter.labels.advanced_filters_filter_value')}
|
||||||
|
name={[field.name, "value"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
(() => {
|
||||||
|
const generateReflections = (reflector) => {
|
||||||
|
if (!reflector) return [];
|
||||||
|
|
||||||
|
const {name} = reflector;
|
||||||
|
const path = name?.split('.');
|
||||||
|
const upperPath = path?.[0];
|
||||||
|
const finalPath = path?.slice(1).join('.');
|
||||||
|
|
||||||
|
return generateInternalReflections({
|
||||||
|
bodyshop,
|
||||||
|
upperPath,
|
||||||
|
finalPath
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const reflections = reflector ? generateReflections(reflector) : [];
|
||||||
|
const fieldPath = [[field.name, "value"]];
|
||||||
|
|
||||||
|
if (reflections.length > 0) {
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
options={reflections}
|
||||||
|
getPopupContainer={trigger => trigger.parentNode}
|
||||||
|
onChange={(value) => {
|
||||||
|
form.setFieldValue(fieldPath, value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === "number") {
|
||||||
|
return (
|
||||||
|
<InputNumber
|
||||||
|
onChange={(value) => form.setFieldValue(fieldPath, value)}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
onChange={(e) => form.setFieldValue(fieldPath, e.target.value)}/>
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
<Col span={2}>
|
||||||
|
<DeleteFilled
|
||||||
|
style={{margin: "1rem", paddingTop: '23px'}}
|
||||||
|
onClick={() => {
|
||||||
|
remove(field.name);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Form.Item>
|
||||||
|
))}
|
||||||
|
<Form.Item>
|
||||||
|
<Button
|
||||||
|
type="dashed"
|
||||||
|
onClick={() => {
|
||||||
|
add();
|
||||||
|
}}
|
||||||
|
style={{width: "100%"}}
|
||||||
|
>
|
||||||
|
{t("general.actions.add")}
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.List>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorters Section
|
||||||
|
* @param sorters
|
||||||
|
* @param form
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SortersSection({sorters, form}) {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
return (
|
||||||
|
<Card type='inner' title={t('reportcenter.labels.advanced_filters_sorters')}
|
||||||
|
style={{marginTop: '10px'}}>
|
||||||
|
<Form.List name={["sorters"]}>
|
||||||
|
{(fields, {add, remove, move}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Sorters
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<Form.Item key={field.key}>
|
||||||
|
<Row gutter={[16, 16]}>
|
||||||
|
<Col span={11}>
|
||||||
|
<Form.Item
|
||||||
|
key={`${index}field`}
|
||||||
|
label={t('reportcenter.labels.advanced_filters_sorter_field')}
|
||||||
|
name={[field.name, "field"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
options={
|
||||||
|
sorters.map((f) => ({
|
||||||
|
value: f.name,
|
||||||
|
label: f?.translation ? (t(f.translation) === f.translation ? f.label : t(f.translation)) : f.label,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
getPopupContainer={trigger => trigger.parentNode}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={11}>
|
||||||
|
<Form.Item
|
||||||
|
key={`${index}direction`}
|
||||||
|
label={t('reportcenter.labels.advanced_filters_sorter_direction')}
|
||||||
|
name={[field.name, "direction"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
options={getOrderOperatorsByType()}
|
||||||
|
getPopupContainer={trigger => trigger.parentNode}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col span={2}>
|
||||||
|
<DeleteFilled
|
||||||
|
style={{margin: "1rem", paddingTop: '23px'}}
|
||||||
|
onClick={() => {
|
||||||
|
remove(field.name);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Form.Item>
|
||||||
|
))}
|
||||||
|
<Form.Item>
|
||||||
|
<Button
|
||||||
|
type="dashed"
|
||||||
|
onClick={() => {
|
||||||
|
add();
|
||||||
|
}}
|
||||||
|
style={{width: "100%"}}
|
||||||
|
>
|
||||||
|
{t("general.actions.add")}
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.List>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render Filters
|
||||||
|
* @param templateId
|
||||||
|
* @param form
|
||||||
|
* @param bodyshop
|
||||||
|
* @returns {JSX.Element|null}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function RenderFilters({templateId, form, bodyshop}) {
|
||||||
|
const [state, setState] = useState(null);
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const {t} = useTranslation();
|
||||||
|
|
||||||
|
const fetch = useCallback(async () => {
|
||||||
|
// Reset all the filters and Sorters.
|
||||||
|
form.resetFields(['filters']);
|
||||||
|
form.resetFields(['sorters']);
|
||||||
|
form.resetFields(['defaultSorters']);
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
const data = await fetchFilterData({name: templateId});
|
||||||
|
|
||||||
|
// We have Success
|
||||||
|
if (data?.success) {
|
||||||
|
if (data?.data?.sorters && data?.data?.sorters.length > 0) {
|
||||||
|
const defaultSorters = data?.data?.sorters.filter((sorter) => sorter.hasOwnProperty('default')).map((sorter) => {
|
||||||
|
return {
|
||||||
|
field: sorter.name,
|
||||||
|
direction: sorter.default.direction
|
||||||
|
};
|
||||||
|
}).sort((a, b) => a.default.order - b.default.order);
|
||||||
|
|
||||||
|
form.setFieldValue('defaultSorters', JSON.stringify(defaultSorters));
|
||||||
|
}
|
||||||
|
// Set the state
|
||||||
|
setState(data.data);
|
||||||
|
}
|
||||||
|
// Something went wrong fetching filter data
|
||||||
|
else {
|
||||||
|
setState(null);
|
||||||
|
}
|
||||||
|
setIsLoading(false);
|
||||||
|
}, [templateId, form]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (templateId) {
|
||||||
|
fetch();
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [templateId, fetch]);
|
||||||
|
|
||||||
|
const filters = useMemo(() => state?.filters || [], [state]);
|
||||||
|
const sorters = useMemo(() => state?.sorters || [], [state]);
|
||||||
|
|
||||||
|
if (!templateId) return null;
|
||||||
|
if (isLoading) return <LoadingSkeleton/>;
|
||||||
|
if (!state) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{marginTop: '10px'}}>
|
||||||
|
<Checkbox
|
||||||
|
checked={visible}
|
||||||
|
onChange={(e) => setVisible(e.target.checked)}
|
||||||
|
children={t('reportcenter.labels.advanced_filters')}
|
||||||
|
/>
|
||||||
|
{visible && (
|
||||||
|
<div>
|
||||||
|
{filters.length > 0 && (
|
||||||
|
<FiltersSection filters={filters} form={form} bodyshop={bodyshop}/>
|
||||||
|
)}
|
||||||
|
{sorters.length > 0 && (
|
||||||
|
<SortersSection sorters={sorters} form={form}/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import {uniqBy} from "lodash";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get value from path
|
||||||
|
* @param obj
|
||||||
|
* @param path
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
const getValueFromPath = (obj, path) => path.split('.').reduce((prev, curr) => prev?.[curr], obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Valid internal reflections
|
||||||
|
* Note: This is intended for future functionality
|
||||||
|
* @type {{special: string[], bodyshop: [{name: string, type: string}]}}
|
||||||
|
*/
|
||||||
|
const VALID_INTERNAL_REFLECTIONS = {
|
||||||
|
bodyshop: [
|
||||||
|
{
|
||||||
|
name: 'md_ro_statuses.statuses',
|
||||||
|
type: 'kv-to-v'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate options
|
||||||
|
* @param bodyshop
|
||||||
|
* @param path
|
||||||
|
* @param labelPath
|
||||||
|
* @param valuePath
|
||||||
|
* @returns {{label: *, value: *}[]}
|
||||||
|
*/
|
||||||
|
const generateOptionsFromObject = (bodyshop, path, labelPath, valuePath) => {
|
||||||
|
const options = getValueFromPath(bodyshop, path);
|
||||||
|
return uniqBy(Object.values(options).map((value) => ({
|
||||||
|
label: value[labelPath],
|
||||||
|
value: value[valuePath],
|
||||||
|
})), 'value');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate special reflections
|
||||||
|
* @param bodyshop
|
||||||
|
* @param finalPath
|
||||||
|
* @returns {{label: *, value: *}[]|{label: *, value: *}[]|{label: string, value: *}[]|*[]}
|
||||||
|
*/
|
||||||
|
const generateSpecialReflections = (bodyshop, finalPath) => {
|
||||||
|
switch (finalPath) {
|
||||||
|
case 'cost_centers':
|
||||||
|
return generateOptionsFromObject(bodyshop, 'md_responsibility_centers.costs', 'name', 'name');
|
||||||
|
// Special case because Categories is an Array, not an Object.
|
||||||
|
case 'categories':
|
||||||
|
const catOptions = getValueFromPath(bodyshop, 'md_categories');
|
||||||
|
return uniqBy(catOptions.map((value) => ({
|
||||||
|
label: value,
|
||||||
|
value: value,
|
||||||
|
})), 'value');
|
||||||
|
case 'insurance_companies':
|
||||||
|
return generateOptionsFromObject(bodyshop, 'md_ins_cos', 'name', 'name');
|
||||||
|
case 'employee_teams':
|
||||||
|
return generateOptionsFromObject(bodyshop, 'employee_teams', 'name', 'id');
|
||||||
|
// Special case because Employees uses a concatenation of first_name and last_name
|
||||||
|
case 'employees':
|
||||||
|
const employeesOptions = getValueFromPath(bodyshop, 'employees');
|
||||||
|
return uniqBy(Object.values(employeesOptions).map((value) => ({
|
||||||
|
label: `${value.first_name} ${value.last_name}`,
|
||||||
|
value: value.id,
|
||||||
|
})), 'value');
|
||||||
|
case 'last_names':
|
||||||
|
return generateOptionsFromObject(bodyshop, 'employees', 'last_name', 'last_name');
|
||||||
|
case 'first_names':
|
||||||
|
return generateOptionsFromObject(bodyshop, 'employees', 'first_name', 'first_name');
|
||||||
|
case 'job_statuses':
|
||||||
|
const statusOptions = getValueFromPath(bodyshop, 'md_ro_statuses.statuses');
|
||||||
|
return Object.values(statusOptions).map((value) => ({
|
||||||
|
label: value,
|
||||||
|
value
|
||||||
|
}));
|
||||||
|
default:
|
||||||
|
console.error('Invalid Special reflection provided by Report Filters');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate bodyshop reflections
|
||||||
|
* @param bodyshop
|
||||||
|
* @param finalPath
|
||||||
|
* @returns {{label: *, value: *}[]|*[]}
|
||||||
|
*/
|
||||||
|
const generateBodyshopReflections = (bodyshop, finalPath) => {
|
||||||
|
const options = getValueFromPath(bodyshop, finalPath);
|
||||||
|
const reflectionRenderer = VALID_INTERNAL_REFLECTIONS.bodyshop.find(reflection => reflection.name === finalPath);
|
||||||
|
if (reflectionRenderer?.type === 'kv-to-v') {
|
||||||
|
return Object.values(options).map((value) => ({
|
||||||
|
label: value,
|
||||||
|
value
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate internal reflections based on the path and bodyshop
|
||||||
|
* @param bodyshop
|
||||||
|
* @param upperPath
|
||||||
|
* @param finalPath
|
||||||
|
* @returns {{label: *, value: *}[]|[]|{label: *, value: *}[]|{label: string, value: *}[]|{label: *, value: *}[]|*[]}
|
||||||
|
*/
|
||||||
|
const generateInternalReflections = ({bodyshop, upperPath, finalPath}) => {
|
||||||
|
switch (upperPath) {
|
||||||
|
case 'special':
|
||||||
|
return generateSpecialReflections(bodyshop, finalPath);
|
||||||
|
case 'bodyshop':
|
||||||
|
return generateBodyshopReflections(bodyshop, finalPath);
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export {generateInternalReflections,}
|
||||||
@@ -11,12 +11,13 @@ import {QUERY_ACTIVE_EMPLOYEES} from "../../graphql/employees.queries";
|
|||||||
import {QUERY_ALL_VENDORS} from "../../graphql/vendors.queries";
|
import {QUERY_ALL_VENDORS} from "../../graphql/vendors.queries";
|
||||||
import {selectReportCenter} from "../../redux/modals/modals.selectors";
|
import {selectReportCenter} from "../../redux/modals/modals.selectors";
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
import DatePIckerRanges from "../../utils/DatePickerRanges";
|
import DatePickerRanges from "../../utils/DatePickerRanges";
|
||||||
import {GenerateDocument} from "../../utils/RenderTemplate";
|
import {GenerateDocument} from "../../utils/RenderTemplate";
|
||||||
import {TemplateList} from "../../utils/TemplateConstants";
|
import {TemplateList} from "../../utils/TemplateConstants";
|
||||||
import EmployeeSearchSelect from "../employee-search-select/employee-search-select.component";
|
import EmployeeSearchSelect from "../employee-search-select/employee-search-select.component";
|
||||||
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
||||||
import "./report-center-modal.styles.scss";
|
import "./report-center-modal.styles.scss";
|
||||||
|
import ReportCenterModalFiltersSortersComponent from "./report-center-modal-filters-sorters-component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
reportCenterModal: selectReportCenter,
|
reportCenterModal: selectReportCenter,
|
||||||
@@ -89,7 +90,7 @@ export function ReportCenterModalComponent({reportCenterModal, bodyshop}) {
|
|||||||
const end = values.dates ? values.dates[1] : null;
|
const end = values.dates ? values.dates[1] : null;
|
||||||
const {id} = values;
|
const {id} = values;
|
||||||
|
|
||||||
await GenerateDocument(
|
const templateConfig =
|
||||||
{
|
{
|
||||||
name: values.key,
|
name: values.key,
|
||||||
variables: {
|
variables: {
|
||||||
@@ -104,7 +105,16 @@ export function ReportCenterModalComponent({reportCenterModal, bodyshop}) {
|
|||||||
|
|
||||||
...(id ? {id: id} : {}),
|
...(id ? {id: id} : {}),
|
||||||
},
|
},
|
||||||
},
|
filters: values.filters,
|
||||||
|
sorters: values.sorters,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_.isString(values.defaultSorters) && !_.isEmpty(values.defaultSorters)) {
|
||||||
|
templateConfig.defaultSorters = JSON.parse(values.defaultSorters);
|
||||||
|
}
|
||||||
|
|
||||||
|
await GenerateDocument(
|
||||||
|
templateConfig,
|
||||||
{
|
{
|
||||||
to: values.to,
|
to: values.to,
|
||||||
subject: Templates[values.key]?.subject,
|
subject: Templates[values.key]?.subject,
|
||||||
@@ -142,6 +152,7 @@ export function ReportCenterModalComponent({reportCenterModal, bodyshop}) {
|
|||||||
onChange={(e) => setSearch(e.target.value)}
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
value={search}
|
value={search}
|
||||||
/>
|
/>
|
||||||
|
<Form.Item name="defaultSorters" hidden/>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="key"
|
name="key"
|
||||||
label={t("reportcenter.labels.key")}
|
label={t("reportcenter.labels.key")}
|
||||||
@@ -174,7 +185,7 @@ export function ReportCenterModalComponent({reportCenterModal, bodyshop}) {
|
|||||||
<Typography.Title level={4}>
|
<Typography.Title level={4}>
|
||||||
{t(`reportcenter.labels.groups.${key}`)}
|
{t(`reportcenter.labels.groups.${key}`)}
|
||||||
</Typography.Title>
|
</Typography.Title>
|
||||||
<ul style={{columns: "2 auto"}}>
|
<ul style={{listStyleType: 'none', columns: "2 auto"}}>
|
||||||
{grouped[key].map((item) => (
|
{grouped[key].map((item) => (
|
||||||
<li key={item.key}>
|
<li key={item.key}>
|
||||||
<Radio key={item.key} value={item.key}>
|
<Radio key={item.key} value={item.key}>
|
||||||
@@ -206,6 +217,7 @@ export function ReportCenterModalComponent({reportCenterModal, bodyshop}) {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<ReportCenterModalFiltersSortersComponent form={form} bodyshop={bodyshop}/>
|
||||||
<Form.Item style={{margin: 0, padding: 0}} dependencies={["key"]}>
|
<Form.Item style={{margin: 0, padding: 0}} dependencies={["key"]}>
|
||||||
{() => {
|
{() => {
|
||||||
const key = form.getFieldValue("key");
|
const key = form.getFieldValue("key");
|
||||||
@@ -274,7 +286,7 @@ export function ReportCenterModalComponent({reportCenterModal, bodyshop}) {
|
|||||||
>
|
>
|
||||||
<DatePicker.RangePicker
|
<DatePicker.RangePicker
|
||||||
format="MM/DD/YYYY"
|
format="MM/DD/YYYY"
|
||||||
presets={DatePIckerRanges}
|
presets={DatePickerRanges}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
@@ -330,3 +342,4 @@ export function ReportCenterModalComponent({reportCenterModal, bodyshop}) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export function ScheduleCalendarContainer({calculateScheduleLoad}) {
|
|||||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||||
let normalizedData = [
|
let normalizedData = [
|
||||||
...data.appointments.map((e) => {
|
...data.appointments.map((e) => {
|
||||||
//Required becuase Hasura returns a string instead of a date object.
|
//Required because Hasura returns a string instead of a date object.
|
||||||
return Object.assign(
|
return Object.assign(
|
||||||
{},
|
{},
|
||||||
e,
|
e,
|
||||||
@@ -57,7 +57,7 @@ export function ScheduleCalendarContainer({calculateScheduleLoad}) {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
...data.employee_vacation.map((e) => {
|
...data.employee_vacation.map((e) => {
|
||||||
//Required becuase Hasura returns a string instead of a date object.
|
//Required because Hasura returns a string instead of a date object.
|
||||||
return {
|
return {
|
||||||
...e,
|
...e,
|
||||||
title: `${
|
title: `${
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {useMutation} from "@apollo/client";
|
import {useMutation} from "@apollo/client";
|
||||||
import {Button, Card, Dropdown, Form, InputNumber, notification} from "antd";
|
import {Button, Card, Dropdown, Form, InputNumber, notification, Space,} from "antd";
|
||||||
|
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 {UPDATE_SCOREBOARD_ENTRY} from "../../graphql/scoreboard.queries";
|
import {UPDATE_SCOREBOARD_ENTRY} from "../../graphql/scoreboard.queries";
|
||||||
@@ -13,6 +14,7 @@ export default function ScoreboardEntryEdit({entry}) {
|
|||||||
|
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async (values) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
values.date = dayjs(values.date).format("YYYY-MM-DD");
|
||||||
const result = await updateScoreboardentry({
|
const result = await updateScoreboardentry({
|
||||||
variables: {sbId: entry.id, sbInput: values},
|
variables: {sbId: entry.id, sbInput: values},
|
||||||
});
|
});
|
||||||
@@ -82,13 +84,14 @@ export default function ScoreboardEntryEdit({entry}) {
|
|||||||
>
|
>
|
||||||
<InputNumber precision={1}/>
|
<InputNumber precision={1}/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Space wrap>
|
||||||
<Button type="primary" loading={loading} htmlType="submit">
|
<Button type="primary" loading={loading} htmlType="submit">
|
||||||
{t("general.actions.save")}
|
{t("general.actions.save")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => setOpen(false)}>
|
<Button onClick={() => setOpen(false)}>
|
||||||
{t("general.actions.cancel")}
|
{t("general.actions.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
|
</Space>
|
||||||
</Form>
|
</Form>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import {SyncOutlined} from "@ant-design/icons";
|
||||||
import {useQuery} from "@apollo/client";
|
import {useQuery} from "@apollo/client";
|
||||||
import {Button, Card, Input, Modal, Space, Table, Typography} from "antd";
|
import {Button, Card, Input, Modal, Space, Table, Typography} from "antd";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
@@ -5,12 +6,13 @@ import {useTranslation} from "react-i18next";
|
|||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {QUERY_SCOREBOARD_PAGINATED} from "../../graphql/scoreboard.queries";
|
import {QUERY_SCOREBOARD_PAGINATED} from "../../graphql/scoreboard.queries";
|
||||||
import {DateFormatter} from "../../utils/DateFormatter";
|
import {DateFormatter} from "../../utils/DateFormatter";
|
||||||
|
import {pageLimit} from "../../utils/config";
|
||||||
|
import {alphaSort, dateSort} from "../../utils/sorters";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay, {OwnerNameDisplayFunction,} from "../owner-name-display/owner-name-display.component";
|
||||||
import ScoreboardEntryEdit from "../scoreboard-entry-edit/scoreboard-entry-edit.component";
|
import ScoreboardEntryEdit from "../scoreboard-entry-edit/scoreboard-entry-edit.component";
|
||||||
import ScoreboardRemoveButton from "../scoreboard-remove-button/scorebard-remove-button.component";
|
import ScoreboardRemoveButton from "../scoreboard-remove-button/scorebard-remove-button.component";
|
||||||
import {SyncOutlined} from "@ant-design/icons";
|
|
||||||
import {pageLimit} from "../../utils/config";
|
|
||||||
|
|
||||||
export default function ScoreboardJobsList({scoreBoardlist}) {
|
export default function ScoreboardJobsList({scoreBoardlist}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
@@ -45,7 +47,7 @@ export default function ScoreboardJobsList({scoreBoardlist}) {
|
|||||||
title: t("jobs.fields.ro_number"),
|
title: t("jobs.fields.ro_number"),
|
||||||
dataIndex: "ro_number",
|
dataIndex: "ro_number",
|
||||||
key: "ro_number",
|
key: "ro_number",
|
||||||
render: (text, record) => (
|
sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number), render: (text, record) => (
|
||||||
<Link to={"/manage/jobs/" + record.job.id}>
|
<Link to={"/manage/jobs/" + record.job.id}>
|
||||||
{record.job.ro_number || t("general.labels.na")}
|
{record.job.ro_number || t("general.labels.na")}
|
||||||
</Link>
|
</Link>
|
||||||
@@ -55,8 +57,11 @@ export default function ScoreboardJobsList({scoreBoardlist}) {
|
|||||||
title: t("jobs.fields.owner"),
|
title: t("jobs.fields.owner"),
|
||||||
dataIndex: "owner",
|
dataIndex: "owner",
|
||||||
key: "owner",
|
key: "owner",
|
||||||
ellipsis: true,
|
ellipsis: true, sorter: (a, b) =>
|
||||||
|
alphaSort(
|
||||||
|
OwnerNameDisplayFunction(a.job),
|
||||||
|
OwnerNameDisplayFunction(b.job)
|
||||||
|
),
|
||||||
render: (text, record) => <OwnerNameDisplay ownerObject={record.job}/>,
|
render: (text, record) => <OwnerNameDisplay ownerObject={record.job}/>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -64,7 +69,15 @@ export default function ScoreboardJobsList({scoreBoardlist}) {
|
|||||||
dataIndex: "vehicle",
|
dataIndex: "vehicle",
|
||||||
key: "vehicle",
|
key: "vehicle",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
render: (text, record) => (
|
sorter: (a, b) =>
|
||||||
|
alphaSort(
|
||||||
|
`${a.job.v_model_yr || ""} ${a.job.v_make_desc || ""} ${
|
||||||
|
a.job.v_model_desc || ""
|
||||||
|
}`,
|
||||||
|
`${b.job.v_model_yr || ""} ${b.job.v_make_desc || ""} ${
|
||||||
|
b.job.v_model_desc || ""
|
||||||
|
}`
|
||||||
|
), render: (text, record) => (
|
||||||
<span>{`${record.job.v_model_yr || ""} ${
|
<span>{`${record.job.v_model_yr || ""} ${
|
||||||
record.job.v_make_desc || ""
|
record.job.v_make_desc || ""
|
||||||
} ${record.job.v_model_desc || ""}`}</span>
|
} ${record.job.v_model_desc || ""}`}</span>
|
||||||
@@ -74,17 +87,20 @@ export default function ScoreboardJobsList({scoreBoardlist}) {
|
|||||||
title: t("scoreboard.fields.date"),
|
title: t("scoreboard.fields.date"),
|
||||||
dataIndex: "date",
|
dataIndex: "date",
|
||||||
key: "date",
|
key: "date",
|
||||||
|
sorter: (a, b) => dateSort(a.date, b.date),
|
||||||
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: t("scoreboard.fields.painthrs"),
|
|
||||||
dataIndex: "painthrs",
|
|
||||||
key: "painthrs",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: t("scoreboard.fields.bodyhrs"),
|
title: t("scoreboard.fields.bodyhrs"),
|
||||||
dataIndex: "bodyhrs",
|
dataIndex: "bodyhrs",
|
||||||
key: "bodyhrs",
|
key: "bodyhrs",
|
||||||
|
sorter: (a, b) => Number(a.bodyhrs) - Number(b.bodyhrs),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("scoreboard.fields.painthrs"),
|
||||||
|
dataIndex: "painthrs",
|
||||||
|
key: "painthrs",
|
||||||
|
sorter: (a, b) => Number(a.painthrs) - Number(b.painthrs),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("general.labels.actions"),
|
title: t("general.labels.actions"),
|
||||||
@@ -105,11 +121,9 @@ export default function ScoreboardJobsList({scoreBoardlist}) {
|
|||||||
open={state.open}
|
open={state.open}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
width="80%"
|
width="80%"
|
||||||
|
closable={false}
|
||||||
cancelButtonProps={{style: {display: "none"}}}
|
cancelButtonProps={{style: {display: "none"}}}
|
||||||
onOk={() => {
|
onOk={() =>
|
||||||
setState((state) => ({...state, open: false}));
|
|
||||||
}}
|
|
||||||
onCancel={() =>
|
|
||||||
setState((state) => ({
|
setState((state) => ({
|
||||||
...state,
|
...state,
|
||||||
open: false,
|
open: false,
|
||||||
@@ -161,9 +175,7 @@ export default function ScoreboardJobsList({scoreBoardlist}) {
|
|||||||
</Card>
|
</Card>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => setState((state) => ({...state, open: true}))}
|
||||||
setState((state) => ({...state, open: true}))
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{t("scoreboard.labels.entries")}
|
{t("scoreboard.labels.entries")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export default function ShopInfoSchedulingComponent({form}) {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<TimePicker showSecond={false} format="HH:mm"/>
|
<TimePicker disableSeconds={true} format="HH:mm"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.schedule_end_time")}
|
label={t("bodyshop.fields.schedule_end_time")}
|
||||||
@@ -47,7 +47,7 @@ export default function ShopInfoSchedulingComponent({form}) {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<TimePicker showSecond={false} format="HH:mm"/>
|
<TimePicker disableSeconds={true} format="HH:mm"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name={["appt_alt_transport"]}
|
name={["appt_alt_transport"]}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export const QUERY_AVAILABLE_CC = gql`
|
|||||||
]
|
]
|
||||||
status: { _eq: "courtesycars.status.in" }
|
status: { _eq: "courtesycars.status.in" }
|
||||||
}
|
}
|
||||||
|
order_by: { fleetnumber: asc }
|
||||||
) {
|
) {
|
||||||
color
|
color
|
||||||
dailycost
|
dailycost
|
||||||
@@ -29,6 +30,7 @@ export const QUERY_AVAILABLE_CC = gql`
|
|||||||
fleetnumber
|
fleetnumber
|
||||||
fuel
|
fuel
|
||||||
id
|
id
|
||||||
|
insuranceexpires
|
||||||
make
|
make
|
||||||
mileage
|
mileage
|
||||||
model
|
model
|
||||||
@@ -57,7 +59,7 @@ export const CHECK_CC_FLEET_NUMBER = gql`
|
|||||||
`;
|
`;
|
||||||
export const QUERY_ALL_CC = gql`
|
export const QUERY_ALL_CC = gql`
|
||||||
query QUERY_ALL_CC {
|
query QUERY_ALL_CC {
|
||||||
courtesycars {
|
courtesycars(order_by: { fleetnumber: asc }) {
|
||||||
color
|
color
|
||||||
created_at
|
created_at
|
||||||
dailycost
|
dailycost
|
||||||
|
|||||||
@@ -760,6 +760,7 @@
|
|||||||
"driverinformation": "Driver's Information",
|
"driverinformation": "Driver's Information",
|
||||||
"findcontract": "Find Contract",
|
"findcontract": "Find Contract",
|
||||||
"findermodal": "Contract Finder",
|
"findermodal": "Contract Finder",
|
||||||
|
"insuranceexpired": "The courtesy car insurance expires before the car is expected to return.",
|
||||||
"noteconvertedfrom": "R.O. created from converted Courtesy Car Contract {{agreementnumber}}.",
|
"noteconvertedfrom": "R.O. created from converted Courtesy Car Contract {{agreementnumber}}.",
|
||||||
"populatefromjob": "Populate from Job",
|
"populatefromjob": "Populate from Job",
|
||||||
"rates": "Contract Rates",
|
"rates": "Contract Rates",
|
||||||
@@ -880,6 +881,7 @@
|
|||||||
"labels": {
|
"labels": {
|
||||||
"bodyhrs": "Body Hrs",
|
"bodyhrs": "Body Hrs",
|
||||||
"dollarsinproduction": "Dollars in Production",
|
"dollarsinproduction": "Dollars in Production",
|
||||||
|
"phone": "Phone",
|
||||||
"prodhrs": "Production Hrs",
|
"prodhrs": "Production Hrs",
|
||||||
"refhrs": "Refinish Hrs"
|
"refhrs": "Refinish Hrs"
|
||||||
},
|
},
|
||||||
@@ -895,8 +897,10 @@
|
|||||||
"productiondollars": "Total Dollars in Production",
|
"productiondollars": "Total Dollars in Production",
|
||||||
"productionhours": "Total Hours in Production",
|
"productionhours": "Total Hours in Production",
|
||||||
"projectedmonthlysales": "Projected Monthly Sales",
|
"projectedmonthlysales": "Projected Monthly Sales",
|
||||||
"scheduledintoday": "Sheduled In Today: {{date}}",
|
"scheduledindate": "Sheduled In Today: {{date}}",
|
||||||
"scheduledouttoday": "Sheduled Out Today: {{date}}"
|
"scheduledintoday": "Sheduled In Today",
|
||||||
|
"scheduledoutdate": "Sheduled Out Today: {{date}}",
|
||||||
|
"scheduledouttoday": "Sheduled Out Today"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
@@ -1819,6 +1823,7 @@
|
|||||||
"ca_gst_all_if_null": "If the Job is marked as a \"GST Registrant\" and this value is set to $0, the customer will be responsible for paying all of the GST by default. ",
|
"ca_gst_all_if_null": "If the Job is marked as a \"GST Registrant\" and this value is set to $0, the customer will be responsible for paying all of the GST by default. ",
|
||||||
"calc_repair_days": "Calculated Repair Days",
|
"calc_repair_days": "Calculated Repair Days",
|
||||||
"calc_repair_days_tt": "This is the approximate number of days required to complete the repair according to the target touch time in your shop configuration (current set to {{target_touchtime}}).",
|
"calc_repair_days_tt": "This is the approximate number of days required to complete the repair according to the target touch time in your shop configuration (current set to {{target_touchtime}}).",
|
||||||
|
"calc_scheuled_completion": "Calculate Scheduled Completion",
|
||||||
"cards": {
|
"cards": {
|
||||||
"customer": "Customer Information",
|
"customer": "Customer Information",
|
||||||
"damage": "Area of Damage",
|
"damage": "Area of Damage",
|
||||||
@@ -1986,6 +1991,7 @@
|
|||||||
"total_sales_tax": "Total Sales Tax",
|
"total_sales_tax": "Total Sales Tax",
|
||||||
"totals": "Totals",
|
"totals": "Totals",
|
||||||
"unvoidnote": "This Job was unvoided.",
|
"unvoidnote": "This Job was unvoided.",
|
||||||
|
"update_scheduled_completion": "Update Scheduled Completion?",
|
||||||
"vehicle_info": "Vehicle",
|
"vehicle_info": "Vehicle",
|
||||||
"vehicleassociation": "Vehicle Association",
|
"vehicleassociation": "Vehicle Association",
|
||||||
"viewallocations": "View Allocations",
|
"viewallocations": "View Allocations",
|
||||||
@@ -2695,6 +2701,16 @@
|
|||||||
"generate": "Generate"
|
"generate": "Generate"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
|
"advanced_filters": "Advanced Filters and Sorters",
|
||||||
|
"advanced_filters_show": "Show",
|
||||||
|
"advanced_filters_hide": "Hide",
|
||||||
|
"advanced_filters_filters": "Filters",
|
||||||
|
"advanced_filters_sorters": "Sorters",
|
||||||
|
"advanced_filters_filter_field": "Field",
|
||||||
|
"advanced_filters_sorter_field": "Field",
|
||||||
|
"advanced_filters_sorter_direction": "Direction",
|
||||||
|
"advanced_filters_filter_operator": "Operator",
|
||||||
|
"advanced_filters_filter_value": "Value",
|
||||||
"dates": "Dates",
|
"dates": "Dates",
|
||||||
"employee": "Employee",
|
"employee": "Employee",
|
||||||
"filterson": "Filters on {{object}}: {{field}}",
|
"filterson": "Filters on {{object}}: {{field}}",
|
||||||
|
|||||||
@@ -760,6 +760,7 @@
|
|||||||
"driverinformation": "",
|
"driverinformation": "",
|
||||||
"findcontract": "",
|
"findcontract": "",
|
||||||
"findermodal": "",
|
"findermodal": "",
|
||||||
|
"insuranceexpired": "",
|
||||||
"noteconvertedfrom": "",
|
"noteconvertedfrom": "",
|
||||||
"populatefromjob": "",
|
"populatefromjob": "",
|
||||||
"rates": "",
|
"rates": "",
|
||||||
@@ -880,6 +881,7 @@
|
|||||||
"labels": {
|
"labels": {
|
||||||
"bodyhrs": "",
|
"bodyhrs": "",
|
||||||
"dollarsinproduction": "",
|
"dollarsinproduction": "",
|
||||||
|
"phone": "",
|
||||||
"prodhrs": "",
|
"prodhrs": "",
|
||||||
"refhrs": ""
|
"refhrs": ""
|
||||||
},
|
},
|
||||||
@@ -895,7 +897,9 @@
|
|||||||
"productiondollars": "",
|
"productiondollars": "",
|
||||||
"productionhours": "",
|
"productionhours": "",
|
||||||
"projectedmonthlysales": "",
|
"projectedmonthlysales": "",
|
||||||
|
"scheduledindate": "",
|
||||||
"scheduledintoday": "",
|
"scheduledintoday": "",
|
||||||
|
"scheduledoutdate": "",
|
||||||
"scheduledouttoday": ""
|
"scheduledouttoday": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1819,6 +1823,7 @@
|
|||||||
"ca_gst_all_if_null": "",
|
"ca_gst_all_if_null": "",
|
||||||
"calc_repair_days": "",
|
"calc_repair_days": "",
|
||||||
"calc_repair_days_tt": "",
|
"calc_repair_days_tt": "",
|
||||||
|
"calc_scheuled_completion": "",
|
||||||
"cards": {
|
"cards": {
|
||||||
"customer": "Información al cliente",
|
"customer": "Información al cliente",
|
||||||
"damage": "Área de Daño",
|
"damage": "Área de Daño",
|
||||||
@@ -1986,6 +1991,7 @@
|
|||||||
"total_sales_tax": "",
|
"total_sales_tax": "",
|
||||||
"totals": "",
|
"totals": "",
|
||||||
"unvoidnote": "",
|
"unvoidnote": "",
|
||||||
|
"update_scheduled_completion": "",
|
||||||
"vehicle_info": "Vehículo",
|
"vehicle_info": "Vehículo",
|
||||||
"vehicleassociation": "",
|
"vehicleassociation": "",
|
||||||
"viewallocations": "",
|
"viewallocations": "",
|
||||||
@@ -2695,6 +2701,16 @@
|
|||||||
"generate": ""
|
"generate": ""
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
|
"advanced_filters": "",
|
||||||
|
"advanced_filters_show": "",
|
||||||
|
"advanced_filters_hide": "",
|
||||||
|
"advanced_filters_filters": "",
|
||||||
|
"advanced_filters_sorters": "",
|
||||||
|
"advanced_filters_filter_field": "",
|
||||||
|
"advanced_filters_sorter_field": "",
|
||||||
|
"advanced_filters_sorter_direction": "",
|
||||||
|
"advanced_filters_filter_operator": "",
|
||||||
|
"advanced_filters_filter_value": "",
|
||||||
"dates": "",
|
"dates": "",
|
||||||
"employee": "",
|
"employee": "",
|
||||||
"filterson": "",
|
"filterson": "",
|
||||||
|
|||||||
@@ -760,6 +760,7 @@
|
|||||||
"driverinformation": "",
|
"driverinformation": "",
|
||||||
"findcontract": "",
|
"findcontract": "",
|
||||||
"findermodal": "",
|
"findermodal": "",
|
||||||
|
"insuranceexpired": "",
|
||||||
"noteconvertedfrom": "",
|
"noteconvertedfrom": "",
|
||||||
"populatefromjob": "",
|
"populatefromjob": "",
|
||||||
"rates": "",
|
"rates": "",
|
||||||
@@ -880,6 +881,7 @@
|
|||||||
"labels": {
|
"labels": {
|
||||||
"bodyhrs": "",
|
"bodyhrs": "",
|
||||||
"dollarsinproduction": "",
|
"dollarsinproduction": "",
|
||||||
|
"phone": "",
|
||||||
"prodhrs": "",
|
"prodhrs": "",
|
||||||
"refhrs": ""
|
"refhrs": ""
|
||||||
},
|
},
|
||||||
@@ -895,7 +897,9 @@
|
|||||||
"productiondollars": "",
|
"productiondollars": "",
|
||||||
"productionhours": "",
|
"productionhours": "",
|
||||||
"projectedmonthlysales": "",
|
"projectedmonthlysales": "",
|
||||||
|
"scheduledindate": "",
|
||||||
"scheduledintoday": "",
|
"scheduledintoday": "",
|
||||||
|
"scheduledoutdate": "",
|
||||||
"scheduledouttoday": ""
|
"scheduledouttoday": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1819,6 +1823,7 @@
|
|||||||
"ca_gst_all_if_null": "",
|
"ca_gst_all_if_null": "",
|
||||||
"calc_repair_days": "",
|
"calc_repair_days": "",
|
||||||
"calc_repair_days_tt": "",
|
"calc_repair_days_tt": "",
|
||||||
|
"calc_scheuled_completion": "",
|
||||||
"cards": {
|
"cards": {
|
||||||
"customer": "Informations client",
|
"customer": "Informations client",
|
||||||
"damage": "Zone de dommages",
|
"damage": "Zone de dommages",
|
||||||
@@ -1986,6 +1991,7 @@
|
|||||||
"total_sales_tax": "",
|
"total_sales_tax": "",
|
||||||
"totals": "",
|
"totals": "",
|
||||||
"unvoidnote": "",
|
"unvoidnote": "",
|
||||||
|
"update_scheduled_completion": "",
|
||||||
"vehicle_info": "Véhicule",
|
"vehicle_info": "Véhicule",
|
||||||
"vehicleassociation": "",
|
"vehicleassociation": "",
|
||||||
"viewallocations": "",
|
"viewallocations": "",
|
||||||
@@ -2695,6 +2701,16 @@
|
|||||||
"generate": ""
|
"generate": ""
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
|
"advanced_filters": "",
|
||||||
|
"advanced_filters_show": "",
|
||||||
|
"advanced_filters_hide": "",
|
||||||
|
"advanced_filters_filters": "",
|
||||||
|
"advanced_filters_sorters": "",
|
||||||
|
"advanced_filters_filter_field": "",
|
||||||
|
"advanced_filters_sorter_field": "",
|
||||||
|
"advanced_filters_sorter_direction": "",
|
||||||
|
"advanced_filters_filter_operator": "",
|
||||||
|
"advanced_filters_filter_value": "",
|
||||||
"dates": "",
|
"dates": "",
|
||||||
"employee": "",
|
"employee": "",
|
||||||
"filterson": "",
|
"filterson": "",
|
||||||
|
|||||||
@@ -57,6 +57,16 @@ const range = [
|
|||||||
label: 'Last 90 Days',
|
label: 'Last 90 Days',
|
||||||
value: [dayjs().add(-90, "day"), dayjs()],
|
value: [dayjs().add(-90, "day"), dayjs()],
|
||||||
}
|
}
|
||||||
]
|
];
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === "development") {
|
||||||
|
range.push({
|
||||||
|
label: 'Last Year',
|
||||||
|
value: [
|
||||||
|
dayjs().subtract(1, "year"),
|
||||||
|
dayjs(),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export default range;
|
export default range;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {store} from "../redux/store";
|
|||||||
import client from "../utils/GraphQLClient";
|
import client from "../utils/GraphQLClient";
|
||||||
import cleanAxios from "./CleanAxios";
|
import cleanAxios from "./CleanAxios";
|
||||||
import {TemplateList} from "./TemplateConstants";
|
import {TemplateList} from "./TemplateConstants";
|
||||||
|
import {generateTemplate} from "./graphQLmodifier";
|
||||||
|
|
||||||
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
||||||
|
|
||||||
@@ -74,7 +75,10 @@ export default async function RenderTemplate(
|
|||||||
headerpath: `/${bodyshop.imexshopid}/header.html`,
|
headerpath: `/${bodyshop.imexshopid}/header.html`,
|
||||||
footerpath: `/${bodyshop.imexshopid}/footer.html`,
|
footerpath: `/${bodyshop.imexshopid}/footer.html`,
|
||||||
bodyshop: bodyshop,
|
bodyshop: bodyshop,
|
||||||
|
filters: templateObject?.filters,
|
||||||
|
sorters: templateObject?.sorters,
|
||||||
offset: bodyshop.timezone, //dayjs().utcOffset(),
|
offset: bodyshop.timezone, //dayjs().utcOffset(),
|
||||||
|
defaultSorters: templateObject?.defaultSorters,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -292,7 +296,7 @@ export const GenerateDocument = async (
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else if (sendType === "x") {
|
} else if (sendType === "x") {
|
||||||
console.log("excel");
|
|
||||||
await RenderTemplate(template, bodyshop, false, true);
|
await RenderTemplate(template, bodyshop, false, true);
|
||||||
} else if (sendType === "text") {
|
} else if (sendType === "text") {
|
||||||
await RenderTemplate(template, bodyshop, false, false, true);
|
await RenderTemplate(template, bodyshop, false, false, true);
|
||||||
@@ -306,6 +310,58 @@ export const GenerateDocuments = async (templates) => {
|
|||||||
await RenderTemplates(templates, bodyshop);
|
await RenderTemplates(templates, bodyshop);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const fetchFilterData = async ({name}) => {
|
||||||
|
try {
|
||||||
|
const bodyshop = store.getState().user.bodyshop;
|
||||||
|
const jsrAuth = (await axios.post("/utils/jsr")).data;
|
||||||
|
jsreport.headers["FirebaseAuthorization"] =
|
||||||
|
"Bearer " + (await auth.currentUser.getIdToken());
|
||||||
|
|
||||||
|
const folders = await cleanAxios.get(`${server}/odata/folders`, {
|
||||||
|
headers: {Authorization: jsrAuth},
|
||||||
|
});
|
||||||
|
const shopSpecificFolder = folders.data.value.find(
|
||||||
|
(f) => f.name === bodyshop.imexshopid
|
||||||
|
);
|
||||||
|
|
||||||
|
const jsReportFilters = await cleanAxios.get(
|
||||||
|
`${server}/odata/assets?$filter=name eq '${name}.filters'`,
|
||||||
|
{headers: {Authorization: jsrAuth}}
|
||||||
|
);
|
||||||
|
console.log("🚀 ~ fetchFilterData ~ jsReportFilters:", jsReportFilters);
|
||||||
|
|
||||||
|
let parsedFilterData;
|
||||||
|
let useShopSpecificTemplate = false;
|
||||||
|
// let shopSpecificTemplate;
|
||||||
|
|
||||||
|
if (shopSpecificFolder) {
|
||||||
|
let shopSpecificTemplate = jsReportFilters.data.value.find(
|
||||||
|
(f) => f?.folder?.shortid === shopSpecificFolder.shortid
|
||||||
|
);
|
||||||
|
if (shopSpecificTemplate) {
|
||||||
|
useShopSpecificTemplate = true;
|
||||||
|
parsedFilterData = atob(shopSpecificTemplate.content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsedFilterData) {
|
||||||
|
const generalTemplate = jsReportFilters.data.value.find((f) => !f.folder);
|
||||||
|
useShopSpecificTemplate = false;
|
||||||
|
if (generalTemplate) parsedFilterData = atob(generalTemplate.content);
|
||||||
|
}
|
||||||
|
const data = JSON.parse(parsedFilterData);
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
useShopSpecificTemplate,
|
||||||
|
success: true,
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const fetchContextData = async (templateObject, jsrAuth) => {
|
const fetchContextData = async (templateObject, jsrAuth) => {
|
||||||
const bodyshop = store.getState().user.bodyshop;
|
const bodyshop = store.getState().user.bodyshop;
|
||||||
|
|
||||||
@@ -344,7 +400,19 @@ const fetchContextData = async (templateObject, jsrAuth) => {
|
|||||||
templateQueryToExecute = atob(generalTemplate.content);
|
templateQueryToExecute = atob(generalTemplate.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
let contextData = {};
|
// Commented out for future revision debugging
|
||||||
|
// console.log('Template Object');
|
||||||
|
// console.dir(templateObject);
|
||||||
|
// console.log('Unmodified Query');
|
||||||
|
// console.dir(templateQueryToExecute);
|
||||||
|
|
||||||
|
const hasFilters = templateObject?.filters?.length > 0;
|
||||||
|
const hasSorters = templateObject?.sorters?.length > 0;
|
||||||
|
const hasDefaultSorters = templateObject?.defaultSorters?.length > 0;
|
||||||
|
|
||||||
|
// We have no template filters or sorters, so we can just execute the query and return the data
|
||||||
|
if (!hasFilters && !hasSorters && !hasDefaultSorters) {
|
||||||
|
let contextData = {};
|
||||||
if (templateQueryToExecute) {
|
if (templateQueryToExecute) {
|
||||||
const {data} = await client.query({
|
const {data} = await client.query({
|
||||||
query: gql(templateQueryToExecute),
|
query: gql(templateQueryToExecute),
|
||||||
@@ -352,8 +420,14 @@ const fetchContextData = async (templateObject, jsrAuth) => {
|
|||||||
});
|
});
|
||||||
contextData = data;
|
contextData = data;
|
||||||
}
|
}
|
||||||
|
return {contextData, useShopSpecificTemplate};
|
||||||
|
}
|
||||||
|
|
||||||
return {contextData, useShopSpecificTemplate};
|
return await generateTemplate(
|
||||||
|
templateQueryToExecute,
|
||||||
|
templateObject,
|
||||||
|
useShopSpecificTemplate
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
//export const displayTemplateInWindow = (html) => {
|
//export const displayTemplateInWindow = (html) => {
|
||||||
|
|||||||
373
client/src/utils/graphQLmodifier.js
Normal file
373
client/src/utils/graphQLmodifier.js
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
import {Kind, parse, print, visit} from "graphql";
|
||||||
|
import client from "./GraphQLClient";
|
||||||
|
import {gql} from "@apollo/client";
|
||||||
|
|
||||||
|
const STRING_OPERATORS = [
|
||||||
|
{value: "_eq", label: "equals"},
|
||||||
|
{value: "_neq", label: "does not equal"},
|
||||||
|
{value: "_like", label: "contains"},
|
||||||
|
{value: "_nlike", label: "does not contain"},
|
||||||
|
{value: "_ilike", label: "contains case-insensitive"},
|
||||||
|
{value: "_nilike", label: "does not contain case-insensitive"}
|
||||||
|
];
|
||||||
|
const NUMBER_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"}
|
||||||
|
];
|
||||||
|
const ORDER_BY_OPERATORS = [
|
||||||
|
{value: "asc", label: "ascending"},
|
||||||
|
{value: "desc", label: "descending"}
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the available operators for filtering
|
||||||
|
* @returns {[{label: string, value: string},{label: string, value: string}]}
|
||||||
|
*/
|
||||||
|
export function getOrderOperatorsByType() {
|
||||||
|
return ORDER_BY_OPERATORS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the available operators for filtering
|
||||||
|
* @param type
|
||||||
|
* @returns {[{label: string, value: string},{label: string, value: string},{label: string, value: string},{label: string, value: string},{label: string, value: string},null]}
|
||||||
|
*/
|
||||||
|
export function getWhereOperatorsByType(type = 'string') {
|
||||||
|
const operators = {
|
||||||
|
string: STRING_OPERATORS,
|
||||||
|
number: NUMBER_OPERATORS
|
||||||
|
};
|
||||||
|
return operators[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable no-loop-func */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a GraphQL query into an AST
|
||||||
|
* @param query
|
||||||
|
* @returns {DocumentNode}
|
||||||
|
*/
|
||||||
|
export function parseQuery(query) {
|
||||||
|
return parse(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print an AST back into a GraphQL query
|
||||||
|
* @param query
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function printQuery(query) {
|
||||||
|
return print(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a template based on the query and object
|
||||||
|
* @param templateQueryToExecute
|
||||||
|
* @param templateObject
|
||||||
|
* @param useShopSpecificTemplate
|
||||||
|
* @returns {Promise<{contextData: {}, useShopSpecificTemplate}>}
|
||||||
|
*/
|
||||||
|
export async function generateTemplate(templateQueryToExecute, templateObject, useShopSpecificTemplate) {
|
||||||
|
// Advanced Filtering and Sorting modifications start here
|
||||||
|
|
||||||
|
// Parse the query and apply the filters and sorters
|
||||||
|
const ast = parseQuery(templateQueryToExecute);
|
||||||
|
|
||||||
|
let filterFields = [];
|
||||||
|
|
||||||
|
if (templateObject?.filters && templateObject?.filters?.length) {
|
||||||
|
applyFilters(ast, templateObject.filters, filterFields);
|
||||||
|
wrapFiltersInAnd(ast, filterFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (templateObject?.sorters && templateObject?.sorters?.length) {
|
||||||
|
applySorters(ast, templateObject.sorters);
|
||||||
|
} else if (templateObject?.defaultSorters && templateObject?.defaultSorters?.length) {
|
||||||
|
applySorters(ast, templateObject.defaultSorters);
|
||||||
|
}
|
||||||
|
|
||||||
|
const finalQuery = printQuery(ast);
|
||||||
|
|
||||||
|
// commented out for future revision debugging
|
||||||
|
// console.log('Modified Query');
|
||||||
|
// console.log(finalQuery);
|
||||||
|
|
||||||
|
let contextData = {};
|
||||||
|
if (templateQueryToExecute) {
|
||||||
|
const {data} = await client.query({
|
||||||
|
query: gql(finalQuery),
|
||||||
|
variables: {...templateObject.variables},
|
||||||
|
});
|
||||||
|
contextData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {contextData, useShopSpecificTemplate};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply sorters to the AST
|
||||||
|
* @param ast
|
||||||
|
* @param sorters
|
||||||
|
*/
|
||||||
|
export function applySorters(ast, sorters) {
|
||||||
|
sorters.forEach((sorter) => {
|
||||||
|
const fieldPath = sorter.field.split('.');
|
||||||
|
visit(ast, {
|
||||||
|
OperationDefinition: {
|
||||||
|
enter(node) {
|
||||||
|
// Loop through each sorter to apply it
|
||||||
|
// noinspection DuplicatedCode
|
||||||
|
|
||||||
|
let currentSelection = node; // Start with the root operation
|
||||||
|
|
||||||
|
// Navigate down the field path to the correct location
|
||||||
|
for (let i = 0; i < fieldPath.length - 1; i++) {
|
||||||
|
let found = false;
|
||||||
|
visit(currentSelection, {
|
||||||
|
Field: {
|
||||||
|
enter(node) {
|
||||||
|
if (node.name.value === fieldPath[i]) {
|
||||||
|
currentSelection = node; // Move down to the next level
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!found) break; // Stop if we can't find the next field in the path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the sorter at the correct level
|
||||||
|
if (currentSelection) {
|
||||||
|
const targetFieldName = fieldPath[fieldPath.length - 1];
|
||||||
|
let orderByArg = currentSelection.arguments.find(arg => arg.name.value === 'order_by');
|
||||||
|
if (!orderByArg) {
|
||||||
|
orderByArg = {
|
||||||
|
kind: Kind.ARGUMENT,
|
||||||
|
name: {kind: Kind.NAME, value: 'order_by'},
|
||||||
|
value: {kind: Kind.OBJECT, fields: []},
|
||||||
|
};
|
||||||
|
currentSelection.arguments.push(orderByArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sorterField = {
|
||||||
|
kind: Kind.OBJECT_FIELD,
|
||||||
|
name: {kind: Kind.NAME, value: targetFieldName},
|
||||||
|
value: {kind: Kind.ENUM, value: sorter.direction}, // Adjust if your schema uses a different type for sorting directions
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the new sorter condition
|
||||||
|
orderByArg.value.fields.push(sorterField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply filters to the AST
|
||||||
|
* @param ast
|
||||||
|
* @param filters
|
||||||
|
*/
|
||||||
|
export function applyFilters(ast, filters) {
|
||||||
|
return visit(ast, {
|
||||||
|
OperationDefinition: {
|
||||||
|
enter(node) {
|
||||||
|
filters.forEach(filter => {
|
||||||
|
const fieldPath = filter.field.split('.');
|
||||||
|
let topLevel = false;
|
||||||
|
|
||||||
|
// Determine if the filter should be applied at the top level
|
||||||
|
if (fieldPath[0].startsWith('[') && fieldPath[0].endsWith(']')) {
|
||||||
|
fieldPath[0] = fieldPath[0].substring(1, fieldPath[0].length - 1); // Strip the brackets
|
||||||
|
topLevel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topLevel) {
|
||||||
|
// Construct the filter for a top-level application
|
||||||
|
const targetFieldName = fieldPath[fieldPath.length - 1];
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the GraphQL kind for a value
|
||||||
|
* @param value
|
||||||
|
* @returns {Kind|Kind.INT}
|
||||||
|
*/
|
||||||
|
function getGraphQLKind(value) {
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return value % 1 === 0 ? Kind.INT : Kind.FLOAT;
|
||||||
|
} else if (typeof value === 'boolean') {
|
||||||
|
return Kind.BOOLEAN;
|
||||||
|
} else if (typeof value === 'string') {
|
||||||
|
return Kind.STRING;
|
||||||
|
}
|
||||||
|
// Extend with more types as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 */
|
||||||
469
package-lock.json
generated
469
package-lock.json
generated
@@ -9,21 +9,21 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-secrets-manager": "^3.503.0",
|
"@aws-sdk/client-secrets-manager": "^3.515.0",
|
||||||
"@aws-sdk/client-ses": "^3.503.0",
|
"@aws-sdk/client-ses": "^3.515.0",
|
||||||
"@aws-sdk/credential-provider-node": "^3.503.0",
|
"@aws-sdk/credential-provider-node": "^3.515.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.0",
|
"cloudinary": "^2.0.1",
|
||||||
"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.1",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"firebase-admin": "^12.0.0",
|
"firebase-admin": "^12.0.0",
|
||||||
"graphql": "^16.8.1",
|
"graphql": "^16.8.1",
|
||||||
@@ -31,23 +31,23 @@
|
|||||||
"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.0.1",
|
"json-2-csv": "^5.2.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"moment-timezone": "^0.5.44",
|
"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.43",
|
||||||
"nodemailer": "^6.9.8",
|
"nodemailer": "^6.9.10",
|
||||||
"phone": "^3.1.42",
|
"phone": "^3.1.42",
|
||||||
"recursive-diff": "^1.0.9",
|
"recursive-diff": "^1.0.9",
|
||||||
"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.11.0",
|
"stripe": "^14.18.0",
|
||||||
"twilio": "^4.20.0",
|
"twilio": "^4.22.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"
|
||||||
@@ -153,27 +153,26 @@
|
|||||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/client-secrets-manager": {
|
"node_modules/@aws-sdk/client-secrets-manager": {
|
||||||
"version": "3.503.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.503.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.515.0.tgz",
|
||||||
"integrity": "sha512-wM+izwvHwPPaUxArLs3dVIyyTVlO4Au2DYqcy/OsuuiGFeSSrbWArPnLqH7tav+OINzWTD4qP9okKGtH/rEdtA==",
|
"integrity": "sha512-YO7SVh0mQ55COP5LcKsXE+o6wsOBBn3beAqKDZIBdjXho5rNhTdvbtaGTiaZmv0ALtu7TxtPVixhbDE0y1QseA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-browser": "3.0.0",
|
"@aws-crypto/sha256-browser": "3.0.0",
|
||||||
"@aws-crypto/sha256-js": "3.0.0",
|
"@aws-crypto/sha256-js": "3.0.0",
|
||||||
"@aws-sdk/client-sts": "3.502.0",
|
"@aws-sdk/client-sts": "3.515.0",
|
||||||
"@aws-sdk/core": "3.496.0",
|
"@aws-sdk/core": "3.513.0",
|
||||||
"@aws-sdk/credential-provider-node": "3.503.0",
|
"@aws-sdk/credential-provider-node": "3.515.0",
|
||||||
"@aws-sdk/middleware-host-header": "3.502.0",
|
"@aws-sdk/middleware-host-header": "3.515.0",
|
||||||
"@aws-sdk/middleware-logger": "3.502.0",
|
"@aws-sdk/middleware-logger": "3.515.0",
|
||||||
"@aws-sdk/middleware-recursion-detection": "3.502.0",
|
"@aws-sdk/middleware-recursion-detection": "3.515.0",
|
||||||
"@aws-sdk/middleware-signing": "3.502.0",
|
"@aws-sdk/middleware-user-agent": "3.515.0",
|
||||||
"@aws-sdk/middleware-user-agent": "3.502.0",
|
"@aws-sdk/region-config-resolver": "3.515.0",
|
||||||
"@aws-sdk/region-config-resolver": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/util-endpoints": "3.515.0",
|
||||||
"@aws-sdk/util-endpoints": "3.502.0",
|
"@aws-sdk/util-user-agent-browser": "3.515.0",
|
||||||
"@aws-sdk/util-user-agent-browser": "3.502.0",
|
"@aws-sdk/util-user-agent-node": "3.515.0",
|
||||||
"@aws-sdk/util-user-agent-node": "3.502.0",
|
|
||||||
"@smithy/config-resolver": "^2.1.1",
|
"@smithy/config-resolver": "^2.1.1",
|
||||||
"@smithy/core": "^1.3.1",
|
"@smithy/core": "^1.3.2",
|
||||||
"@smithy/fetch-http-handler": "^2.4.1",
|
"@smithy/fetch-http-handler": "^2.4.1",
|
||||||
"@smithy/hash-node": "^2.1.1",
|
"@smithy/hash-node": "^2.1.1",
|
||||||
"@smithy/invalid-dependency": "^2.1.1",
|
"@smithy/invalid-dependency": "^2.1.1",
|
||||||
@@ -192,47 +191,39 @@
|
|||||||
"@smithy/util-body-length-browser": "^2.1.1",
|
"@smithy/util-body-length-browser": "^2.1.1",
|
||||||
"@smithy/util-body-length-node": "^2.2.1",
|
"@smithy/util-body-length-node": "^2.2.1",
|
||||||
"@smithy/util-defaults-mode-browser": "^2.1.1",
|
"@smithy/util-defaults-mode-browser": "^2.1.1",
|
||||||
"@smithy/util-defaults-mode-node": "^2.1.1",
|
"@smithy/util-defaults-mode-node": "^2.2.0",
|
||||||
"@smithy/util-endpoints": "^1.1.1",
|
"@smithy/util-endpoints": "^1.1.1",
|
||||||
|
"@smithy/util-middleware": "^2.1.1",
|
||||||
"@smithy/util-retry": "^2.1.1",
|
"@smithy/util-retry": "^2.1.1",
|
||||||
"@smithy/util-utf8": "^2.1.1",
|
"@smithy/util-utf8": "^2.1.1",
|
||||||
"tslib": "^2.5.0",
|
"tslib": "^2.5.0",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^9.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/client-secrets-manager/node_modules/uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
|
||||||
"bin": {
|
|
||||||
"uuid": "dist/bin/uuid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@aws-sdk/client-ses": {
|
"node_modules/@aws-sdk/client-ses": {
|
||||||
"version": "3.503.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.503.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.515.0.tgz",
|
||||||
"integrity": "sha512-ppMy4sDHiFMxPsEKAE7G7v6Xtf4tsdXN2IhrML/SjrNmnSDvKMmcBHdnus1WyjKk0oev7sgYTbcVBryxTb/AhA==",
|
"integrity": "sha512-X51TvcpqJ83ZOSUa/efWl+cj3cXBF6fCb2iNghjRD2McDvzGKoiR+Zaoy05doPdh/GZ7azTBqX0qKRIyUj//wg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-browser": "3.0.0",
|
"@aws-crypto/sha256-browser": "3.0.0",
|
||||||
"@aws-crypto/sha256-js": "3.0.0",
|
"@aws-crypto/sha256-js": "3.0.0",
|
||||||
"@aws-sdk/client-sts": "3.502.0",
|
"@aws-sdk/client-sts": "3.515.0",
|
||||||
"@aws-sdk/core": "3.496.0",
|
"@aws-sdk/core": "3.513.0",
|
||||||
"@aws-sdk/credential-provider-node": "3.503.0",
|
"@aws-sdk/credential-provider-node": "3.515.0",
|
||||||
"@aws-sdk/middleware-host-header": "3.502.0",
|
"@aws-sdk/middleware-host-header": "3.515.0",
|
||||||
"@aws-sdk/middleware-logger": "3.502.0",
|
"@aws-sdk/middleware-logger": "3.515.0",
|
||||||
"@aws-sdk/middleware-recursion-detection": "3.502.0",
|
"@aws-sdk/middleware-recursion-detection": "3.515.0",
|
||||||
"@aws-sdk/middleware-signing": "3.502.0",
|
"@aws-sdk/middleware-user-agent": "3.515.0",
|
||||||
"@aws-sdk/middleware-user-agent": "3.502.0",
|
"@aws-sdk/region-config-resolver": "3.515.0",
|
||||||
"@aws-sdk/region-config-resolver": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/util-endpoints": "3.515.0",
|
||||||
"@aws-sdk/util-endpoints": "3.502.0",
|
"@aws-sdk/util-user-agent-browser": "3.515.0",
|
||||||
"@aws-sdk/util-user-agent-browser": "3.502.0",
|
"@aws-sdk/util-user-agent-node": "3.515.0",
|
||||||
"@aws-sdk/util-user-agent-node": "3.502.0",
|
|
||||||
"@smithy/config-resolver": "^2.1.1",
|
"@smithy/config-resolver": "^2.1.1",
|
||||||
"@smithy/core": "^1.3.1",
|
"@smithy/core": "^1.3.2",
|
||||||
"@smithy/fetch-http-handler": "^2.4.1",
|
"@smithy/fetch-http-handler": "^2.4.1",
|
||||||
"@smithy/hash-node": "^2.1.1",
|
"@smithy/hash-node": "^2.1.1",
|
||||||
"@smithy/invalid-dependency": "^2.1.1",
|
"@smithy/invalid-dependency": "^2.1.1",
|
||||||
@@ -251,8 +242,9 @@
|
|||||||
"@smithy/util-body-length-browser": "^2.1.1",
|
"@smithy/util-body-length-browser": "^2.1.1",
|
||||||
"@smithy/util-body-length-node": "^2.2.1",
|
"@smithy/util-body-length-node": "^2.2.1",
|
||||||
"@smithy/util-defaults-mode-browser": "^2.1.1",
|
"@smithy/util-defaults-mode-browser": "^2.1.1",
|
||||||
"@smithy/util-defaults-mode-node": "^2.1.1",
|
"@smithy/util-defaults-mode-node": "^2.2.0",
|
||||||
"@smithy/util-endpoints": "^1.1.1",
|
"@smithy/util-endpoints": "^1.1.1",
|
||||||
|
"@smithy/util-middleware": "^2.1.1",
|
||||||
"@smithy/util-retry": "^2.1.1",
|
"@smithy/util-retry": "^2.1.1",
|
||||||
"@smithy/util-utf8": "^2.1.1",
|
"@smithy/util-utf8": "^2.1.1",
|
||||||
"@smithy/util-waiter": "^2.1.1",
|
"@smithy/util-waiter": "^2.1.1",
|
||||||
@@ -264,24 +256,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/client-sso": {
|
"node_modules/@aws-sdk/client-sso": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.515.0.tgz",
|
||||||
"integrity": "sha512-OZAYal1+PQgUUtWiHhRayDtX0OD+XpXHKAhjYgEIPbyhQaCMp3/Bq1xDX151piWXvXqXLJHFKb8DUEqzwGO9QA==",
|
"integrity": "sha512-4oGBLW476zmkdN98lAns3bObRNO+DLOfg4MDUSR6l6GYBV/zGAtoy2O/FhwYKgA2L5h2ZtElGopLlk/1Q0ePLw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-browser": "3.0.0",
|
"@aws-crypto/sha256-browser": "3.0.0",
|
||||||
"@aws-crypto/sha256-js": "3.0.0",
|
"@aws-crypto/sha256-js": "3.0.0",
|
||||||
"@aws-sdk/core": "3.496.0",
|
"@aws-sdk/core": "3.513.0",
|
||||||
"@aws-sdk/middleware-host-header": "3.502.0",
|
"@aws-sdk/middleware-host-header": "3.515.0",
|
||||||
"@aws-sdk/middleware-logger": "3.502.0",
|
"@aws-sdk/middleware-logger": "3.515.0",
|
||||||
"@aws-sdk/middleware-recursion-detection": "3.502.0",
|
"@aws-sdk/middleware-recursion-detection": "3.515.0",
|
||||||
"@aws-sdk/middleware-user-agent": "3.502.0",
|
"@aws-sdk/middleware-user-agent": "3.515.0",
|
||||||
"@aws-sdk/region-config-resolver": "3.502.0",
|
"@aws-sdk/region-config-resolver": "3.515.0",
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@aws-sdk/util-endpoints": "3.502.0",
|
"@aws-sdk/util-endpoints": "3.515.0",
|
||||||
"@aws-sdk/util-user-agent-browser": "3.502.0",
|
"@aws-sdk/util-user-agent-browser": "3.515.0",
|
||||||
"@aws-sdk/util-user-agent-node": "3.502.0",
|
"@aws-sdk/util-user-agent-node": "3.515.0",
|
||||||
"@smithy/config-resolver": "^2.1.1",
|
"@smithy/config-resolver": "^2.1.1",
|
||||||
"@smithy/core": "^1.3.1",
|
"@smithy/core": "^1.3.2",
|
||||||
"@smithy/fetch-http-handler": "^2.4.1",
|
"@smithy/fetch-http-handler": "^2.4.1",
|
||||||
"@smithy/hash-node": "^2.1.1",
|
"@smithy/hash-node": "^2.1.1",
|
||||||
"@smithy/invalid-dependency": "^2.1.1",
|
"@smithy/invalid-dependency": "^2.1.1",
|
||||||
@@ -300,8 +292,9 @@
|
|||||||
"@smithy/util-body-length-browser": "^2.1.1",
|
"@smithy/util-body-length-browser": "^2.1.1",
|
||||||
"@smithy/util-body-length-node": "^2.2.1",
|
"@smithy/util-body-length-node": "^2.2.1",
|
||||||
"@smithy/util-defaults-mode-browser": "^2.1.1",
|
"@smithy/util-defaults-mode-browser": "^2.1.1",
|
||||||
"@smithy/util-defaults-mode-node": "^2.1.1",
|
"@smithy/util-defaults-mode-node": "^2.2.0",
|
||||||
"@smithy/util-endpoints": "^1.1.1",
|
"@smithy/util-endpoints": "^1.1.1",
|
||||||
|
"@smithy/util-middleware": "^2.1.1",
|
||||||
"@smithy/util-retry": "^2.1.1",
|
"@smithy/util-retry": "^2.1.1",
|
||||||
"@smithy/util-utf8": "^2.1.1",
|
"@smithy/util-utf8": "^2.1.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
@@ -311,26 +304,25 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/client-sso-oidc": {
|
"node_modules/@aws-sdk/client-sso-oidc": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.515.0.tgz",
|
||||||
"integrity": "sha512-Yc9tZqTOMWtdgpkrdjKShgWb9oKNsFQrItfoiN1xWDllaFFRPi2KTiZiR0AbSTrNasJy13d210DOxrIdte+kWQ==",
|
"integrity": "sha512-zACa8LNlPUdlNUBqQRf5a3MfouLNtcBfm84v2c8M976DwJrMGONPe1QjyLLsD38uESQiXiVQRruj/b000iMXNw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-browser": "3.0.0",
|
"@aws-crypto/sha256-browser": "3.0.0",
|
||||||
"@aws-crypto/sha256-js": "3.0.0",
|
"@aws-crypto/sha256-js": "3.0.0",
|
||||||
"@aws-sdk/client-sts": "3.502.0",
|
"@aws-sdk/client-sts": "3.515.0",
|
||||||
"@aws-sdk/core": "3.496.0",
|
"@aws-sdk/core": "3.513.0",
|
||||||
"@aws-sdk/middleware-host-header": "3.502.0",
|
"@aws-sdk/middleware-host-header": "3.515.0",
|
||||||
"@aws-sdk/middleware-logger": "3.502.0",
|
"@aws-sdk/middleware-logger": "3.515.0",
|
||||||
"@aws-sdk/middleware-recursion-detection": "3.502.0",
|
"@aws-sdk/middleware-recursion-detection": "3.515.0",
|
||||||
"@aws-sdk/middleware-signing": "3.502.0",
|
"@aws-sdk/middleware-user-agent": "3.515.0",
|
||||||
"@aws-sdk/middleware-user-agent": "3.502.0",
|
"@aws-sdk/region-config-resolver": "3.515.0",
|
||||||
"@aws-sdk/region-config-resolver": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/util-endpoints": "3.515.0",
|
||||||
"@aws-sdk/util-endpoints": "3.502.0",
|
"@aws-sdk/util-user-agent-browser": "3.515.0",
|
||||||
"@aws-sdk/util-user-agent-browser": "3.502.0",
|
"@aws-sdk/util-user-agent-node": "3.515.0",
|
||||||
"@aws-sdk/util-user-agent-node": "3.502.0",
|
|
||||||
"@smithy/config-resolver": "^2.1.1",
|
"@smithy/config-resolver": "^2.1.1",
|
||||||
"@smithy/core": "^1.3.1",
|
"@smithy/core": "^1.3.2",
|
||||||
"@smithy/fetch-http-handler": "^2.4.1",
|
"@smithy/fetch-http-handler": "^2.4.1",
|
||||||
"@smithy/hash-node": "^2.1.1",
|
"@smithy/hash-node": "^2.1.1",
|
||||||
"@smithy/invalid-dependency": "^2.1.1",
|
"@smithy/invalid-dependency": "^2.1.1",
|
||||||
@@ -349,8 +341,9 @@
|
|||||||
"@smithy/util-body-length-browser": "^2.1.1",
|
"@smithy/util-body-length-browser": "^2.1.1",
|
||||||
"@smithy/util-body-length-node": "^2.2.1",
|
"@smithy/util-body-length-node": "^2.2.1",
|
||||||
"@smithy/util-defaults-mode-browser": "^2.1.1",
|
"@smithy/util-defaults-mode-browser": "^2.1.1",
|
||||||
"@smithy/util-defaults-mode-node": "^2.1.1",
|
"@smithy/util-defaults-mode-node": "^2.2.0",
|
||||||
"@smithy/util-endpoints": "^1.1.1",
|
"@smithy/util-endpoints": "^1.1.1",
|
||||||
|
"@smithy/util-middleware": "^2.1.1",
|
||||||
"@smithy/util-retry": "^2.1.1",
|
"@smithy/util-retry": "^2.1.1",
|
||||||
"@smithy/util-utf8": "^2.1.1",
|
"@smithy/util-utf8": "^2.1.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
@@ -359,28 +352,28 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@aws-sdk/credential-provider-node": "*"
|
"@aws-sdk/credential-provider-node": "^3.515.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/client-sts": {
|
"node_modules/@aws-sdk/client-sts": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.515.0.tgz",
|
||||||
"integrity": "sha512-0q08gsvn6nuRqjK+i/e30PT/t7vvYwmGJS0PhJikZWv5yRDNSUxSYG0uDwKSbLDzmc2UX5+mLeyjPHlL4hbGlA==",
|
"integrity": "sha512-ScYuvaIDgip3atOJIA1FU2n0gJkEdveu1KrrCPathoUCV5zpK8qQmO/n+Fj/7hKFxeKdFbB+4W4CsJWYH94nlg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-browser": "3.0.0",
|
"@aws-crypto/sha256-browser": "3.0.0",
|
||||||
"@aws-crypto/sha256-js": "3.0.0",
|
"@aws-crypto/sha256-js": "3.0.0",
|
||||||
"@aws-sdk/core": "3.496.0",
|
"@aws-sdk/core": "3.513.0",
|
||||||
"@aws-sdk/middleware-host-header": "3.502.0",
|
"@aws-sdk/middleware-host-header": "3.515.0",
|
||||||
"@aws-sdk/middleware-logger": "3.502.0",
|
"@aws-sdk/middleware-logger": "3.515.0",
|
||||||
"@aws-sdk/middleware-recursion-detection": "3.502.0",
|
"@aws-sdk/middleware-recursion-detection": "3.515.0",
|
||||||
"@aws-sdk/middleware-user-agent": "3.502.0",
|
"@aws-sdk/middleware-user-agent": "3.515.0",
|
||||||
"@aws-sdk/region-config-resolver": "3.502.0",
|
"@aws-sdk/region-config-resolver": "3.515.0",
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@aws-sdk/util-endpoints": "3.502.0",
|
"@aws-sdk/util-endpoints": "3.515.0",
|
||||||
"@aws-sdk/util-user-agent-browser": "3.502.0",
|
"@aws-sdk/util-user-agent-browser": "3.515.0",
|
||||||
"@aws-sdk/util-user-agent-node": "3.502.0",
|
"@aws-sdk/util-user-agent-node": "3.515.0",
|
||||||
"@smithy/config-resolver": "^2.1.1",
|
"@smithy/config-resolver": "^2.1.1",
|
||||||
"@smithy/core": "^1.3.1",
|
"@smithy/core": "^1.3.2",
|
||||||
"@smithy/fetch-http-handler": "^2.4.1",
|
"@smithy/fetch-http-handler": "^2.4.1",
|
||||||
"@smithy/hash-node": "^2.1.1",
|
"@smithy/hash-node": "^2.1.1",
|
||||||
"@smithy/invalid-dependency": "^2.1.1",
|
"@smithy/invalid-dependency": "^2.1.1",
|
||||||
@@ -399,7 +392,7 @@
|
|||||||
"@smithy/util-body-length-browser": "^2.1.1",
|
"@smithy/util-body-length-browser": "^2.1.1",
|
||||||
"@smithy/util-body-length-node": "^2.2.1",
|
"@smithy/util-body-length-node": "^2.2.1",
|
||||||
"@smithy/util-defaults-mode-browser": "^2.1.1",
|
"@smithy/util-defaults-mode-browser": "^2.1.1",
|
||||||
"@smithy/util-defaults-mode-node": "^2.1.1",
|
"@smithy/util-defaults-mode-node": "^2.2.0",
|
||||||
"@smithy/util-endpoints": "^1.1.1",
|
"@smithy/util-endpoints": "^1.1.1",
|
||||||
"@smithy/util-middleware": "^2.1.1",
|
"@smithy/util-middleware": "^2.1.1",
|
||||||
"@smithy/util-retry": "^2.1.1",
|
"@smithy/util-retry": "^2.1.1",
|
||||||
@@ -411,15 +404,15 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@aws-sdk/credential-provider-node": "*"
|
"@aws-sdk/credential-provider-node": "^3.515.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/core": {
|
"node_modules/@aws-sdk/core": {
|
||||||
"version": "3.496.0",
|
"version": "3.513.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.496.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.513.0.tgz",
|
||||||
"integrity": "sha512-yT+ug7Cw/3eJi7x2es0+46x12+cIJm5Xv+GPWsrTFD1TKgqO/VPEgfDtHFagDNbFmjNQA65Ygc/kEdIX9ICX/A==",
|
"integrity": "sha512-L+9DL4apWuqNKVOMJ8siAuWoRM9rZf9w1iPv8S2o83WO2jVK7E/m+rNW1dFo9HsA5V1ccDl2H2qLXx24HiHmOw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@smithy/core": "^1.3.1",
|
"@smithy/core": "^1.3.2",
|
||||||
"@smithy/protocol-http": "^3.1.1",
|
"@smithy/protocol-http": "^3.1.1",
|
||||||
"@smithy/signature-v4": "^2.1.1",
|
"@smithy/signature-v4": "^2.1.1",
|
||||||
"@smithy/smithy-client": "^2.3.1",
|
"@smithy/smithy-client": "^2.3.1",
|
||||||
@@ -431,11 +424,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/credential-provider-env": {
|
"node_modules/@aws-sdk/credential-provider-env": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.515.0.tgz",
|
||||||
"integrity": "sha512-KIB8Ae1Z7domMU/jU4KiIgK4tmYgvuXlhR54ehwlVHxnEoFPoPuGHFZU7oFn79jhhSLUFQ1lRYMxP0cEwb7XeQ==",
|
"integrity": "sha512-45vxdyqhTAaUMERYVWOziG3K8L2TV9G4ryQS/KZ84o7NAybE9GMdoZRVmGHAO7mJJ1wQiYCM/E+i5b3NW9JfNA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/property-provider": "^2.1.1",
|
"@smithy/property-provider": "^2.1.1",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
@@ -444,17 +437,36 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/credential-provider-ini": {
|
"node_modules/@aws-sdk/credential-provider-http": {
|
||||||
"version": "3.503.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.503.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.515.0.tgz",
|
||||||
"integrity": "sha512-sfmVLtUx+KDJ74jlbxW6dr1ysXh2EAESA+a5stFehgeXM1BeEdZc938wGcb8Mzm9w6li3IK0otXy8/R5TkQn3g==",
|
"integrity": "sha512-Ba6FXK77vU4WyheiamNjEuTFmir0eAXuJGPO27lBaA8g+V/seXGHScsbOG14aQGDOr2P02OPwKGZrWWA7BFpfQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sts": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@aws-sdk/credential-provider-env": "3.502.0",
|
"@smithy/fetch-http-handler": "^2.4.1",
|
||||||
"@aws-sdk/credential-provider-process": "3.502.0",
|
"@smithy/node-http-handler": "^2.3.1",
|
||||||
"@aws-sdk/credential-provider-sso": "3.502.0",
|
"@smithy/property-provider": "^2.1.1",
|
||||||
"@aws-sdk/credential-provider-web-identity": "3.502.0",
|
"@smithy/protocol-http": "^3.1.1",
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@smithy/smithy-client": "^2.3.1",
|
||||||
|
"@smithy/types": "^2.9.1",
|
||||||
|
"@smithy/util-stream": "^2.1.1",
|
||||||
|
"tslib": "^2.5.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@aws-sdk/credential-provider-ini": {
|
||||||
|
"version": "3.515.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.515.0.tgz",
|
||||||
|
"integrity": "sha512-ouDlNZdv2TKeVEA/YZk2+XklTXyAAGdbWnl4IgN9ItaodWI+lZjdIoNC8BAooVH+atIV/cZgoGTGQL7j2TxJ9A==",
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-sts": "3.515.0",
|
||||||
|
"@aws-sdk/credential-provider-env": "3.515.0",
|
||||||
|
"@aws-sdk/credential-provider-process": "3.515.0",
|
||||||
|
"@aws-sdk/credential-provider-sso": "3.515.0",
|
||||||
|
"@aws-sdk/credential-provider-web-identity": "3.515.0",
|
||||||
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/credential-provider-imds": "^2.2.1",
|
"@smithy/credential-provider-imds": "^2.2.1",
|
||||||
"@smithy/property-provider": "^2.1.1",
|
"@smithy/property-provider": "^2.1.1",
|
||||||
"@smithy/shared-ini-file-loader": "^2.3.1",
|
"@smithy/shared-ini-file-loader": "^2.3.1",
|
||||||
@@ -466,16 +478,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/credential-provider-node": {
|
"node_modules/@aws-sdk/credential-provider-node": {
|
||||||
"version": "3.503.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.503.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.515.0.tgz",
|
||||||
"integrity": "sha512-jE+QpqWU7ESxbKtWmeerv4ze7HntGcfh4PFscsy+O3QZYXXntzkDAne9wRvT38rfI+uVOGGNdCtz+8zSS3MaZw==",
|
"integrity": "sha512-Y4kHSpbxksiCZZNcvsiKUd8Fb2XlyUuONEwqWFNL82ZH6TCCjBGS31wJQCSxBHqYcOL3tiORUEJkoO7uS30uQA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/credential-provider-env": "3.502.0",
|
"@aws-sdk/credential-provider-env": "3.515.0",
|
||||||
"@aws-sdk/credential-provider-ini": "3.503.0",
|
"@aws-sdk/credential-provider-http": "3.515.0",
|
||||||
"@aws-sdk/credential-provider-process": "3.502.0",
|
"@aws-sdk/credential-provider-ini": "3.515.0",
|
||||||
"@aws-sdk/credential-provider-sso": "3.502.0",
|
"@aws-sdk/credential-provider-process": "3.515.0",
|
||||||
"@aws-sdk/credential-provider-web-identity": "3.502.0",
|
"@aws-sdk/credential-provider-sso": "3.515.0",
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/credential-provider-web-identity": "3.515.0",
|
||||||
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/credential-provider-imds": "^2.2.1",
|
"@smithy/credential-provider-imds": "^2.2.1",
|
||||||
"@smithy/property-provider": "^2.1.1",
|
"@smithy/property-provider": "^2.1.1",
|
||||||
"@smithy/shared-ini-file-loader": "^2.3.1",
|
"@smithy/shared-ini-file-loader": "^2.3.1",
|
||||||
@@ -487,11 +500,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/credential-provider-process": {
|
"node_modules/@aws-sdk/credential-provider-process": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.515.0.tgz",
|
||||||
"integrity": "sha512-fJJowOjQ4infYQX0E1J3xFVlmuwEYJAFk0Mo1qwafWmEthsBJs+6BR2RiWDELHKrSK35u4Pf3fu3RkYuCtmQFw==",
|
"integrity": "sha512-pSjiOA2FM63LHRKNDvEpBRp80FVGT0Mw/gzgbqFXP+sewk0WVonYbEcMDTJptH3VsLPGzqH/DQ1YL/aEIBuXFQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/property-provider": "^2.1.1",
|
"@smithy/property-provider": "^2.1.1",
|
||||||
"@smithy/shared-ini-file-loader": "^2.3.1",
|
"@smithy/shared-ini-file-loader": "^2.3.1",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
@@ -502,13 +515,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/credential-provider-sso": {
|
"node_modules/@aws-sdk/credential-provider-sso": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.515.0.tgz",
|
||||||
"integrity": "sha512-/2Nyvo+cWQpH283lmZBimTJ9JDhES9FzQUkhUXZgxQo3Ez4sguLVi2V9xoFFyG0cMff5fuNivdKHfj4FeMGjZw==",
|
"integrity": "sha512-j7vUkiSmuhpBvZYoPTRTI4ePnQbiZMFl6TNhg9b9DprC1zHkucsZnhRhqjOVlrw/H6J4jmcPGcHHTZ5WQNI5xQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sso": "3.502.0",
|
"@aws-sdk/client-sso": "3.515.0",
|
||||||
"@aws-sdk/token-providers": "3.502.0",
|
"@aws-sdk/token-providers": "3.515.0",
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/property-provider": "^2.1.1",
|
"@smithy/property-provider": "^2.1.1",
|
||||||
"@smithy/shared-ini-file-loader": "^2.3.1",
|
"@smithy/shared-ini-file-loader": "^2.3.1",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
@@ -519,12 +532,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/credential-provider-web-identity": {
|
"node_modules/@aws-sdk/credential-provider-web-identity": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.515.0.tgz",
|
||||||
"integrity": "sha512-veBAjDqjMMgA2Qxxf9ywDfHYLeJpaeHWLWCQ9XCHwJJ6ZIGWmAZPTq3he/UMr5JIQXooIccqqyqXMDIXPenXpA==",
|
"integrity": "sha512-66+2g4z3fWwdoGReY8aUHvm6JrKZMTRxjuizljVmMyOBttKPeBYXvUTop/g3ZGUx1f8j+C5qsGK52viYBvtjuQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sts": "3.502.0",
|
"@aws-sdk/client-sts": "3.515.0",
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/property-provider": "^2.1.1",
|
"@smithy/property-provider": "^2.1.1",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
@@ -534,11 +547,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/middleware-host-header": {
|
"node_modules/@aws-sdk/middleware-host-header": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.515.0.tgz",
|
||||||
"integrity": "sha512-EjnG0GTYXT/wJBmm5/mTjDcAkzU8L7wQjOzd3FTXuTCNNyvAvwrszbOj5FlarEw5XJBbQiZtBs+I5u9+zy560w==",
|
"integrity": "sha512-I1MwWPzdRKM1luvdDdjdGsDjNVPhj9zaIytEchjTY40NcKOg+p2evLD2y69ozzg8pyXK63r8DdvDGOo9QPuh0A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/protocol-http": "^3.1.1",
|
"@smithy/protocol-http": "^3.1.1",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
@@ -548,11 +561,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/middleware-logger": {
|
"node_modules/@aws-sdk/middleware-logger": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.515.0.tgz",
|
||||||
"integrity": "sha512-FDyv6K4nCoHxbjLGS2H8ex8I0KDIiu4FJgVRPs140ZJy6gE5Pwxzv6YTzZGLMrnqcIs9gh065Lf6DjwMelZqaw==",
|
"integrity": "sha512-qXomJzg2m/5seQOxHi/yOXOKfSjwrrJSmEmfwJKJyQgdMbBcjz3Cz0H/1LyC6c5hHm6a/SZgSTzDAbAoUmyL+Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
},
|
},
|
||||||
@@ -561,11 +574,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/middleware-recursion-detection": {
|
"node_modules/@aws-sdk/middleware-recursion-detection": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.515.0.tgz",
|
||||||
"integrity": "sha512-hvbyGJbxeuezxOu8VfFmcV4ql1hKXLxHTe5FNYfEBat2KaZXVhc1Hg+4TvB06/53p+E8J99Afmumkqbxs2esUA==",
|
"integrity": "sha512-dokHLbTV3IHRIBrw9mGoxcNTnQsjlm7TpkJhPdGT9T4Mq399EyQo51u6IsVMm07RXLl2Zw7u+u9p+qWBFzmFRA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/protocol-http": "^3.1.1",
|
"@smithy/protocol-http": "^3.1.1",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
@@ -574,30 +587,13 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/middleware-signing": {
|
|
||||||
"version": "3.502.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.502.0.tgz",
|
|
||||||
"integrity": "sha512-4hF08vSzJ7L6sB+393gOFj3s2N6nLusYS0XrMW6wYNFU10IDdbf8Z3TZ7gysDJJHEGQPmTAesPEDBsasGWcMxg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@aws-sdk/types": "3.502.0",
|
|
||||||
"@smithy/property-provider": "^2.1.1",
|
|
||||||
"@smithy/protocol-http": "^3.1.1",
|
|
||||||
"@smithy/signature-v4": "^2.1.1",
|
|
||||||
"@smithy/types": "^2.9.1",
|
|
||||||
"@smithy/util-middleware": "^2.1.1",
|
|
||||||
"tslib": "^2.5.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@aws-sdk/middleware-user-agent": {
|
"node_modules/@aws-sdk/middleware-user-agent": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.515.0.tgz",
|
||||||
"integrity": "sha512-TxbBZbRiXPH0AUxegqiNd9aM9zNSbfjtBs5MEfcBsweeT/B2O7K1EjP9+CkB8Xmk/5FLKhAKLr19b1TNoE27rw==",
|
"integrity": "sha512-nOqZjGA/GkjuJ5fUshec9Fv6HFd7ovOTxMJbw3MfAhqXuVZ6dKF41lpVJ4imNsgyFt3shUg9WDY8zGFjlYMB3g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@aws-sdk/util-endpoints": "3.502.0",
|
"@aws-sdk/util-endpoints": "3.515.0",
|
||||||
"@smithy/protocol-http": "^3.1.1",
|
"@smithy/protocol-http": "^3.1.1",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
@@ -607,11 +603,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/region-config-resolver": {
|
"node_modules/@aws-sdk/region-config-resolver": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.515.0.tgz",
|
||||||
"integrity": "sha512-mxmsX2AGgnSM+Sah7mcQCIneOsJQNiLX0COwEttuf8eO+6cLMAZvVudH3BnWTfea4/A9nuri9DLCqBvEmPrilg==",
|
"integrity": "sha512-RIRx9loxMgEAc/r1wPfnfShOuzn4RBi8pPPv6/jhhITEeMnJe6enAh2k5y9DdiVDDgCWZgVFSv0YkAIfzAFsnQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/node-config-provider": "^2.2.1",
|
"@smithy/node-config-provider": "^2.2.1",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"@smithy/util-config-provider": "^2.2.1",
|
"@smithy/util-config-provider": "^2.2.1",
|
||||||
@@ -623,12 +619,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/token-providers": {
|
"node_modules/@aws-sdk/token-providers": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.515.0.tgz",
|
||||||
"integrity": "sha512-RQgMgIXYlSf0xGl6EUeD+pqIPBlb7e29dbqHOBFc66hJVYUC2ULZX7Y+jLvcGIEaMiIaTPyvntZRFip+U+9hag==",
|
"integrity": "sha512-MQuf04rIcTXqwDzmyHSpFPF1fKEzRl64oXtCRUF3ddxTdK6wxXkePfK6wNCuL+GEbEcJAoCtIGIRpzGPJvQjHA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sso-oidc": "3.502.0",
|
"@aws-sdk/client-sso-oidc": "3.515.0",
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/property-provider": "^2.1.1",
|
"@smithy/property-provider": "^2.1.1",
|
||||||
"@smithy/shared-ini-file-loader": "^2.3.1",
|
"@smithy/shared-ini-file-loader": "^2.3.1",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
@@ -639,9 +635,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/types": {
|
"node_modules/@aws-sdk/types": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.515.0.tgz",
|
||||||
"integrity": "sha512-M0DSPYe/gXhwD2QHgoukaZv5oDxhW3FfvYIrJptyqUq3OnPJBcDbihHjrE0PBtfh/9kgMZT60/fQ2NVFANfa2g==",
|
"integrity": "sha512-B3gUpiMlpT6ERaLvZZ61D0RyrQPsFYDkCncLPVkZOKkCOoFU46zi1o6T5JcYiz8vkx1q9RGloQ5exh79s5pU/w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
@@ -651,11 +647,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/util-endpoints": {
|
"node_modules/@aws-sdk/util-endpoints": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.515.0.tgz",
|
||||||
"integrity": "sha512-6LKFlJPp2J24r1Kpfoz5ESQn+1v5fEjDB3mtUKRdpwarhm3syu7HbKlHCF3KbcCOyahobvLvhoedT78rJFEeeg==",
|
"integrity": "sha512-UJi+jdwcGFV/F7d3+e2aQn5yZOVpDiAgfgNhPnEtgV0WozJ5/ZUeZBgWvSc/K415N4A4D/9cbBc7+I+35qzcDQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"@smithy/util-endpoints": "^1.1.1",
|
"@smithy/util-endpoints": "^1.1.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
@@ -676,22 +672,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/util-user-agent-browser": {
|
"node_modules/@aws-sdk/util-user-agent-browser": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.515.0.tgz",
|
||||||
"integrity": "sha512-v8gKyCs2obXoIkLETAeEQ3AM+QmhHhst9xbM1cJtKUGsRlVIak/XyyD+kVE6kmMm1cjfudHpHKABWk9apQcIZQ==",
|
"integrity": "sha512-pTWQb0JCafTmLHLDv3Qqs/nAAJghcPdGQIBpsCStb0YEzg3At/dOi2AIQ683yYnXmeOxLXJDzmlsovfVObJScw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"bowser": "^2.11.0",
|
"bowser": "^2.11.0",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aws-sdk/util-user-agent-node": {
|
"node_modules/@aws-sdk/util-user-agent-node": {
|
||||||
"version": "3.502.0",
|
"version": "3.515.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.502.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.515.0.tgz",
|
||||||
"integrity": "sha512-9RjxpkGZKbTdl96tIJvAo+vZoz4P/cQh36SBUt9xfRfW0BtsaLyvSrvlR5wyUYhvRcC12Axqh/8JtnAPq//+Vw==",
|
"integrity": "sha512-A/KJ+/HTohHyVXLH+t/bO0Z2mPrQgELbQO8tX+B2nElo8uklj70r5cT7F8ETsI9oOy+HDVpiL5/v45ZgpUOiPg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/types": "3.502.0",
|
"@aws-sdk/types": "3.515.0",
|
||||||
"@smithy/node-config-provider": "^2.2.1",
|
"@smithy/node-config-provider": "^2.2.1",
|
||||||
"@smithy/types": "^2.9.1",
|
"@smithy/types": "^2.9.1",
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
@@ -1231,9 +1227,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@smithy/core": {
|
"node_modules/@smithy/core": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.3.2.tgz",
|
||||||
"integrity": "sha512-tf+NIu9FkOh312b6M9G4D68is4Xr7qptzaZGZUREELF8ysE1yLKphqt7nsomjKZVwW7WE5pDDex9idowNGRQ/Q==",
|
"integrity": "sha512-tYDmTp0f2TZVE18jAOH1PnmkngLQ+dOGUlMd1u67s87ieueNeyqhja6z/Z4MxhybEiXKOWFOmGjfTZWFxljwJw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@smithy/middleware-endpoint": "^2.4.1",
|
"@smithy/middleware-endpoint": "^2.4.1",
|
||||||
"@smithy/middleware-retry": "^2.1.1",
|
"@smithy/middleware-retry": "^2.1.1",
|
||||||
@@ -1627,9 +1623,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@smithy/util-defaults-mode-node": {
|
"node_modules/@smithy/util-defaults-mode-node": {
|
||||||
"version": "2.1.1",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.2.0.tgz",
|
||||||
"integrity": "sha512-tYVrc+w+jSBfBd267KDnvSGOh4NMz+wVH7v4CClDbkdPfnjvImBZsOURncT5jsFwR9KCuDyPoSZq4Pa6+eCUrA==",
|
"integrity": "sha512-iFJp/N4EtkanFpBUtSrrIbtOIBf69KNuve03ic1afhJ9/korDxdM0c6cCH4Ehj/smI9pDCfVv+bqT3xZjF2WaA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@smithy/config-resolver": "^2.1.1",
|
"@smithy/config-resolver": "^2.1.1",
|
||||||
"@smithy/credential-provider-imds": "^2.2.1",
|
"@smithy/credential-provider-imds": "^2.2.1",
|
||||||
@@ -2409,11 +2405,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cloudinary": {
|
"node_modules/cloudinary": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.0.1.tgz",
|
||||||
"integrity": "sha512-NUbufckg2GiuJjB0DVGFBRNLt4jl+2nOA1KeZv1ub8FCduNFvkcdGF1t9JKeoVVM8Po9wYvjICcecMsjQVq1Jw==",
|
"integrity": "sha512-+j5GswtCwjAmLhjs/K26id4Zvh53zL/YWzgyenxgbdXdXmdFM8d5H1FV1sJCkpS77AqylJKBzyztySdILM+F+A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cloudinary-core": "^2.13.0",
|
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"q": "^1.5.1"
|
"q": "^1.5.1"
|
||||||
},
|
},
|
||||||
@@ -2421,14 +2416,6 @@
|
|||||||
"node": ">=9"
|
"node": ">=9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cloudinary-core": {
|
|
||||||
"version": "2.13.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/cloudinary-core/-/cloudinary-core-2.13.0.tgz",
|
|
||||||
"integrity": "sha512-Nt0Q5I2FtenmJghtC4YZ3MZZbGg1wLm84SsxcuVwZ83OyJqG9CNIGp86CiI6iDv3QobaqBUpOT7vg+HqY5HxEA==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"lodash": ">=4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/color": {
|
"node_modules/color": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||||
@@ -3024,14 +3011,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dotenv": {
|
"node_modules/dotenv": {
|
||||||
"version": "16.4.1",
|
"version": "16.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
|
||||||
"integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==",
|
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/motdotla/dotenv?sponsor=1"
|
"url": "https://dotenvx.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/duplexer": {
|
"node_modules/duplexer": {
|
||||||
@@ -4373,9 +4360,9 @@
|
|||||||
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
|
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
|
||||||
},
|
},
|
||||||
"node_modules/json-2-csv": {
|
"node_modules/json-2-csv": {
|
||||||
"version": "5.0.1",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/json-2-csv/-/json-2-csv-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-2-csv/-/json-2-csv-5.2.0.tgz",
|
||||||
"integrity": "sha512-rP9ChyMskS0angbvFdQ43SwEe72mEvqcY1/V2OeukQWxtlreUuZWhMlTdWjtd4L6kJxq+HPFTI06yqLvZiEVIA==",
|
"integrity": "sha512-C+XmSKRCS7zSTENm7Ha/lhLkO2ZE+fcSNC2kLiWSEGKy6ZwRCG2KakMJj0bvyfy2U8oZY+KFoU8F1isCgpUBYg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"deeks": "3.0.2",
|
"deeks": "3.0.2",
|
||||||
"doc-path": "4.0.2"
|
"doc-path": "4.0.2"
|
||||||
@@ -4778,9 +4765,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/moment-timezone": {
|
"node_modules/moment-timezone": {
|
||||||
"version": "0.5.44",
|
"version": "0.5.45",
|
||||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.44.tgz",
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz",
|
||||||
"integrity": "sha512-nv3YpzI/8lkQn0U6RkLd+f0W/zy/JnoR5/EyPz/dNkPTBjA2jNLCVxaiQ8QpeLymhSZvX0wCL5s27NQWdOPwAw==",
|
"integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"moment": "^2.29.4"
|
"moment": "^2.29.4"
|
||||||
},
|
},
|
||||||
@@ -4921,9 +4908,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nodemailer": {
|
"node_modules/nodemailer": {
|
||||||
"version": "6.9.8",
|
"version": "6.9.10",
|
||||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.8.tgz",
|
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.10.tgz",
|
||||||
"integrity": "sha512-cfrYUk16e67Ks051i4CntM9kshRYei1/o/Gi8K1d+R34OIs21xdFnW7Pt7EucmVKA0LKtqUGNcjMZ7ehjl49mQ==",
|
"integrity": "sha512-qtoKfGFhvIFW5kLfrkw2R6Nm6Ur4LNUMykyqu6n9BRKJuyQrqEGwdXXUAbwWEKt33dlWUGXb7rzmJP/p4+O+CA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
@@ -6325,9 +6312,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/stripe": {
|
"node_modules/stripe": {
|
||||||
"version": "14.14.0",
|
"version": "14.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/stripe/-/stripe-14.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/stripe/-/stripe-14.18.0.tgz",
|
||||||
"integrity": "sha512-P6lvKHxgDzZXto9VMstG1ucv4Ls0U9nOoQhVZABXJ33kRD7zMwkBy5Y4c3BO59O230uSTkOFPLh87YxVzkp0Mg==",
|
"integrity": "sha512-yLqKPqYgGJbMxrQiE4+i2i00ZVA2NRIZbZ1rejzj5XR3F3Uc+1iy9QE133knZudhVGMw367b8vTpB8D9pYMETw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": ">=8.1.0",
|
"@types/node": ">=8.1.0",
|
||||||
"qs": "^6.11.0"
|
"qs": "^6.11.0"
|
||||||
@@ -6620,9 +6607,9 @@
|
|||||||
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
|
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
|
||||||
},
|
},
|
||||||
"node_modules/twilio": {
|
"node_modules/twilio": {
|
||||||
"version": "4.21.0",
|
"version": "4.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/twilio/-/twilio-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/twilio/-/twilio-4.22.0.tgz",
|
||||||
"integrity": "sha512-+meDbJPOxs6vEysJ7xX7XMn6FLKmZFSeVzMKjzN9NWgDXssp713Kf1ukteZlXhnhd7/NtNiUv5OU17qVgBb/BQ==",
|
"integrity": "sha512-Dn4x9FxhuCorz2ddJ8/Z8o3G0rLmrQo0frF1MMwWqtLrOwQzhL7Ca/Fup8jqbfjD+JSG1L8DE9a3MGBDETDrNg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
"dayjs": "^1.11.9",
|
"dayjs": "^1.11.9",
|
||||||
|
|||||||
20
package.json
20
package.json
@@ -18,21 +18,21 @@
|
|||||||
"start": "node server.js"
|
"start": "node server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-secrets-manager": "^3.503.0",
|
"@aws-sdk/client-secrets-manager": "^3.515.0",
|
||||||
"@aws-sdk/client-ses": "^3.503.0",
|
"@aws-sdk/client-ses": "^3.515.0",
|
||||||
"@aws-sdk/credential-provider-node": "^3.503.0",
|
"@aws-sdk/credential-provider-node": "^3.515.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.0",
|
"cloudinary": "^2.0.1",
|
||||||
"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.1",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"firebase-admin": "^12.0.0",
|
"firebase-admin": "^12.0.0",
|
||||||
"graphql": "^16.8.1",
|
"graphql": "^16.8.1",
|
||||||
@@ -40,23 +40,23 @@
|
|||||||
"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.0.1",
|
"json-2-csv": "^5.2.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"moment-timezone": "^0.5.44",
|
"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.43",
|
||||||
"nodemailer": "^6.9.8",
|
"nodemailer": "^6.9.10",
|
||||||
"phone": "^3.1.42",
|
"phone": "^3.1.42",
|
||||||
"recursive-diff": "^1.0.9",
|
"recursive-diff": "^1.0.9",
|
||||||
"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.11.0",
|
"stripe": "^14.18.0",
|
||||||
"twilio": "^4.20.0",
|
"twilio": "^4.22.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"
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ async function JobCostingMulti(req, res) {
|
|||||||
|
|
||||||
logger.log("job-costing-multi-start", "DEBUG", req.user.email, jobids, null);
|
logger.log("job-costing-multi-start", "DEBUG", req.user.email, jobids, null);
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await client
|
const resp = await client
|
||||||
.setHeaders({Authorization: BearerToken})
|
.setHeaders({Authorization: BearerToken})
|
||||||
|
|||||||
Reference in New Issue
Block a user