Skip to content

Commit

Permalink
Add control to clear all selected dashboard filters (#6486)
Browse files Browse the repository at this point in the history
  • Loading branch information
acelaya authored Jul 30, 2024
1 parent abcd7c6 commit ef62177
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { MultiSelect } from '@hypothesis/frontend-shared';
import {
CancelIcon,
IconButton,
MultiSelect,
} from '@hypothesis/frontend-shared';
import { useMemo } from 'preact/hooks';

import type { Assignment, Course, Student } from '../../api-types';
Expand All @@ -12,6 +16,7 @@ export type DashboardActivityFiltersProps = {
onAssignmentsChange: (newAssignmentIds: string[]) => void;
selectedStudentIds: string[];
onStudentsChange: (newStudentIds: string[]) => void;
onClearSelection?: () => void;
};

/**
Expand All @@ -25,7 +30,12 @@ export default function DashboardActivityFilters({
onAssignmentsChange,
selectedStudentIds,
onStudentsChange,
onClearSelection,
}: DashboardActivityFiltersProps) {
const hasSelection =
selectedStudentIds.length > 0 ||
selectedAssignmentIds.length > 0 ||
selectedCourseIds.length > 0;
const { dashboard } = useConfig(['dashboard']);
const { routes } = dashboard;

Expand Down Expand Up @@ -123,6 +133,15 @@ export default function DashboardActivityFilters({
</MultiSelect.Option>
))}
</MultiSelect>
{hasSelection && onClearSelection && (
<IconButton
title="Clear filters"
icon={CancelIcon}
classes="text-grey-7"
onClick={() => onClearSelection()}
data-testid="clear-button"
/>
)}
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export default function OrganizationActivity() {
onAssignmentsChange={assignmentIds => updateFilters({ assignmentIds })}
selectedCourseIds={courseIds}
onCoursesChange={courseIds => updateFilters({ courseIds })}
onClearSelection={() =>
updateFilters({ studentIds: [], assignmentIds: [], courseIds: [] })
}
/>
<OrderableActivityTable
loading={courses.isLoading}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,28 +113,17 @@ describe('DashboardActivityFilters', () => {
$imports.$restore();
});

/**
@param {Object} [selection]
@param {Object[]} [selection.selectedStudentIds]
@param {Object[]} [selection.selectedAssignmentIds]
@param {Object[]} [selection.selectedCourseIds]
*/
function createComponent(selection = {}) {
const {
selectedStudentIds = [],
selectedAssignmentIds = [],
selectedCourseIds = [],
} = selection;

function createComponent(props = {}) {
const wrapper = mount(
<Config.Provider value={fakeConfig}>
<DashboardActivityFilters
selectedCourseIds={selectedCourseIds}
selectedCourseIds={[]}
onCoursesChange={onCoursesChange}
selectedAssignmentIds={selectedAssignmentIds}
selectedAssignmentIds={[]}
onAssignmentsChange={onAssignmentsChange}
selectedStudentIds={selectedStudentIds}
selectedStudentIds={[]}
onStudentsChange={onStudentsChange}
{...props}
/>
</Config.Provider>,
);
Expand Down Expand Up @@ -270,6 +259,52 @@ describe('DashboardActivityFilters', () => {
});
});

describe('clear filters', () => {
[
// Callback provided, but no items selected
{
props: { onClearSelection: sinon.stub() },
shouldRenderClearButton: false,
},
// Callback not provided
{
props: {
selectedAssignmentIds: [...assignments],
selectedStudentIds: [...studentsWithName],
},
shouldRenderClearButton: false,
},
// Callback provided and items selected
{
props: {
onClearSelection: sinon.stub(),
selectedCourseIds: [...courses],
},
shouldRenderClearButton: true,
},
].forEach(({ props, shouldRenderClearButton }) => {
it('shows clear button if `onClearSelection` callback was provided and some items are selected', () => {
const wrapper = createComponent(props);
assert.equal(
shouldRenderClearButton,
wrapper.exists('[data-testid="clear-button"]'),
);
});
});

it('invokes `onClearSelection` when clear button is clicked', () => {
const onClearSelection = sinon.stub();
const wrapper = createComponent({
onClearSelection,
selectedCourseIds: [...courses],
});

wrapper.find('button[data-testid="clear-button"]').simulate('click');

assert.called(onClearSelection);
});
});

it(
'should pass a11y checks',
checkAccessibility({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ describe('OrganizationActivity', () => {
let fakeConfig;

beforeEach(() => {
// Reset query string before every test
history.replaceState(null, '', '?');

wrappers = [];

fakeUseAPIFetch = sinon.stub().returns({
Expand Down Expand Up @@ -192,6 +195,20 @@ describe('OrganizationActivity', () => {
});
});

it('allows filters to be cleared', () => {
const wrapper = createComponent();
const filters = wrapper.find('DashboardActivityFilters');

act(() => filters.props().onClearSelection());
wrapper.update();

assert.calledWith(fakeUseAPIFetch.lastCall, sinon.match.string, {
h_userid: [],
assignment_id: [],
course_id: [],
});
});

it(
'should pass a11y checks',
checkAccessibility({
Expand Down

0 comments on commit ef62177

Please sign in to comment.