diff --git a/client/src/components/jobs-list/jobs-list.component.jsx b/client/src/components/jobs-list/jobs-list.component.jsx index d11e4b688..6d04bcd47 100644 --- a/client/src/components/jobs-list/jobs-list.component.jsx +++ b/client/src/components/jobs-list/jobs-list.component.jsx @@ -184,12 +184,15 @@ export function JobsList({ bodyshop }) { ), sortOrder: state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order, render: (text, record) => { + const vehicleLabel = + `${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`.trim(); + return record.vehicleid ? ( e.stopPropagation()}> - {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`} + {vehicleLabel} ) : ( - {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`} + {vehicleLabel} ); } }, diff --git a/client/src/components/responsive-table/responsive-table.component.jsx b/client/src/components/responsive-table/responsive-table.component.jsx index 4228d9efe..94ed7fc02 100644 --- a/client/src/components/responsive-table/responsive-table.component.jsx +++ b/client/src/components/responsive-table/responsive-table.component.jsx @@ -1,9 +1,12 @@ import { Grid, Table } from "antd"; import { useMemo } from "react"; +import "./responsive-table.styles.scss"; -function ResponsiveTable({ columns, mobileColumnKeys, scroll, ...rest }) { +function ResponsiveTable({ className, columns, mobileColumnKeys, scroll, tableLayout, ...rest }) { const screens = Grid.useBreakpoint(); const isPhone = !screens.md; + const isCompactViewport = !screens.lg; + const prefersHorizontalScroll = isPhone || isCompactViewport; const isResponsiveFilteringEnabled = ["1", "true", "yes", "on"].includes( String(import.meta.env.VITE_APP_ENABLE_RESPONSIVE_TABLE_FILTERING || "") .trim() @@ -38,9 +41,53 @@ function ResponsiveTable({ columns, mobileColumnKeys, scroll, ...rest }) { return filteredColumns.length > 0 ? filteredColumns : columns; }, [columns, isPhone, isResponsiveFilteringEnabled, mobileColumnKeys]); - const resolvedScroll = scroll ?? { x: "max-content" }; + const resolvedScroll = useMemo(() => { + if (prefersHorizontalScroll) { + if (scroll == null) { + return { x: "max-content" }; + } - return ; + if (typeof scroll !== "object" || Array.isArray(scroll)) { + return scroll; + } + + const { x, ...baseScroll } = scroll; + + return { ...baseScroll, x: x ?? "max-content" }; + } + + if (scroll == null) { + // Explicitly override ConfigProvider table.scroll desktop defaults. + return {}; + } + + if (typeof scroll !== "object" || Array.isArray(scroll)) { + return scroll; + } + + const { x, ...desktopScroll } = scroll; + + // On desktop we prefer fitting columns with ellipsis over forced horizontal scroll. + if (x == null) { + return desktopScroll; + } + + return desktopScroll; + }, [prefersHorizontalScroll, scroll]); + + const resolvedTableLayout = tableLayout ?? (prefersHorizontalScroll ? "auto" : "fixed"); + const responsiveClassName = prefersHorizontalScroll ? undefined : "responsive-table-fit"; + const resolvedClassName = [responsiveClassName, className].filter(Boolean).join(" "); + + return ( +
+ ); } ResponsiveTable.Summary = Table.Summary; diff --git a/client/src/components/responsive-table/responsive-table.styles.scss b/client/src/components/responsive-table/responsive-table.styles.scss new file mode 100644 index 000000000..349a46024 --- /dev/null +++ b/client/src/components/responsive-table/responsive-table.styles.scss @@ -0,0 +1,27 @@ +.responsive-table-fit .ant-table-cell, +.responsive-table-fit .ant-table-cell > * { + min-width: 0; +} + +.responsive-table-fit .ant-table-content > table { + width: 100%; +} + +.responsive-table-fit .ant-table-column-sorters { + width: 100%; +} + +.responsive-table-fit .ant-table-column-title, +.responsive-table-fit .ant-space, +.responsive-table-fit .ant-space-item { + min-width: 0; +} + +.responsive-table-fit .ant-table-cell-ellipsis > a, +.responsive-table-fit .ant-table-cell-ellipsis > span { + display: block; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/server/web-sockets/createLogEvent.js b/server/web-sockets/createLogEvent.js index 0e0d52cbc..b1824d334 100644 --- a/server/web-sockets/createLogEvent.js +++ b/server/web-sockets/createLogEvent.js @@ -1,114 +1,113 @@ const { isArray } = require("lodash"); const logger = require("../utils/logger"); - function createLogEvent(socket, level, message) { - if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) { - // console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); - socket.emit("log-event", { - timestamp: new Date(), - level, - message - }); + if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) { + // console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); + socket.emit("log-event", { + timestamp: new Date(), + level, + message + }); - logger.log("ws-log-event", level, socket.user.email, socket.recordid, { - wsmessage: message - }); - - if (socket.logEvents && isArray(socket.logEvents)) { - socket.logEvents.push({ - timestamp: new Date(), - level, - message - }); - } - // if (level === "ERROR") { - // throw new Error(message); - // } - } -} - -function createJsonEvent(socket, level, message, json) { - if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) { - //console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); - socket.emit("log-event", { - timestamp: new Date(), - level, - message - }); - } - logger.log( - "ws-log-event-json", - level, - socket.user.email, - socket.recordid, - { - wsmessage: message, - json - }, - true - ); + logger.log("ws-log-event", level, socket.user.email, socket.recordid, { + wsmessage: message + }); if (socket.logEvents && isArray(socket.logEvents)) { - socket.logEvents.push({ - timestamp: new Date(), - level, - message - }); + socket.logEvents.push({ + timestamp: new Date(), + level, + message + }); } // if (level === "ERROR") { // throw new Error(message); // } + } +} + +function createJsonEvent(socket, level, message, json) { + if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) { + //console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); + socket.emit("log-event", { + timestamp: new Date(), + level, + message + }); + } + logger.log( + "ws-log-event-json", + level, + socket.user.email, + socket.recordid, + { + wsmessage: message, + json + }, + true + ); + + if (socket.logEvents && isArray(socket.logEvents)) { + socket.logEvents.push({ + timestamp: new Date(), + level, + message + }); + } + // if (level === "ERROR") { + // throw new Error(message); + // } } function createXmlEvent(socket, xml, message, isError = false) { - if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("SILLY")) { - socket.emit("log-event", { - timestamp: new Date(), - level: isError ? "ERROR" : "SILLY", - message: `${message}: ${xml}` - }); - } + if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("SILLY")) { + socket.emit("log-event", { + timestamp: new Date(), + level: isError ? "ERROR" : "SILLY", + message: `${message}: ${xml}` + }); + } - logger.log( - isError ? "ws-log-event-xml-error" : "ws-log-event-xml", - isError ? "ERROR" : "SILLY", - socket.user.email, - socket.recordid, - { - wsmessage: message, - xml - }, - true - ); + logger.log( + isError ? "ws-log-event-xml-error" : "ws-log-event-xml", + isError ? "ERROR" : "SILLY", + socket.user.email, + socket.recordid, + { + wsmessage: message, + xml + }, + true + ); - if (socket.logEvents && isArray(socket.logEvents)) { - socket.logEvents.push({ - timestamp: new Date(), - level: isError ? "ERROR" : "SILLY", - message, - xml - }); - } + if (socket.logEvents && isArray(socket.logEvents)) { + socket.logEvents.push({ + timestamp: new Date(), + level: isError ? "ERROR" : "SILLY", + message, + xml + }); + } } function LogLevelHierarchy(level) { - switch (level) { - case "XML": - return 5; - case "SILLY": - return 5; - case "DEBUG": - return 4; - case "INFO": - return 3; - case "WARN": - return 2; - case "ERROR": - return 1; - default: - return 3; - } + switch (level) { + case "XML": + return 5; + case "SILLY": + return 5; + case "DEBUG": + return 4; + case "INFO": + return 3; + case "WARN": + return 2; + case "ERROR": + return 1; + default: + return 3; + } } exports.createLogEvent = createLogEvent;