Merge remote-tracking branch 'origin/master-AIO' into feature/IO-2742-redis

This commit is contained in:
Dave Richer
2024-09-09 11:39:48 -04:00
4 changed files with 452 additions and 435 deletions

View File

@@ -5,6 +5,7 @@ orbs:
aws-s3: circleci/aws-s3@4.0.0 aws-s3: circleci/aws-s3@4.0.0
aws-cli: circleci/aws-cli@4.0 aws-cli: circleci/aws-cli@4.0
eb: circleci/aws-elastic-beanstalk@2.0.1 eb: circleci/aws-elastic-beanstalk@2.0.1
jira: circleci/jira@2.1.0
jobs: jobs:
imex-api-deploy: imex-api-deploy:
docker: docker:
@@ -18,6 +19,12 @@ jobs:
eb status --verbose eb status --verbose
eb deploy eb deploy
eb status eb status
- jira/notify:
environment: Production (ImEX) - API
environment_type: production
job_type: deployment
pipeline_id: << pipeline.id >>
pipeline_number: << pipeline.number >>
imex-hasura-migrate: imex-hasura-migrate:
docker: docker:
@@ -33,11 +40,16 @@ jobs:
- run: - run:
name: Execute migration name: Execute migration
command: | command: |
npm install hasura-cli -g curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
hasura migrate apply --endpoint https://db.imex.online/ --admin-secret << parameters.secret >> hasura migrate apply --endpoint https://db.imex.online/ --admin-secret << parameters.secret >>
hasura metadata apply --endpoint https://db.imex.online/ --admin-secret << parameters.secret >> hasura metadata apply --endpoint https://db.imex.online/ --admin-secret << parameters.secret >>
hasura metadata reload --endpoint https://db.imex.online/ --admin-secret << parameters.secret >> hasura metadata reload --endpoint https://db.imex.online/ --admin-secret << parameters.secret >>
- jira/notify:
environment: Production (ImEX) - Hasura
environment_type: production
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
imex-app-build: imex-app-build:
docker: docker:
- image: cimg/node:18.18.2 - image: cimg/node:18.18.2
@@ -62,6 +74,7 @@ jobs:
to: "s3://imex-online-production/" to: "s3://imex-online-production/"
arguments: "--exclude '*.map'" arguments: "--exclude '*.map'"
imex-app-beta-build: imex-app-beta-build:
docker: docker:
- image: cimg/node:18.18.2 - image: cimg/node:18.18.2
@@ -86,6 +99,12 @@ jobs:
from: dist from: dist
to: "s3://imex-online-beta/" to: "s3://imex-online-beta/"
arguments: "--exclude '*.map'" arguments: "--exclude '*.map'"
- jira/notify:
environment: Production (ImEX) - Front End
environment_type: production
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
rome-api-deploy: rome-api-deploy:
docker: docker:
@@ -99,7 +118,12 @@ jobs:
eb status --verbose eb status --verbose
eb deploy eb deploy
eb status eb status
- jira/notify:
environment: Production (Rome) - API
environment_type: production
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
rome-hasura-migrate: rome-hasura-migrate:
docker: docker:
- image: cimg/node:18.18.2 - image: cimg/node:18.18.2
@@ -114,11 +138,16 @@ jobs:
- run: - run:
name: Execute migration name: Execute migration
command: | command: |
npm install hasura-cli -g curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
hasura migrate apply --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >> hasura migrate apply --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
hasura metadata apply --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >> hasura metadata apply --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
hasura metadata reload --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >> hasura metadata reload --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
- jira/notify:
environment: Production (Rome) - Hasura
environment_type: production
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
rome-app-build: rome-app-build:
docker: docker:
- image: cimg/node:18.18.2 - image: cimg/node:18.18.2
@@ -143,6 +172,12 @@ jobs:
from: dist from: dist
to: "s3://rome-online-production/" to: "s3://rome-online-production/"
arguments: "--exclude '*.map'" arguments: "--exclude '*.map'"
- jira/notify:
environment: Production (Rome) - Front End
environment_type: production
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
promanager-app-build: promanager-app-build:
docker: docker:
@@ -168,6 +203,12 @@ jobs:
from: dist from: dist
to: "s3://promanager-production/" to: "s3://promanager-production/"
arguments: "--exclude '*.map'" arguments: "--exclude '*.map'"
- jira/notify:
environment: Production (ProManager) - Front End
environment_type: production
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
test-rome-hasura-migrate: test-rome-hasura-migrate:
docker: docker:
@@ -183,10 +224,16 @@ jobs:
- run: - run:
name: Execute migration name: Execute migration
command: | command: |
npm install hasura-cli -g curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
hasura migrate apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >> hasura migrate apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
hasura metadata apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >> hasura metadata apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
hasura metadata reload --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >> hasura metadata reload --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
- jira/notify:
environment: Test (Rome) - Hasura
environment_type: testing
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
test-rome-app-build: test-rome-app-build:
docker: docker:
@@ -212,6 +259,12 @@ jobs:
from: dist from: dist
to: "s3://rome-online-test/" to: "s3://rome-online-test/"
arguments: "--exclude '*.map'" arguments: "--exclude '*.map'"
- jira/notify:
environment: Test (Rome) - Front End
environment_type: testing
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
test-promanager-app-build: test-promanager-app-build:
docker: docker:
@@ -237,6 +290,12 @@ jobs:
from: dist from: dist
to: "s3://promanager-testing/" to: "s3://promanager-testing/"
arguments: "--exclude '*.map'" arguments: "--exclude '*.map'"
- jira/notify:
environment: Test (ProManager) - Front End
environment_type: testing
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
test-hasura-migrate: test-hasura-migrate:
docker: docker:
@@ -252,10 +311,16 @@ jobs:
- run: - run:
name: Execute migration name: Execute migration
command: | command: |
npm install hasura-cli -g curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
hasura migrate apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >> hasura migrate apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
hasura metadata apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >> hasura metadata apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
hasura metadata reload --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >> hasura metadata reload --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
- jira/notify:
environment: Test (ImEX) - Hasura
environment_type: testing
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
imex-test-app-build: imex-test-app-build:
docker: docker:
@@ -302,7 +367,12 @@ jobs:
from: dist from: dist
to: "s3://imex-online-test-beta/" to: "s3://imex-online-test-beta/"
arguments: "--exclude '*.map'" arguments: "--exclude '*.map'"
- jira/notify:
environment: Test (ImEX) - Front End
environment_type: testing
pipeline_id: << pipeline.id >>
job_type: deployment
pipeline_number: << pipeline.number >>
admin-app-build: admin-app-build:
docker: docker:

View File

@@ -6,11 +6,11 @@ import {
PauseCircleOutlined PauseCircleOutlined
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Card, Col, Row, Space, Tooltip } from "antd"; import { Card, Col, Row, Space, Tooltip } from "antd";
import Dinero from "dinero.js";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { DateTimeFormatter } from "../../utils/DateFormatter"; import { DateTimeFormatter } from "../../utils/DateFormatter";
import Dinero from "dinero.js";
import ProductionAlert from "../production-list-columns/production-list-columns.alert.component"; import ProductionAlert from "../production-list-columns/production-list-columns.alert.component";
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component"; import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
@@ -18,8 +18,8 @@ import ProductionSubletsManageComponent from "../production-sublets-manage/produ
import dayjs from "../../utils/day"; import dayjs from "../../utils/day";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component"; import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
const cardColor = (ssbuckets, totalHrs) => { const cardColor = (ssbuckets, totalHrs) => {
const bucket = ssbuckets.find((bucket) => bucket.gte <= totalHrs && (!bucket.lt || bucket.lt > totalHrs)); const bucket = ssbuckets.find((bucket) => bucket.gte <= totalHrs && (!bucket.lt || bucket.lt > totalHrs));
@@ -213,21 +213,13 @@ const EstimatorToolTip = ({ metadata, cardSettings }) => {
}; };
const SubtotalTooltip = ({ metadata, cardSettings, t }) => { const SubtotalTooltip = ({ metadata, cardSettings, t }) => {
const amount = metadata?.job_totals?.totals?.subtotal?.amount; const dineroAmount = Dinero(metadata?.job_totals?.totals?.subtotal ?? Dinero()).toFormat();
const dineroAmount = amount ? Dinero({ amount: parseInt(amount * 100) }).toFormat("0,0.00") : null;
return ( return (
cardSettings?.subtotal && ( cardSettings?.subtotal && (
<Col span={cardSettings.compact ? 24 : 12}> <Col span={cardSettings.compact ? 24 : 12}>
<EllipsesToolTip <EllipsesToolTip title={`${dineroAmount}`} kiosk={cardSettings.kiosk}>
title={!!amount ? `${t("production.statistics.currency_symbol")}${dineroAmount}` : null} {dineroAmount}
kiosk={cardSettings.kiosk}
>
{!!amount ? (
<span>{`${t("production.statistics.currency_symbol")}${dineroAmount}`}</span>
) : (
<span>&nbsp;</span>
)}
</EllipsesToolTip> </EllipsesToolTip>
</Col> </Col>
) )

View File

@@ -30,219 +30,226 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
return ( return (
<RbacWrapper action="shop:rbac"> <RbacWrapper action="shop:rbac">
<LayoutFormRow> <LayoutFormRow>
{...HasFeatureAccess({ featureName: "export", bodyshop }) ? [ {...HasFeatureAccess({ featureName: "export", bodyshop })
<Form.Item ? [
label={t("bodyshop.fields.rbac.accounting.exportlog")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.accounting.exportlog")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "accounting:exportlog"]} ]}
> name={["md_rbac", "accounting:exportlog"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.accounting.payables")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.accounting.payables")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "accounting:payables"]} ]}
> name={["md_rbac", "accounting:payables"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.accounting.payments")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.accounting.payments")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "accounting:payments"]} ]}
> name={["md_rbac", "accounting:payments"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.accounting.receivables")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.accounting.receivables")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "accounting:receivables"]} ]}
> name={["md_rbac", "accounting:receivables"]}
<InputNumber /> >
</Form.Item> <InputNumber />
]:[]} </Form.Item>
{...HasFeatureAccess({ featureName: "bills", bodyshop }) ? [ ]
<Form.Item : []}
label={t("bodyshop.fields.rbac.bills.delete")} {...HasFeatureAccess({ featureName: "bills", bodyshop })
rules={[ ? [
{ <Form.Item
required: true label={t("bodyshop.fields.rbac.bills.delete")}
//message: t("general.validation.required"), rules={[
} {
]} required: true
name={["md_rbac", "bills:delete"]} //message: t("general.validation.required"),
> }
<InputNumber /> ]}
</Form.Item>, name={["md_rbac", "bills:delete"]}
<Form.Item >
label={t("bodyshop.fields.rbac.bills.enter")} <InputNumber />
rules={[ </Form.Item>,
{ <Form.Item
required: true label={t("bodyshop.fields.rbac.bills.enter")}
//message: t("general.validation.required"), rules={[
} {
]} required: true
name={["md_rbac", "bills:enter"]} //message: t("general.validation.required"),
> }
<InputNumber /> ]}
</Form.Item>, name={["md_rbac", "bills:enter"]}
<Form.Item >
label={t("bodyshop.fields.rbac.bills.list")} <InputNumber />
rules={[ </Form.Item>,
{ <Form.Item
required: true label={t("bodyshop.fields.rbac.bills.list")}
//message: t("general.validation.required"), rules={[
} {
]} required: true
name={["md_rbac", "bills:list"]} //message: t("general.validation.required"),
> }
<InputNumber /> ]}
</Form.Item>, name={["md_rbac", "bills:list"]}
<Form.Item >
label={t("bodyshop.fields.rbac.bills.reexport")} <InputNumber />
rules={[ </Form.Item>,
{ <Form.Item
required: true label={t("bodyshop.fields.rbac.bills.reexport")}
//message: t("general.validation.required"), rules={[
} {
]} required: true
name={["md_rbac", "bills:reexport"]} //message: t("general.validation.required"),
> }
<InputNumber /> ]}
</Form.Item>, name={["md_rbac", "bills:reexport"]}
<Form.Item >
label={t("bodyshop.fields.rbac.bills.view")} <InputNumber />
rules={[ </Form.Item>,
{ <Form.Item
required: true label={t("bodyshop.fields.rbac.bills.view")}
//message: t("general.validation.required"), rules={[
} {
]} required: true
name={["md_rbac", "bills:view"]} //message: t("general.validation.required"),
> }
<InputNumber /> ]}
</Form.Item> name={["md_rbac", "bills:view"]}
]:[]} >
<InputNumber />
{...HasFeatureAccess({ featureName: "courtesycars", bodyshop }) ? [ </Form.Item>
<Form.Item ]
label={t("bodyshop.fields.rbac.contracts.create")} : []}
rules={[ {...HasFeatureAccess({ featureName: "courtesycars", bodyshop })
{ ? [
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.contracts.create")}
} rules={[
]} {
name={["md_rbac", "contracts:create"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item>, ]}
<Form.Item name={["md_rbac", "contracts:create"]}
label={t("bodyshop.fields.rbac.contracts.detail")} >
rules={[ <InputNumber />
{ </Form.Item>,
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.contracts.detail")}
} rules={[
]} {
name={["md_rbac", "contracts:detail"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item>, ]}
<Form.Item name={["md_rbac", "contracts:detail"]}
label={t("bodyshop.fields.rbac.contracts.list")} >
rules={[ <InputNumber />
{ </Form.Item>,
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.contracts.list")}
} rules={[
]} {
name={["md_rbac", "contracts:list"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item>, ]}
<Form.Item name={["md_rbac", "contracts:list"]}
label={t("bodyshop.fields.rbac.courtesycar.create")} >
rules={[ <InputNumber />
{ </Form.Item>,
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.courtesycar.create")}
} rules={[
]} {
name={["md_rbac", "courtesycar:create"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item>, ]}
<Form.Item name={["md_rbac", "courtesycar:create"]}
label={t("bodyshop.fields.rbac.courtesycar.detail")} >
rules={[ <InputNumber />
{ </Form.Item>,
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.courtesycar.detail")}
} rules={[
]} {
name={["md_rbac", "courtesycar:detail"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item>, ]}
<Form.Item name={["md_rbac", "courtesycar:detail"]}
label={t("bodyshop.fields.rbac.courtesycar.list")} >
rules={[ <InputNumber />
{ </Form.Item>,
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.courtesycar.list")}
} rules={[
]} {
name={["md_rbac", "courtesycar:list"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item> ]}
]:[]} name={["md_rbac", "courtesycar:list"]}
{...HasFeatureAccess({ featureName: "csi", bodyshop }) ? [ >
<Form.Item <InputNumber />
label={t("bodyshop.fields.rbac.csi.export")} </Form.Item>
rules={[ ]
{ : []}
required: true {...HasFeatureAccess({ featureName: "csi", bodyshop })
//message: t("general.validation.required"), ? [
} <Form.Item
]} label={t("bodyshop.fields.rbac.csi.export")}
name={["md_rbac", "csi:export"]} rules={[
> {
<InputNumber /> required: true
</Form.Item>, //message: t("general.validation.required"),
<Form.Item }
label={t("bodyshop.fields.rbac.csi.page")} ]}
rules={[ name={["md_rbac", "csi:export"]}
{ >
required: true <InputNumber />
//message: t("general.validation.required"), </Form.Item>,
} <Form.Item
]} label={t("bodyshop.fields.rbac.csi.page")}
name={["md_rbac", "csi:page"]} rules={[
> {
<InputNumber /> required: true
</Form.Item> //message: t("general.validation.required"),
]:[]} }
]}
name={["md_rbac", "csi:page"]}
>
<InputNumber />
</Form.Item>
]
: []}
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.employees.page")} label={t("bodyshop.fields.rbac.employees.page")}
rules={[ rules={[
@@ -255,6 +262,18 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.employee_teams.page")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "employee_teams:page"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.jobs.admin")} label={t("bodyshop.fields.rbac.jobs.admin")}
rules={[ rules={[
@@ -435,31 +454,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.employees.page")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "employees:page"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.employee_teams.page")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "employee_teams:page"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.payments.enter")} label={t("bodyshop.fields.rbac.payments.enter")}
rules={[ rules={[
@@ -522,7 +516,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
)} )}
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.production.list")} label={t("bodyshop.fields.rbac.production.list")}
rules={[ rules={[
@@ -561,128 +554,118 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
)} )}
{...HasFeatureAccess({ featureName: "timetickets", bodyshop }) ? [ {...HasFeatureAccess({ featureName: "timetickets", bodyshop })
<Form.Item ? [
label={t("bodyshop.fields.rbac.shiftclock.view")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.shiftclock.view")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "shiftclock:view"]} ]}
> name={["md_rbac", "shiftclock:view"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.shop.config")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.shop.config")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "shop:config"]} ]}
> name={["md_rbac", "shop:config"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.timetickets.edit")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.timetickets.edit")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "timetickets:edit"]} ]}
> name={["md_rbac", "timetickets:edit"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.timetickets.shiftedit")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "timetickets:shiftedit"]} ]}
> name={["md_rbac", "timetickets:shiftedit"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.timetickets.editcommitted")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.timetickets.editcommitted")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "timetickets:editcommitted"]} ]}
> name={["md_rbac", "timetickets:editcommitted"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.ttapprovals.view")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.ttapprovals.view")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "ttapprovals:view"]} ]}
> name={["md_rbac", "ttapprovals:view"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.ttapprovals.approve")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.ttapprovals.approve")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "ttapprovals:approve"]} ]}
> name={["md_rbac", "ttapprovals:approve"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.timetickets.enter")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.timetickets.enter")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "timetickets:enter"]} ]}
> name={["md_rbac", "timetickets:enter"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>,
label={t("bodyshop.fields.rbac.timetickets.list")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.timetickets.list")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "timetickets:list"]} ]}
> name={["md_rbac", "timetickets:list"]}
<InputNumber /> >
</Form.Item>, <InputNumber />
<Form.Item </Form.Item>
label={t("bodyshop.fields.rbac.timetickets.shiftedit")} ]
rules={[ : []}
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "timetickets:shiftedit"]}
>
<InputNumber />
</Form.Item>
]:[]}
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.shop.vendors")} label={t("bodyshop.fields.rbac.shop.vendors")}
rules={[ rules={[
@@ -757,7 +740,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
)} )}
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.users.editaccess")} label={t("bodyshop.fields.rbac.users.editaccess")}
rules={[ rules={[

View File

@@ -12,7 +12,7 @@ import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
import { onlyUnique } from "../../utils/arrayHelper"; import { onlyUnique } from "../../utils/arrayHelper";
import dayjs from "../../utils/day"; import dayjs from "../../utils/day";
import { alphaSort, dateSort } from "../../utils/sorters"; import { alphaSort, dateSort } from "../../utils/sorters";
import RbacWrapper, { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component"; import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter-button.component"; import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter-button.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
@@ -52,6 +52,10 @@ export function TimeTicketList({
splitKey: bodyshop.imexshopid splitKey: bodyshop.imexshopid
}); });
const canEditCommittedTimeTickets = HasRbacAccess({ bodyshop, authLevel, action: "timetickets:editcommitted" });
const canEditTimeTickets = HasRbacAccess({ bodyshop, authLevel, action: "timetickets:edit" });
const canEditShiftTickets = HasRbacAccess({ bodyshop, authLevel, action: "timetickets:shiftedit" });
const totals = useMemo(() => { const totals = useMemo(() => {
if (timetickets) if (timetickets)
return timetickets.reduce( return timetickets.reduce(
@@ -65,6 +69,18 @@ export function TimeTicketList({
return { productivehrs: 0, actualhrs: 0 }; return { productivehrs: 0, actualhrs: 0 };
}, [timetickets]); }, [timetickets]);
const isDisabled = (record) => {
if (disabled === true || !record.id) return true;
const isShiftTicket = !record.ciecacode;
const isCommitted = record.committed_at;
if (isShiftTicket) {
return !(canEditShiftTickets && (!isCommitted || canEditCommittedTimeTickets));
}
return !(canEditTimeTickets && (!isCommitted || canEditCommittedTimeTickets));
};
const columns = [ const columns = [
...(Enhanced_Payroll.treatment === "on" ...(Enhanced_Payroll.treatment === "on"
? [ ? [
@@ -241,59 +257,16 @@ export function TimeTicketList({
</TimeTicketEnterButton> </TimeTicketEnterButton>
)} )}
{!techConsole && ( {!techConsole && (
<RbacWrapper <TimeTicketEnterButton
action="timetickets:edit" actions={{ refetch }}
noauth={() => { context={{
return <div />; id: record.id,
timeticket: record
}} }}
disabled={isDisabled(record)}
> >
<TimeTicketEnterButton <EditFilled />
actions={{ refetch }} </TimeTicketEnterButton>
context={{
id: record.id,
timeticket: record
}}
disabled={
record.ciecacode
? record.committed_at
? HasRbacAccess({
bodyshop,
authLevel: authLevel,
action: "timetickets:editcommitted"
}) &&
HasRbacAccess({
bodyshop,
authLevel: authLevel,
action: "timetickets:edit"
})
: HasRbacAccess({
bodyshop,
authLevel: authLevel,
action: "timetickets:edit"
})
: record.committed_at
? HasRbacAccess({
bodyshop,
authLevel: authLevel,
action: "timetickets:editcommitted"
}) &&
HasRbacAccess({
bodyshop,
authLevel: authLevel,
action: "timetickets:shiftedit"
})
: HasRbacAccess({
bodyshop,
authLevel: authLevel,
action: "timetickets:shiftedit"
})
? disabled
: !record.jobid
}
>
<EditFilled />
</TimeTicketEnterButton>
</RbacWrapper>
)} )}
</Space> </Space>
) )