Skip to content

Commit 6fb9e27

Browse files
authored
fix: settings/messages accessibility (#14064)
refactor: enhance accessibility and styling in various components - Updated StringReader component to improve styling with min-width and leading adjustments. - Added keyboard event handling in TableComponent to prevent double activation of dialogs. - Enhanced SessionView component with new keyboard event handling for cell selection. - Improved TextModal styling for better alignment and readability. - Added aria-label to TextEditorArea for improved accessibility. - Introduced accessibility tests for HeaderMessagesComponent and messagesPage to ensure compliance. These changes aim to enhance user experience and accessibility across the application.
1 parent 38e1fdb commit 6fb9e27

6 files changed

Lines changed: 416 additions & 8 deletions

File tree

src/frontend/src/components/common/stringReaderComponent/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default function StringReader({
1212
return (
1313
<TextModal editable={editable} setValue={setValue} value={string ?? ""}>
1414
{/* INVISIBLE CHARACTER TO PREVENT AGgrid bug */}
15-
<span className="truncate">{string ?? "‎"}</span>
15+
<span className="min-w-0 truncate leading-6">{string ?? "‎"}</span>
1616
</TextModal>
1717
);
1818
}

src/frontend/src/modals/IOModal/components/session-view.tsx

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { useIsFetching } from "@tanstack/react-query";
2-
import type { NewValueParams, SelectionChangedEvent } from "ag-grid-community";
2+
import type {
3+
CellKeyDownEvent,
4+
NewValueParams,
5+
SelectionChangedEvent,
6+
SuppressKeyboardEventParams,
7+
} from "ag-grid-community";
38
import cloneDeep from "lodash/cloneDeep";
49
import { useEffect, useMemo, useState } from "react";
510
import { useTranslation } from "react-i18next";
@@ -16,6 +21,14 @@ import useAlertStore from "../../../stores/alertStore";
1621
import { useMessagesStore } from "../../../stores/messagesStore";
1722
import { extractColumnsFromRows, messagesSorter } from "../../../utils/utils";
1823

24+
function suppressMessageRowActionKeys(params: SuppressKeyboardEventParams) {
25+
return (
26+
params.event.key === "Enter" ||
27+
params.event.key === " " ||
28+
params.event.key === "Spacebar"
29+
);
30+
}
31+
1932
export default function SessionView({
2033
session,
2134
id,
@@ -73,10 +86,17 @@ export default function SessionView({
7386
files: t("messages.column.files"),
7487
};
7588

76-
const columns = extractColumnsFromRows(messages, "intersection").map((col) =>
77-
col.field && columnHeaderMap[col.field]
78-
? { ...col, headerName: columnHeaderMap[col.field] }
79-
: col,
89+
const columns = extractColumnsFromRows(messages, "intersection").map(
90+
(col) => ({
91+
...col,
92+
...(col.field && columnHeaderMap[col.field]
93+
? { headerName: columnHeaderMap[col.field] }
94+
: {}),
95+
...(col.field === "text"
96+
? { flex: 3, minWidth: 320, tooltipField: "text" }
97+
: {}),
98+
suppressKeyboardEvent: suppressMessageRowActionKeys,
99+
}),
80100
);
81101
const isFetchingCount = useIsFetching({
82102
queryKey: ["useGetMessagesQuery"],
@@ -149,26 +169,44 @@ export default function SessionView({
149169
deleteMessages({ ids: selectedRows });
150170
}
151171

172+
function handleCellKeyDown(event: CellKeyDownEvent) {
173+
const keyboardEvent = event.event as KeyboardEvent | undefined;
174+
if (keyboardEvent?.key !== " " && keyboardEvent?.key !== "Spacebar") {
175+
return;
176+
}
177+
178+
keyboardEvent.preventDefault();
179+
keyboardEvent.stopPropagation();
180+
event.node.setSelected(!event.node.isSelected(), false);
181+
setSelectedRows(event.api.getSelectedRows().map((row) => row.id));
182+
}
183+
152184
const editable = useMemo(() => {
153185
return playgroundPage
154186
? false
155187
: [{ field: "text", onUpdate: handleUpdateMessage, editableCell: false }];
156188
}, [handleUpdateMessage]);
157189

158190
return isFetching ? (
159-
<div className="flex h-full w-full items-center justify-center align-middle">
191+
<div
192+
aria-label={t("common.loading")}
193+
className="flex h-full w-full items-center justify-center align-middle"
194+
role="status"
195+
>
160196
<Loading></Loading>
161197
</div>
162198
) : (
163199
<TableComponent
164200
key={"sessionView"}
201+
tableLabel={t("messages.title")}
165202
onDelete={playgroundPage ? undefined : handleRemoveMessages}
166203
readOnlyEdit
167204
editable={editable}
168205
overlayNoRowsTemplate={t("table.noRowsToShow")}
169206
onSelectionChanged={(event: SelectionChangedEvent) => {
170207
setSelectedRows(event.api.getSelectedRows().map((row) => row.id));
171208
}}
209+
onCellKeyDown={handleCellKeyDown}
172210
rowSelection={playgroundPage ? undefined : "multiple"}
173211
suppressRowClickSelection={true}
174212
pagination={true}

src/frontend/src/modals/textModal/components/textEditorArea/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const TextEditorArea = ({
2121
}
2222
return (
2323
<Textarea
24+
aria-label={t("modal.viewText")}
2425
readOnly={readonly}
2526
className={`w-full custom-scroll ${left ? "min-h-32" : "h-full"} ${
2627
resizable ? "resize-y" : "resize-none"

src/frontend/src/modals/textModal/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export default function TextModal({
4444
tabIndex={-1}
4545
data-langflow-text-cell-trigger
4646
aria-haspopup="dialog"
47-
className="h-full w-full truncate text-left"
47+
className="flex h-6 min-h-6 w-full items-center truncate text-left leading-6"
4848
>
4949
{children}
5050
</button>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { render } from "@testing-library/react";
2+
import { axe } from "@/utils/a11y-test";
3+
import HeaderMessagesComponent from "..";
4+
5+
describe("HeaderMessagesComponent accessibility", () => {
6+
it("should have no axe violations", async () => {
7+
const { container } = render(<HeaderMessagesComponent />);
8+
9+
expect(await axe(container)).toHaveNoViolations();
10+
});
11+
});

0 commit comments

Comments
 (0)