BOD-5 BOD-36 #comment Added Audit Trail List to jobs and created Audit List view component + queries

This commit is contained in:
Patrick Fic
2020-03-10 11:02:28 -07:00
parent d1cfd9bacf
commit 05d7aa7000
10 changed files with 345 additions and 21 deletions

View File

@@ -0,0 +1,82 @@
import React, { useState } from "react";
import { Table } from "antd";
import { alphaSort } from "../../utils/sorters";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import { useTranslation } from "react-i18next";
import AuditTrailValuesComponent from "../audit-trail-values/audit-trail-values.component";
export default function AuditTrailListComponent({ loading, data }) {
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: {}
});
const { t } = useTranslation();
const columns = [
{
title: t("audit.fields.created"),
dataIndex: " created",
key: " created",
render: (text, record) => (
<DateTimeFormatter>{record.created}</DateTimeFormatter>
),
sorter: (a, b) => a.created - b.created,
sortOrder:
state.sortedInfo.columnKey === "created" && state.sortedInfo.order
},
{
title: t("audit.fields.operation"),
dataIndex: "operation",
key: "operation",
sorter: (a, b) => alphaSort(a.operation, b.operation),
sortOrder:
state.sortedInfo.columnKey === "operation" && state.sortedInfo.order
},
{
title: t("audit.fields.values"),
dataIndex: " old_val",
key: " old_val",
render: (text, record) => (
<AuditTrailValuesComponent
oldV={record.old_val}
newV={record.new_val}
/>
)
},
{
title: t("audit.fields.useremail"),
dataIndex: "useremail",
key: "useremail",
sorter: (a, b) => alphaSort(a.useremail, b.useremail),
sortOrder:
state.sortedInfo.columnKey === "useremail" && state.sortedInfo.order
}
];
const formItemLayout = {
labelCol: {
xs: { span: 12 },
sm: { span: 5 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 12 }
}
};
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
return (
<Table
{...formItemLayout}
loading={loading}
size="small"
pagination={{ position: "top", defaultPageSize: 25 }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
dataSource={data}
onChange={handleTableChange}
/>
);
}

View File

@@ -0,0 +1,24 @@
import React from "react";
import AuditTrailListComponent from "./audit-trail-list.component";
import { useQuery } from "react-apollo";
import { QUERY_AUDIT_TRAIL } from "../../graphql/audit_trail.queries";
import AlertComponent from "../alert/alert.component";
export default function AuditTrailListContainer({ recordId }) {
const { loading, error, data } = useQuery(QUERY_AUDIT_TRAIL, {
variables: { id: recordId },
fetchPolicy: "network-only"
});
return (
<div>
{error ? (
<AlertComponent type="error" message={error.message} />
) : (
<AuditTrailListComponent
loading={loading}
data={data ? data.audit_trail : null}
/>
)}
</div>
);
}

View File

@@ -0,0 +1,15 @@
import React from "react";
import { List } from "antd";
import Icon from "@ant-design/icons";
import { FaArrowRight } from "react-icons/fa";
export default function AuditTrailValuesComponent({ oldV, newV }) {
return (
<List bordered size="small">
{Object.keys(oldV).map((key, idx) => (
<List.Item key={idx} value={key}>
{key}: {oldV[key]} <Icon component={FaArrowRight} /> {newV[key]}
</List.Item>
))}
</List>
);
}

View File

@@ -0,0 +1,18 @@
import { gql } from "apollo-boost";
export const QUERY_AUDIT_TRAIL = gql`
query QUERY_AUDIT_TRAIL($id: uuid!) {
audit_trail(where: {recordid: {_eq: $id}}) {
useremail
tabname
schemaname
recordid
operation
old_val
new_val
id
created
bodyshopid
}
}
`;

View File

@@ -13,7 +13,8 @@ import {
FaHardHat,
FaInfo,
FaRegStickyNote,
FaShieldAlt
FaShieldAlt,
FaHistory
} from "react-icons/fa";
//import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container";
//import JobsDetailClaims from "../../components/jobs-detail-claims/jobs-detail-claims.component";
@@ -70,6 +71,9 @@ const EnterInvoiceModalContainer = lazy(() =>
const JobsDetailPliContainer = lazy(() =>
import("../../components/jobs-detail-pli/jobs-detail-pli.container")
);
const JobsDetailAuditContainer = lazy(() =>
import("../../components/audit-trail-list/audit-trail-list.container")
);
export default function JobsDetailPage({
job,
@@ -120,7 +124,7 @@ export default function JobsDetailPage({
<Form
form={form}
onFieldsChange={(a, b) => console.log("a,b", a, b)}
//onFieldsChange={(a, b) => console.log("a,b", a, b)}
name="JobDetailForm"
onFinish={handleFinish}
{...formItemLayout}
@@ -262,6 +266,21 @@ export default function JobsDetailPage({
>
<JobNotesContainer jobId={job.id} />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<Icon component={FaHistory} />
{t("jobs.labels.audit")}
</span>
}
key="audit"
>
<JobsDetailAuditContainer recordId={job.id }/>
</Tabs.TabPane>
</Tabs>
</Form>
</Suspense>

View File

@@ -56,6 +56,14 @@
"actions": "Actions"
}
},
"audit": {
"fields": {
"created": "Time",
"operation": "Operation",
"useremail": "User",
"values": ""
}
},
"bodyshop": {
"errors": {
"loading": "Unable to load shop details. Please call technical support."
@@ -178,7 +186,8 @@
"is_credit_memo": "Credit Memo?",
"ro_number": "RO Number",
"total": "Invoice Total",
"vendor": "Vendor"
"vendor": "Vendor",
"vendorname": "Vendor Name"
},
"labels": {
"actions": "Actions",
@@ -337,6 +346,7 @@
},
"labels": {
"appointmentconfirmation": "Send confirmation to customer?",
"audit": "Audit Trail",
"available_new_jobs": "",
"cards": {
"appraiser": "Appraiser",

View File

@@ -56,6 +56,14 @@
"actions": "Comportamiento"
}
},
"audit": {
"fields": {
"created": "",
"operation": "",
"useremail": "",
"values": ""
}
},
"bodyshop": {
"errors": {
"loading": "No se pueden cargar los detalles de la tienda. Por favor llame al soporte técnico."
@@ -178,7 +186,8 @@
"is_credit_memo": "",
"ro_number": "",
"total": "",
"vendor": ""
"vendor": "",
"vendorname": ""
},
"labels": {
"actions": "",
@@ -337,6 +346,7 @@
},
"labels": {
"appointmentconfirmation": "¿Enviar confirmación al cliente?",
"audit": "",
"available_new_jobs": "",
"cards": {
"appraiser": "Tasador",

View File

@@ -56,6 +56,14 @@
"actions": "actes"
}
},
"audit": {
"fields": {
"created": "",
"operation": "",
"useremail": "",
"values": ""
}
},
"bodyshop": {
"errors": {
"loading": "Impossible de charger les détails de la boutique. Veuillez appeler le support technique."
@@ -178,7 +186,8 @@
"is_credit_memo": "",
"ro_number": "",
"total": "",
"vendor": ""
"vendor": "",
"vendorname": ""
},
"labels": {
"actions": "",
@@ -337,6 +346,7 @@
},
"labels": {
"appointmentconfirmation": "Envoyer une confirmation au client?",
"audit": "",
"available_new_jobs": "",
"cards": {
"appraiser": "Expert",