release/2026-02-27 - Add gating
This commit is contained in:
@@ -20,7 +20,8 @@ export function DmsLogEvents({
|
||||
detailsNonce,
|
||||
isDarkMode,
|
||||
colorizeJson = false,
|
||||
showDetails = true
|
||||
showDetails = true,
|
||||
allowXmlPayload = true
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [openSet, setOpenSet] = useState(() => new Set());
|
||||
@@ -75,7 +76,7 @@ export function DmsLogEvents({
|
||||
// Only treat meta as "present" when we are allowed to show details
|
||||
const hasMeta = !isEmpty(meta) && showDetails;
|
||||
const isOpen = hasMeta && openSet.has(idx);
|
||||
const xml = hasMeta ? extractXmlFromMeta(meta) : { request: null, response: null };
|
||||
const xml = hasMeta && allowXmlPayload ? extractXmlFromMeta(meta) : { request: null, response: null };
|
||||
const hasRequestXml = !!xml.request;
|
||||
const hasResponseXml = !!xml.response;
|
||||
const copyPayload = hasMeta ? getCopyPayload(meta) : null;
|
||||
@@ -175,7 +176,7 @@ export function DmsLogEvents({
|
||||
)
|
||||
};
|
||||
}),
|
||||
[logs, openSet, colorizeJson, copiedKey, isDarkMode, showDetails, t]
|
||||
[logs, openSet, colorizeJson, copiedKey, isDarkMode, showDetails, allowXmlPayload, t]
|
||||
);
|
||||
|
||||
return <Timeline reverse items={items} />;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useSocket } from "../../contexts/SocketIO/useSocket.js";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
|
||||
import { QUERY_JOB_EXPORT_DMS } from "../../graphql/jobs.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { insertAuditTrail, setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
@@ -29,7 +29,8 @@ import DmsAllocationsSummary from "../../components/dms-allocations-summary/dms-
|
||||
import RrAllocationsSummary from "../../components/dms-allocations-summary/rr-dms-allocations-summary.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
bodyshop: selectBodyshop,
|
||||
currentUser: selectCurrentUser
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
@@ -65,7 +66,41 @@ const DMS_SOCKET_EVENTS = {
|
||||
}
|
||||
};
|
||||
|
||||
export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, insertAuditTrail }) {
|
||||
const stripRrXmlFromPayload = (input) => {
|
||||
if (input == null || typeof input !== "object") return input;
|
||||
|
||||
let target = null;
|
||||
try {
|
||||
target = JSON.parse(JSON.stringify(input));
|
||||
} catch {
|
||||
// Fallback to in-place scrub if cloning fails.
|
||||
target = input;
|
||||
}
|
||||
|
||||
const scrub = (node) => {
|
||||
if (node == null || typeof node !== "object") return;
|
||||
if (Array.isArray(node)) {
|
||||
node.forEach(scrub);
|
||||
return;
|
||||
}
|
||||
|
||||
delete node.requestXml;
|
||||
delete node.responseXml;
|
||||
|
||||
if (node.xml && typeof node.xml === "object") {
|
||||
delete node.xml.request;
|
||||
delete node.xml.response;
|
||||
if (Object.keys(node.xml).length === 0) delete node.xml;
|
||||
}
|
||||
|
||||
Object.values(node).forEach(scrub);
|
||||
};
|
||||
|
||||
scrub(target);
|
||||
return target;
|
||||
};
|
||||
|
||||
export function DmsContainer({ bodyshop, currentUser, setBreadcrumbs, setSelectedHeader, insertAuditTrail }) {
|
||||
const {
|
||||
treatments: { Fortellis }
|
||||
} = useTreatmentsWithConfig({
|
||||
@@ -79,6 +114,15 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
const [allocationsSummary, setAllocationsSummary] = useState(null);
|
||||
const [reconnectNonce, setReconnectNonce] = useState(0);
|
||||
|
||||
const isDevEnv = import.meta.env.DEV;
|
||||
const isProdEnv = import.meta.env.PROD;
|
||||
const userEmail = (currentUser?.email || "").toLowerCase();
|
||||
|
||||
const devEmails = ["imex.dev", "rome.dev"];
|
||||
const prodEmails = ["imex.prod", "rome.prod", "imex.test", "rome.test"];
|
||||
const hasValidEmail = (emails) => emails.some((email) => userEmail.endsWith(email));
|
||||
const canViewSensitiveRrXml = (isDevEnv && hasValidEmail(devEmails)) || (isProdEnv && hasValidEmail(prodEmails));
|
||||
|
||||
// Compute a single normalized mode and pick the proper socket
|
||||
const mode = getDmsMode(bodyshop, Fortellis.treatment); // "rr" | "fortellis" | "cdk" | "pbs" | "none"
|
||||
|
||||
@@ -241,6 +285,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
}, [jobId, mode, activeSocket]);
|
||||
|
||||
const handleExportFailed = (payload = {}) => {
|
||||
const safePayload = canViewSensitiveRrXml ? payload : stripRrXmlFromPayload(payload);
|
||||
const { title, friendlyMessage, error: errText, severity, errorCode, vendorStatusCode } = payload;
|
||||
|
||||
const msg =
|
||||
@@ -271,7 +316,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
timestamp: new Date(),
|
||||
level: (sev || "error").toUpperCase(),
|
||||
message: `${vendorTitle}: ${msg}`,
|
||||
meta: { errorCode, vendorStatusCode, raw: payload, blockedByOpenRoLimit: !!isRrOpenRoLimit }
|
||||
meta: { errorCode, vendorStatusCode, raw: safePayload, blockedByOpenRoLimit: !!isRrOpenRoLimit }
|
||||
}
|
||||
]);
|
||||
};
|
||||
@@ -344,11 +389,16 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
// Logs
|
||||
const onLog = isRrMode
|
||||
? (payload = {}) => {
|
||||
const safePayload = canViewSensitiveRrXml ? payload : stripRrXmlFromPayload(payload);
|
||||
const normalized = {
|
||||
timestamp: payload.timestamp ? new Date(payload.timestamp) : payload.ts ? new Date(payload.ts) : new Date(),
|
||||
level: (payload.level || "INFO").toUpperCase(),
|
||||
message: payload.message || payload.msg || "",
|
||||
meta: payload.meta ?? payload.ctx ?? payload.details ?? null
|
||||
timestamp: safePayload.timestamp
|
||||
? new Date(safePayload.timestamp)
|
||||
: safePayload.ts
|
||||
? new Date(safePayload.ts)
|
||||
: new Date(),
|
||||
level: (safePayload.level || "INFO").toUpperCase(),
|
||||
message: safePayload.message || safePayload.msg || "",
|
||||
meta: safePayload.meta ?? safePayload.ctx ?? safePayload.details ?? null
|
||||
};
|
||||
setLogs((prev) => [...prev, normalized]);
|
||||
}
|
||||
@@ -429,7 +479,19 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
activeSocket.disconnect();
|
||||
}
|
||||
};
|
||||
}, [mode, activeSocket, channels, logLevel, notification, t, insertAuditTrail, history, isRrMode, providerLabel]);
|
||||
}, [
|
||||
mode,
|
||||
activeSocket,
|
||||
channels,
|
||||
logLevel,
|
||||
notification,
|
||||
t,
|
||||
insertAuditTrail,
|
||||
history,
|
||||
isRrMode,
|
||||
providerLabel,
|
||||
canViewSensitiveRrXml
|
||||
]);
|
||||
|
||||
// RR finalize callback (unchanged public behavior)
|
||||
const handleRrValidationFinished = () => {
|
||||
@@ -588,6 +650,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
detailsNonce={detailsNonce}
|
||||
colorizeJson={isRrMode ? colorizeJson : false}
|
||||
showDetails={isRrMode}
|
||||
allowXmlPayload={canViewSensitiveRrXml}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user