IO-909 RBAC Shift Editing
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
<babeledit_project version="1.2" be_version="2.7.1">
|
<babeledit_project be_version="2.7.1" version="1.2">
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
BabelEdit project file
|
BabelEdit project file
|
||||||
@@ -3817,6 +3817,27 @@
|
|||||||
<folder_node>
|
<folder_node>
|
||||||
<name>accounting</name>
|
<name>accounting</name>
|
||||||
<children>
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>exportlog</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>payables</name>
|
<name>payables</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -4795,6 +4816,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>shiftedit</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
<folder_node>
|
<folder_node>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const FormDatePicker = ({ value, onChange, onBlur, ...restProps }, ref) => {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
format={dateFormat}
|
format={dateFormat}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
|
disabledTime
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ const ret = {
|
|||||||
"timetickets:enter": 3,
|
"timetickets:enter": 3,
|
||||||
"timetickets:list": 3,
|
"timetickets:list": 3,
|
||||||
"timetickets:edit": 4,
|
"timetickets:edit": 4,
|
||||||
|
"timetickets:shiftedit": 5,
|
||||||
|
|
||||||
"users:editaccess": 4,
|
"users:editaccess": 4,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,19 +5,16 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import {
|
import {
|
||||||
selectAuthLevel,
|
selectAuthLevel,
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import rbacDefaults from "./rbac-defaults";
|
import rbacDefaults from "./rbac-defaults";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
currentUser: selectCurrentUser,
|
|
||||||
authLevel: selectAuthLevel,
|
authLevel: selectAuthLevel,
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
|
|
||||||
function RbacWrapper({
|
function RbacWrapper({
|
||||||
currentUser,
|
|
||||||
authLevel,
|
authLevel,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
requiredAuthLevel,
|
requiredAuthLevel,
|
||||||
@@ -33,7 +30,9 @@ function RbacWrapper({
|
|||||||
(requiredAuthLevel && requiredAuthLevel <= authLevel) ||
|
(requiredAuthLevel && requiredAuthLevel <= authLevel) ||
|
||||||
((bodyshop.md_rbac && bodyshop.md_rbac[action]) || rbacDefaults[action]) <=
|
((bodyshop.md_rbac && bodyshop.md_rbac[action]) || rbacDefaults[action]) <=
|
||||||
authLevel ||
|
authLevel ||
|
||||||
(!bodyshop.md_rbac && rbacDefaults[action] <= authLevel)
|
(bodyshop.md_rbac &&
|
||||||
|
!bodyshop.md_rbac[action] &&
|
||||||
|
rbacDefaults[action] <= authLevel)
|
||||||
)
|
)
|
||||||
return children;
|
return children;
|
||||||
//return <div>{React.cloneElement(children, restProps)}</div>;
|
//return <div>{React.cloneElement(children, restProps)}</div>;
|
||||||
@@ -48,12 +47,28 @@ function RbacWrapper({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RbacWrapper.propTypes = {
|
export function HasRbacAccess({
|
||||||
// currentUser: PropTypes.object.isRequired,
|
authLevel,
|
||||||
// authLevel: PropTypes.number.isRequired,
|
bodyshop,
|
||||||
// noauth: PropTypes.oneOfType(PropTypes.string, PropTypes.func),
|
requiredAuthLevel,
|
||||||
// requiredAuthLevel: PropTypes.number,
|
action,
|
||||||
// action: PropTypes.string,
|
}) {
|
||||||
// };
|
console.log(
|
||||||
|
"Checking access for action",
|
||||||
|
action,
|
||||||
|
bodyshop.md_rbac[action],
|
||||||
|
authLevel,
|
||||||
|
bodyshop.md_rbac[action] <= authLevel
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
(requiredAuthLevel && requiredAuthLevel <= authLevel) ||
|
||||||
|
((bodyshop.md_rbac && bodyshop.md_rbac[action]) || rbacDefaults[action]) <=
|
||||||
|
authLevel ||
|
||||||
|
(bodyshop.md_rbac &&
|
||||||
|
!bodyshop.md_rbac[action] &&
|
||||||
|
rbacDefaults[action] <= authLevel)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(RbacWrapper);
|
export default connect(mapStateToProps, null)(RbacWrapper);
|
||||||
|
|||||||
@@ -226,6 +226,12 @@ export function ShopEmployeesFormComponent({
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Select>
|
<Select>
|
||||||
|
<Select.Option
|
||||||
|
key={"shift"}
|
||||||
|
value="timetickets.labels.shift"
|
||||||
|
>
|
||||||
|
{t("timetickets.labels.shift")}
|
||||||
|
</Select.Option>
|
||||||
{bodyshop.md_responsibility_centers.costs.map((c) => (
|
{bodyshop.md_responsibility_centers.costs.map((c) => (
|
||||||
<Select.Option key={c.name} value={c.name}>
|
<Select.Option key={c.name} value={c.name}>
|
||||||
{c.name}
|
{c.name}
|
||||||
|
|||||||
@@ -465,6 +465,18 @@ export default function ShopInfoRbacComponent({ form }) {
|
|||||||
>
|
>
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</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={[
|
||||||
|
|||||||
@@ -2,13 +2,32 @@ import { Card, Space, Table } from "antd";
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import {
|
||||||
|
selectAuthLevel,
|
||||||
|
selectBodyshop,
|
||||||
|
} from "../../redux/user/user.selectors";
|
||||||
import { onlyUnique } from "../../utils/arrayHelper";
|
import { onlyUnique } from "../../utils/arrayHelper";
|
||||||
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
import RbacWrapper, {
|
||||||
|
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";
|
||||||
|
|
||||||
export default function TimeTicketList({
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
authLevel: selectAuthLevel,
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
|
});
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketList);
|
||||||
|
|
||||||
|
export function TimeTicketList({
|
||||||
|
bodyshop,
|
||||||
|
authLevel,
|
||||||
disabled,
|
disabled,
|
||||||
loading,
|
loading,
|
||||||
timetickets,
|
timetickets,
|
||||||
@@ -154,7 +173,7 @@ export default function TimeTicketList({
|
|||||||
<TimeTicketEnterButton
|
<TimeTicketEnterButton
|
||||||
actions={{ refetch }}
|
actions={{ refetch }}
|
||||||
context={{ id: record.id, timeticket: record }}
|
context={{ id: record.id, timeticket: record }}
|
||||||
disabled={!!!record.job || disabled}
|
disabled={!record.job || disabled}
|
||||||
>
|
>
|
||||||
{t("general.actions.edit")}
|
{t("general.actions.edit")}
|
||||||
</TimeTicketEnterButton>
|
</TimeTicketEnterButton>
|
||||||
@@ -172,7 +191,15 @@ export default function TimeTicketList({
|
|||||||
id: record.id,
|
id: record.id,
|
||||||
timeticket: record,
|
timeticket: record,
|
||||||
}}
|
}}
|
||||||
disabled={!!!record.jobid || disabled}
|
disabled={
|
||||||
|
HasRbacAccess({
|
||||||
|
bodyshop,
|
||||||
|
authLevel: authLevel,
|
||||||
|
action: "timetickets:shiftedit",
|
||||||
|
})
|
||||||
|
? disabled
|
||||||
|
: !record.jobid
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{t("general.actions.edit")}
|
{t("general.actions.edit")}
|
||||||
</TimeTicketEnterButton>
|
</TimeTicketEnterButton>
|
||||||
|
|||||||
@@ -2,18 +2,37 @@ import { useQuery } from "@apollo/client";
|
|||||||
import { Form, Input, InputNumber, Select } from "antd";
|
import { Form, Input, InputNumber, Select } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
|
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
|
||||||
|
import {
|
||||||
|
selectAuthLevel,
|
||||||
|
selectBodyshop,
|
||||||
|
} from "../../redux/user/user.selectors";
|
||||||
import EmployeeSearchSelect from "../employee-search-select/employee-search-select.component";
|
import EmployeeSearchSelect from "../employee-search-select/employee-search-select.component";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
||||||
|
import FormDateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
||||||
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
||||||
import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component";
|
import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
|
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
|
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
|
||||||
|
|
||||||
export default function TimeTicketModalComponent({
|
const mapStateToProps = createStructuredSelector({
|
||||||
form,
|
bodyshop: selectBodyshop,
|
||||||
|
authLevel: selectAuthLevel,
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({});
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(TimeTicketModalComponent);
|
||||||
|
|
||||||
|
export function TimeTicketModalComponent({
|
||||||
|
form,
|
||||||
|
bodyshop,
|
||||||
|
authLevel,
|
||||||
employeeAutoCompleteOptions,
|
employeeAutoCompleteOptions,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -21,17 +40,23 @@ export default function TimeTicketModalComponent({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<LayoutFormRow grow>
|
<LayoutFormRow grow>
|
||||||
<Form.Item
|
<Form.Item shouldUpdate>
|
||||||
name="jobid"
|
{() => (
|
||||||
label={t("timetickets.fields.ro_number")}
|
<Form.Item
|
||||||
rules={[
|
name="jobid"
|
||||||
{
|
label={t("timetickets.fields.ro_number")}
|
||||||
required: true,
|
rules={[
|
||||||
message: t("general.validation.required"),
|
{
|
||||||
},
|
required:
|
||||||
]}
|
!form.getFieldValue("cost_center") ===
|
||||||
>
|
"timetickets.labels.shift",
|
||||||
<JobSearchSelect convertedOnly notExported={false} />
|
message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<JobSearchSelect convertedOnly notExported={false} />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("timetickets.fields.date")}
|
label={t("timetickets.fields.date")}
|
||||||
@@ -104,34 +129,51 @@ export default function TimeTicketModalComponent({
|
|||||||
>
|
>
|
||||||
<InputNumber min={0} precision={1} />
|
<InputNumber min={0} precision={1} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item label={t("timetickets.fields.actualhrs")} name="actualhrs">
|
||||||
label={t("timetickets.fields.actualhrs")}
|
|
||||||
name="actualhrs"
|
|
||||||
// rules={[
|
|
||||||
// {
|
|
||||||
// required: true,
|
|
||||||
// message: t("general.validation.required"),
|
|
||||||
// },
|
|
||||||
// ]}
|
|
||||||
>
|
|
||||||
<InputNumber min={0} precision={1} />
|
<InputNumber min={0} precision={1} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item label={t("timetickets.fields.clockon")} name="clockon">
|
||||||
|
<FormDateTimePicker
|
||||||
|
disabled={
|
||||||
|
!HasRbacAccess({
|
||||||
|
bodyshop,
|
||||||
|
authLevel,
|
||||||
|
action: "timetickets:shiftedit",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label={t("timetickets.fields.clockoff")} name="clockoff">
|
||||||
|
<FormDateTimePicker
|
||||||
|
disabled={
|
||||||
|
!HasRbacAccess({
|
||||||
|
bodyshop,
|
||||||
|
authLevel,
|
||||||
|
action: "timetickets:shiftedit",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
<Form.Item label={t("timetickets.fields.memo")} name="memo">
|
<Form.Item label={t("timetickets.fields.memo")} name="memo">
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
<Form.Item
|
{() => (
|
||||||
name="ciecacode"
|
<Form.Item
|
||||||
label={t("timetickets.fields.ciecacode")}
|
name="ciecacode"
|
||||||
rules={[
|
label={t("timetickets.fields.ciecacode")}
|
||||||
{
|
rules={[
|
||||||
required: true,
|
{
|
||||||
message: t("general.validation.required"),
|
required:
|
||||||
},
|
!form.getFieldValue("cost_center") ===
|
||||||
]}
|
"timetickets.labels.shift",
|
||||||
>
|
message: t("general.validation.required"),
|
||||||
<Input disabled />
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input disabled />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<Form.Item dependencies={["jobid"]}>
|
<Form.Item dependencies={["jobid"]}>
|
||||||
|
|||||||
@@ -246,6 +246,7 @@
|
|||||||
"prodtargethrs": "Production Target Hours",
|
"prodtargethrs": "Production Target Hours",
|
||||||
"rbac": {
|
"rbac": {
|
||||||
"accounting": {
|
"accounting": {
|
||||||
|
"exportlog": "Accounting -> Export Log",
|
||||||
"payables": "Accounting -> Payables",
|
"payables": "Accounting -> Payables",
|
||||||
"payments": "Accounting -> Payments",
|
"payments": "Accounting -> Payments",
|
||||||
"receivables": "Accounting -> Receivables"
|
"receivables": "Accounting -> Receivables"
|
||||||
@@ -318,7 +319,8 @@
|
|||||||
"timetickets": {
|
"timetickets": {
|
||||||
"edit": "Time Tickets -> Edit",
|
"edit": "Time Tickets -> Edit",
|
||||||
"enter": "Time Tickets -> Enter",
|
"enter": "Time Tickets -> Enter",
|
||||||
"list": "Time Tickets -> List"
|
"list": "Time Tickets -> List",
|
||||||
|
"shiftedit": "Time Tickets -> Shift Edit"
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"editaccess": "Users -> Edit access"
|
"editaccess": "Users -> Edit access"
|
||||||
|
|||||||
@@ -246,6 +246,7 @@
|
|||||||
"prodtargethrs": "",
|
"prodtargethrs": "",
|
||||||
"rbac": {
|
"rbac": {
|
||||||
"accounting": {
|
"accounting": {
|
||||||
|
"exportlog": "",
|
||||||
"payables": "",
|
"payables": "",
|
||||||
"payments": "",
|
"payments": "",
|
||||||
"receivables": ""
|
"receivables": ""
|
||||||
@@ -318,7 +319,8 @@
|
|||||||
"timetickets": {
|
"timetickets": {
|
||||||
"edit": "",
|
"edit": "",
|
||||||
"enter": "",
|
"enter": "",
|
||||||
"list": ""
|
"list": "",
|
||||||
|
"shiftedit": ""
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"editaccess": ""
|
"editaccess": ""
|
||||||
|
|||||||
@@ -246,6 +246,7 @@
|
|||||||
"prodtargethrs": "",
|
"prodtargethrs": "",
|
||||||
"rbac": {
|
"rbac": {
|
||||||
"accounting": {
|
"accounting": {
|
||||||
|
"exportlog": "",
|
||||||
"payables": "",
|
"payables": "",
|
||||||
"payments": "",
|
"payments": "",
|
||||||
"receivables": ""
|
"receivables": ""
|
||||||
@@ -318,7 +319,8 @@
|
|||||||
"timetickets": {
|
"timetickets": {
|
||||||
"edit": "",
|
"edit": "",
|
||||||
"enter": "",
|
"enter": "",
|
||||||
"list": ""
|
"list": "",
|
||||||
|
"shiftedit": ""
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"editaccess": ""
|
"editaccess": ""
|
||||||
|
|||||||
Reference in New Issue
Block a user