Merge branch 'dev' into fix/ab/sh-369-completion-doc-service-gate

This commit is contained in:
Alexandre Brandizzi 2026-09-16 20:16:13 -03:00 • committed by GitHub
commit 20662b57c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 129 additions and 1 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 185 KiB

View file

@ -1,4 +1,5 @@
import { WO_TABLE_COLS } from "./wo-table-cols";
import { WoTableHeaderLabel } from "./wo-table-header-label";
export function WoTableHead() {
return (
@ -25,7 +26,7 @@ export function WoTableHead() {
borderBottom: "1px solid var(--border)",
}}
>
{col.label}
<WoTableHeaderLabel colKey={col.key} label={col.label} />
{Boolean(srLabel) && <span className="sr-only">{srLabel}</span>}
</th>
);

View file

@ -0,0 +1,39 @@
import { Tooltip } from "@mui/material";
import { CircleQuestionMark } from "lucide-react";
import { getWoTableHeaderTooltip } from "@/domain/work-orders/constants/wo-table-header-tooltips";
type WoTableHeaderLabelProps = {
colKey: string;
label: string;
};
export function WoTableHeaderLabel({ colKey, label }: WoTableHeaderLabelProps) {
const tooltip = getWoTableHeaderTooltip(colKey);
if (!tooltip) {
return <>{label}</>;
}
return (
<span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}>
{label}
<Tooltip title={tooltip} arrow placement="top">
<button
type="button"
aria-label={`${label} column help`}
style={{
display: "inline-flex",
cursor: "help",
color: "var(--color-text-muted)",
padding: 0,
border: 0,
background: "transparent",
}}
>
<CircleQuestionMark size={13} aria-hidden="true" />
</button>
</Tooltip>
</span>
);
}

View file

@ -0,0 +1,17 @@
/**
* Help copy for date-column headers on the work orders board table.
* Keyed by the `WO_TABLE_COLS` column key; only columns with copy here show a
* header help icon. `appt` (Appt Time) is an intentional open point — do not
* add it without a business-rule decision.
*/
export const WO_TABLE_HEADER_TOOLTIPS = {
sched: "The date the work is planned to happen. Setting it moves the work order to Scheduled.",
due: "The deadline for the work — when it must be completed by.",
completed: "The date the vendor actually finished the work. Required to complete the work order.",
} as const;
export function getWoTableHeaderTooltip(colKey: string): string | undefined {
return colKey in WO_TABLE_HEADER_TOOLTIPS
? WO_TABLE_HEADER_TOOLTIPS[colKey as keyof typeof WO_TABLE_HEADER_TOOLTIPS]
: undefined;
}

View file

@ -0,0 +1,71 @@
import { screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it } from "vitest";
import { WoTableHead } from "@/app/(protected)/workorders/_components/list/table/wo-table-head";
import { getWoTableHeaderTooltip } from "@/domain/work-orders/constants/wo-table-header-tooltips";
import { renderWithProviders } from "@/test/test-utils";
const CASES = [
{
columnName: "SCHEDULE ON",
tooltip:
"The date the work is planned to happen. Setting it moves the work order to Scheduled.",
},
{
columnName: "DUE DATE",
tooltip: "The deadline for the work — when it must be completed by.",
},
{
columnName: "COMPLETED DATE",
tooltip: "The date the vendor actually finished the work. Required to complete the work order.",
},
];
function renderHead() {
return renderWithProviders(
<table>
<WoTableHead />
</table>,
{ withAuth: false },
);
}
describe("WoTableHead date column header tooltips (SH-195)", () => {
it.each(CASES)(
"shows the $columnName help icon and tooltip copy on hover",
async ({ columnName, tooltip }) => {
const user = userEvent.setup();
renderHead();
const header = screen.getByRole("columnheader", { name: new RegExp(`^${columnName}`) });
const icon = within(header).getByRole("button", { name: `${columnName} column help` });
await user.hover(icon);
const tip = await screen.findByText(tooltip);
expect(tip).toBeInTheDocument();
},
15000,
);
it("moves focus to the help icon on tab and keeps it keyboard reachable", async () => {
const user = userEvent.setup();
renderHead();
const header = screen.getByRole("columnheader", { name: /^SCHEDULE ON/ });
const icon = within(header).getByRole("button", { name: "SCHEDULE ON column help" });
await user.tab();
expect(icon).toHaveFocus();
});
it("does not add a help icon to Appt Time (open point, not implemented)", () => {
renderHead();
const header = screen.getByRole("columnheader", { name: "APPT TIME" });
expect(within(header).queryByRole("img")).not.toBeInTheDocument();
expect(getWoTableHeaderTooltip("appt")).toBeUndefined();
});
});