Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set row aria-label for search results #241

Merged
merged 4 commits into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 71 additions & 24 deletions src/components/search/SearchResultTable.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Immutable from 'immutable';
import { defineMessages, FormattedMessage } from 'react-intl';
import { defineMessages, intlShape, FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import get from 'lodash/get';
import { Table } from 'cspace-layout';
Expand All @@ -16,6 +16,11 @@ const messages = defineMessages({
id: 'searchResultTable.searchPending',
defaultMessage: '⋯',
},
rowLabel: {
id: 'searchResultTable.rowLabel',
description: 'The aria-label for a row',
defaultMessage: '{primary} selected row {index} of {total}',
},
});

/**
Expand All @@ -31,7 +36,7 @@ const isSortable = (column, searchDescriptor) => {
return (sortBy && (!searchDescriptor.getIn(['searchQuery', 'rel']) || sortBy.indexOf('/0/') === -1));
};

const rowRenderer = (params, location) => {
const rowRenderer = (params, location, ariaLabel) => {
// This is a fork of react-virtualized's default row renderer:
// https://github.com/bvaughn/react-virtualized/blob/master/source/Table/defaultRowRenderer.js

Expand All @@ -58,7 +63,7 @@ const rowRenderer = (params, location) => {
// onRowMouseOver ||
// onRowRightClick
) {
a11yProps['aria-label'] = 'row';
a11yProps['aria-label'] = ariaLabel;
a11yProps.tabIndex = 0;

if (onRowClick) {
Expand Down Expand Up @@ -122,6 +127,7 @@ const propTypes = {
}).isRequired,
formatCellData: PropTypes.func,
formatColumnLabel: PropTypes.func,
intl: intlShape,
isSearchPending: PropTypes.bool,
linkItems: PropTypes.bool,
// eslint-disable-next-line react/forbid-prop-types
Expand Down Expand Up @@ -156,11 +162,13 @@ export default class SearchResultTable extends Component {
constructor() {
super();

this.getColumnConfig = this.getColumnConfig.bind(this);
this.getItemLocation = this.getItemLocation.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleRowClick = this.handleRowClick.bind(this);
this.renderNoItems = this.renderNoItems.bind(this);
this.renderRow = this.renderRow.bind(this);
this.renderRowLabel = this.renderRowLabel.bind(this);
this.sort = this.sort.bind(this);
}

Expand Down Expand Up @@ -193,6 +201,35 @@ export default class SearchResultTable extends Component {
}
}

getColumnConfig() {
const {
columnSetName,
config,
searchDescriptor,
} = this.props;

const recordType = searchDescriptor.get('recordType');
const subresource = searchDescriptor.get('subresource');

const columnConfigurer = subresource
? config.subresources[subresource]
: config.recordTypes[recordType];

let columnConfig = get(columnConfigurer, ['columns', columnSetName]);

if (!columnConfig && columnSetName !== defaultProps.columnSetName) {
// Fall back to the default column set if the named one doesn't exist.

columnConfig = get(columnConfigurer, ['columns', defaultProps.columnSetName]);
}

if (!columnConfig) {
columnConfig = [];
}

return columnConfig;
}

getItemLocation(item) {
const {
config,
Expand Down Expand Up @@ -253,7 +290,31 @@ export default class SearchResultTable extends Component {
return <div className={emptyResultStyles.common}>{message}</div>;
}

renderRow(params) {
renderRowLabel(params, totalItems) {
const {
intl,
} = this.props;

const {
index,
rowData,
} = params;

const columnConfig = this.getColumnConfig();
const primaryCol = Object.keys(columnConfig)
.filter((col) => col !== 'workflowState')
.at(0);

const primaryData = rowData.get(primaryCol);
const label = primaryData
? intl.formatMessage(messages.rowLabel,
{ primary: primaryData, index: index + 1, total: totalItems })
: 'row';

return label;
}

renderRow(params, totalItems) {
const {
getItemLocation,
linkItems,
Expand All @@ -271,12 +332,13 @@ export default class SearchResultTable extends Component {
location = locationGetter(rowData);
}

return rowRenderer(params, location);
const ariaLabel = this.renderRowLabel(params, totalItems);

return rowRenderer(params, location, ariaLabel);
}

renderTable() {
const {
columnSetName,
config,
formatCellData,
formatColumnLabel,
Expand All @@ -288,8 +350,6 @@ export default class SearchResultTable extends Component {
} = this.props;

if (searchResult) {
const recordType = searchDescriptor.get('recordType');
const subresource = searchDescriptor.get('subresource');
const searchQuery = searchDescriptor.get('searchQuery');

const listTypeConfig = config.listTypes[listType];
Expand Down Expand Up @@ -320,21 +380,7 @@ export default class SearchResultTable extends Component {
items = Immutable.List.of(items);
}

const columnConfigurer = subresource
? config.subresources[subresource]
: config.recordTypes[recordType];

let columnConfig = get(columnConfigurer, ['columns', columnSetName]);

if (!columnConfig && columnSetName !== defaultProps.columnSetName) {
// Fall back to the default column set if the named one doesn't exist.

columnConfig = get(columnConfigurer, ['columns', defaultProps.columnSetName]);
}

if (!columnConfig) {
columnConfig = [];
}
const columnConfig = this.getColumnConfig();

const columns = Object.keys(columnConfig)
.filter((name) => !columnConfig[name].disabled)
Expand Down Expand Up @@ -402,6 +448,7 @@ export default class SearchResultTable extends Component {
}

const height = (heightBasis * rowHeight) + rowHeight;
const renderRowWithTotal = (params) => this.renderRow(params, totalItems);

return (
<div style={{ height }}>
Expand All @@ -416,7 +463,7 @@ export default class SearchResultTable extends Component {
sortBy={sortColumnName}
sortDirection={sortDir === 'desc' ? Table.SortDirection.DESC : Table.SortDirection.ASC}
noRowsRenderer={this.renderNoItems}
rowRenderer={this.renderRow}
rowRenderer={renderRowWithTotal}
/>
</div>
);
Expand Down
29 changes: 28 additions & 1 deletion test/specs/components/search/SearchResultTable.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ const searchResult = Immutable.fromJS({
},
});

const intl = {
formatMessage: (message) => `formatted ${message.id}`,
};

describe('SearchResultTable', () => {
beforeEach(function before() {
this.container = createTestContainer(this);
Expand All @@ -153,7 +157,10 @@ describe('SearchResultTable', () => {
it('should render as a div', function test() {
render(
<Router>
<SearchResultTable config={config} />
<SearchResultTable
config={config}
intl={intl}
/>
</Router>, this.container,
);

Expand All @@ -166,6 +173,7 @@ describe('SearchResultTable', () => {
<SearchResultTable
columnSetName="narrow"
config={config}
intl={intl}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
/>
Expand All @@ -183,6 +191,7 @@ describe('SearchResultTable', () => {
<SearchResultTable
columnSetName="foobar"
config={config}
intl={intl}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
/>
Expand All @@ -200,6 +209,7 @@ describe('SearchResultTable', () => {
<SearchResultTable
columnSetName="foobar"
config={config}
intl={intl}
searchDescriptor={groupSearchDescriptor}
searchResult={searchResult}
/>
Expand All @@ -216,6 +226,7 @@ describe('SearchResultTable', () => {
<Router>
<SearchResultTable
config={config}
intl={intl}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
/>
Expand All @@ -230,6 +241,7 @@ describe('SearchResultTable', () => {
<Router>
<SearchResultTable
config={config}
intl={intl}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
/>
Expand All @@ -244,6 +256,7 @@ describe('SearchResultTable', () => {
<Router>
<SearchResultTable
config={config}
intl={intl}
linkItems={false}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
Expand All @@ -259,6 +272,7 @@ describe('SearchResultTable', () => {
<Router>
<SearchResultTable
config={config}
intl={intl}
listType="foo"
searchDescriptor={searchDescriptor}
searchResult={searchResult}
Expand All @@ -274,6 +288,7 @@ describe('SearchResultTable', () => {
<Router>
<SearchResultTable
config={config}
intl={intl}
listType="bar"
searchDescriptor={searchDescriptor}
searchResult={searchResult}
Expand All @@ -298,6 +313,7 @@ describe('SearchResultTable', () => {
<Router>
<SearchResultTable
config={config}
intl={intl}
searchDescriptor={searchDescriptor}
searchResult={emptySearchResult}
/>
Expand All @@ -322,6 +338,7 @@ describe('SearchResultTable', () => {
<Router>
<SearchResultTable
config={config}
intl={intl}
isSearchPending
searchDescriptor={searchDescriptor}
searchResult={emptySearchResult}
Expand Down Expand Up @@ -353,6 +370,7 @@ describe('SearchResultTable', () => {
render(
<Router>
<SearchResultTable
intl={intl}
config={config}
searchDescriptor={searchDescriptor}
searchResult={singleSearchResult}
Expand All @@ -376,6 +394,7 @@ describe('SearchResultTable', () => {
render(
<Router>
<SearchResultTable
intl={intl}
config={config}
searchDescriptor={searchDescriptor}
searchResult={singleSearchResult}
Expand All @@ -390,6 +409,7 @@ describe('SearchResultTable', () => {
render(
<Router>
<SearchResultTable
intl={intl}
config={config}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
Expand All @@ -413,6 +433,7 @@ describe('SearchResultTable', () => {
render(
<Router>
<SearchResultTable
intl={intl}
config={config}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
Expand Down Expand Up @@ -442,6 +463,7 @@ describe('SearchResultTable', () => {
render(
<Router>
<SearchResultTable
intl={intl}
config={config}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
Expand Down Expand Up @@ -469,6 +491,7 @@ describe('SearchResultTable', () => {
render(
<Router>
<SearchResultTable
intl={intl}
config={config}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
Expand Down Expand Up @@ -500,6 +523,7 @@ describe('SearchResultTable', () => {
render(
<Router>
<SearchResultTable
intl={intl}
config={config}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
Expand Down Expand Up @@ -537,6 +561,7 @@ describe('SearchResultTable', () => {
render(
<Router>
<SearchResultTable
intl={intl}
config={config}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
Expand Down Expand Up @@ -567,6 +592,7 @@ describe('SearchResultTable', () => {
render(
<Router>
<SearchResultTable
intl={intl}
config={config}
searchName={searchName}
searchDescriptor={searchDescriptor}
Expand Down Expand Up @@ -596,6 +622,7 @@ describe('SearchResultTable', () => {
<Router>
<SearchResultTable
config={config}
intl={intl}
searchName={searchName}
searchDescriptor={searchDescriptor}
searchResult={searchResult}
Expand Down