feature/IO-3554-Form-Row-Layout - Modify how truncation works on responsive tables.

This commit is contained in:
Dave
2026-03-02 11:29:06 -05:00
parent 9a41cfd6af
commit 56c24e3450
4 changed files with 173 additions and 97 deletions

View File

@@ -184,12 +184,15 @@ export function JobsList({ bodyshop }) {
), ),
sortOrder: state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order, sortOrder: state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
render: (text, record) => { render: (text, record) => {
const vehicleLabel =
`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`.trim();
return record.vehicleid ? ( return record.vehicleid ? (
<Link to={"/manage/vehicles/" + record.vehicleid} onClick={(e) => e.stopPropagation()}> <Link to={"/manage/vehicles/" + record.vehicleid} onClick={(e) => e.stopPropagation()}>
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`} <span className="ellipses">{vehicleLabel}</span>
</Link> </Link>
) : ( ) : (
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`}</span> <span className="ellipses">{vehicleLabel}</span>
); );
} }
}, },

View File

@@ -1,9 +1,12 @@
import { Grid, Table } from "antd"; import { Grid, Table } from "antd";
import { useMemo } from "react"; 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 screens = Grid.useBreakpoint();
const isPhone = !screens.md; const isPhone = !screens.md;
const isCompactViewport = !screens.lg;
const prefersHorizontalScroll = isPhone || isCompactViewport;
const isResponsiveFilteringEnabled = ["1", "true", "yes", "on"].includes( const isResponsiveFilteringEnabled = ["1", "true", "yes", "on"].includes(
String(import.meta.env.VITE_APP_ENABLE_RESPONSIVE_TABLE_FILTERING || "") String(import.meta.env.VITE_APP_ENABLE_RESPONSIVE_TABLE_FILTERING || "")
.trim() .trim()
@@ -38,9 +41,53 @@ function ResponsiveTable({ columns, mobileColumnKeys, scroll, ...rest }) {
return filteredColumns.length > 0 ? filteredColumns : columns; return filteredColumns.length > 0 ? filteredColumns : columns;
}, [columns, isPhone, isResponsiveFilteringEnabled, mobileColumnKeys]); }, [columns, isPhone, isResponsiveFilteringEnabled, mobileColumnKeys]);
const resolvedScroll = scroll ?? { x: "max-content" }; const resolvedScroll = useMemo(() => {
if (prefersHorizontalScroll) {
if (scroll == null) {
return { x: "max-content" };
}
return <Table columns={resolvedColumns} scroll={resolvedScroll} {...rest} />; 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 (
<Table
className={resolvedClassName}
columns={resolvedColumns}
scroll={resolvedScroll}
tableLayout={resolvedTableLayout}
{...rest}
/>
);
} }
ResponsiveTable.Summary = Table.Summary; ResponsiveTable.Summary = Table.Summary;

View File

@@ -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;
}

View File

@@ -1,114 +1,113 @@
const { isArray } = require("lodash"); const { isArray } = require("lodash");
const logger = require("../utils/logger"); const logger = require("../utils/logger");
function createLogEvent(socket, level, message) { function createLogEvent(socket, level, message) {
if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) { if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) {
// console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`); // console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`);
socket.emit("log-event", { socket.emit("log-event", {
timestamp: new Date(), timestamp: new Date(),
level, level,
message message
}); });
logger.log("ws-log-event", level, socket.user.email, socket.recordid, { logger.log("ws-log-event", level, socket.user.email, socket.recordid, {
wsmessage: message 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
);
if (socket.logEvents && isArray(socket.logEvents)) { if (socket.logEvents && isArray(socket.logEvents)) {
socket.logEvents.push({ socket.logEvents.push({
timestamp: new Date(), timestamp: new Date(),
level, level,
message message
}); });
} }
// if (level === "ERROR") { // if (level === "ERROR") {
// throw new Error(message); // 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) { function createXmlEvent(socket, xml, message, isError = false) {
if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("SILLY")) { if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("SILLY")) {
socket.emit("log-event", { socket.emit("log-event", {
timestamp: new Date(), timestamp: new Date(),
level: isError ? "ERROR" : "SILLY", level: isError ? "ERROR" : "SILLY",
message: `${message}: ${xml}` message: `${message}: ${xml}`
}); });
} }
logger.log( logger.log(
isError ? "ws-log-event-xml-error" : "ws-log-event-xml", isError ? "ws-log-event-xml-error" : "ws-log-event-xml",
isError ? "ERROR" : "SILLY", isError ? "ERROR" : "SILLY",
socket.user.email, socket.user.email,
socket.recordid, socket.recordid,
{ {
wsmessage: message, wsmessage: message,
xml xml
}, },
true true
); );
if (socket.logEvents && isArray(socket.logEvents)) { if (socket.logEvents && isArray(socket.logEvents)) {
socket.logEvents.push({ socket.logEvents.push({
timestamp: new Date(), timestamp: new Date(),
level: isError ? "ERROR" : "SILLY", level: isError ? "ERROR" : "SILLY",
message, message,
xml xml
}); });
} }
} }
function LogLevelHierarchy(level) { function LogLevelHierarchy(level) {
switch (level) { switch (level) {
case "XML": case "XML":
return 5; return 5;
case "SILLY": case "SILLY":
return 5; return 5;
case "DEBUG": case "DEBUG":
return 4; return 4;
case "INFO": case "INFO":
return 3; return 3;
case "WARN": case "WARN":
return 2; return 2;
case "ERROR": case "ERROR":
return 1; return 1;
default: default:
return 3; return 3;
} }
} }
exports.createLogEvent = createLogEvent; exports.createLogEvent = createLogEvent;