Skip to content
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
17 changes: 14 additions & 3 deletions src/library-authoring/LibraryAuthoringPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
ClearFiltersButton,
FilterByBlockType,
FilterByTags,
FilterByPublished,
SearchContextProvider,
SearchKeywordsField,
SearchSortWidget,
Expand All @@ -46,6 +45,7 @@ import { SidebarBodyComponentId, useSidebarContext } from './common/context/Side
import { allLibraryPageTabs, ContentType, useLibraryRoutes } from './routes';

import messages from './messages';
import LibraryFilterByPublished from './generic/filter-by-published';

const HeaderActions = () => {
const intl = useIntl();
Expand Down Expand Up @@ -246,6 +246,17 @@ const LibraryAuthoringPage = ({
extraFilter.push(activeTypeFilters[activeKey]);
}

/*

<FilterByPublished key={
// It is necessary to re-render `FilterByPublished` every time `FilterByBlockType`
// appears or disappears, this is because when the menu is opened it is rendered
// in a previous state, causing an inconsistency in its position.
// By changing the key we can re-render the component.
!(insideCollections || insideUnits) ? 'filter-published-1' : 'filter-published-2'
}
*/

// Disable filtering by block/problem type when viewing the Collections tab.
const overrideTypesFilter = (insideCollections || insideUnits) ? new TypesFilterData() : undefined;

Expand Down Expand Up @@ -299,8 +310,8 @@ const LibraryAuthoringPage = ({
<SearchKeywordsField className="mr-3" />
<FilterByTags />
{!(insideCollections || insideUnits) && <FilterByBlockType />}
<FilterByPublished key={
// It is necessary to re-render `FilterByPublished` every time `FilterByBlockType`
<LibraryFilterByPublished key={
// It is necessary to re-render `LibraryFilterByPublished` every time `FilterByBlockType`
// appears or disappears, this is because when the menu is opened it is rendered
// in a previous state, causing an inconsistency in its position.
// By changing the key we can re-render the component.
Expand Down
4 changes: 2 additions & 2 deletions src/library-authoring/collections/LibraryCollectionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import NotFoundAlert from '../../generic/NotFoundAlert';
import {
ClearFiltersButton,
FilterByBlockType,
FilterByPublished,
FilterByTags,
SearchContextProvider,
SearchKeywordsField,
Expand All @@ -36,6 +35,7 @@ import { SidebarBodyComponentId, useSidebarContext } from '../common/context/Sid
import messages from './messages';
import { LibrarySidebar } from '../library-sidebar';
import LibraryCollectionComponents from './LibraryCollectionComponents';
import LibraryFilterByPublished from '../generic/filter-by-published';

const HeaderActions = () => {
const intl = useIntl();
Expand Down Expand Up @@ -218,7 +218,7 @@ const LibraryCollectionPage = () => {
<SearchKeywordsField className="mr-3" />
<FilterByTags />
<FilterByBlockType />
<FilterByPublished />
<LibraryFilterByPublished />
<ClearFiltersButton />
<ActionRow.Spacer />
<SearchSortWidget />
Expand Down
39 changes: 39 additions & 0 deletions src/library-authoring/component-picker/ComponentPicker.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -302,4 +302,43 @@ describe('<ComponentPicker />', () => {
expect(screen.queryByRole('tab', { name: /collections/i })).not.toBeInTheDocument();
expect(screen.queryByRole('tab', { name: /components/i })).not.toBeInTheDocument();
});

it('should not display never published filter', async () => {
render(<ComponentPicker />);

expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
fireEvent.click(screen.getByDisplayValue(/lib:sampletaxonomyorg1:tl1/i));

// Wait for the content library to load
const filterButton = await screen.findByRole('button', { name: /publish status/i });
fireEvent.click(filterButton);

// Verify the filters. Note: It's hard to verify the `published` filter,
// because there are many components with that text on the screen, but that's not the important thing.
expect(screen.getByText(/modified since publish/i)).toBeInTheDocument();
expect(screen.queryByText(/never published/i)).not.toBeInTheDocument();
});

it('should not display never published filter in collection page', async () => {
render(<ComponentPicker />);

expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
fireEvent.click(screen.getByDisplayValue(/lib:sampletaxonomyorg1:tl1/i));

// Wait for the content library to load
await screen.findByText(/Change Library/i);
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();

// Click on the collection card to open the sidebar
fireEvent.click(screen.queryAllByText('Collection 1')[0]);

// Wait for the content library to load
const filterButton = await screen.findByRole('button', { name: /publish status/i });
fireEvent.click(filterButton);

// Verify the filters. Note: It's hard to verify the `published` filter,
// because there are many components with that text on the screen, but that's not the important thing.
expect(screen.getByText(/modified since publish/i)).toBeInTheDocument();
expect(screen.queryByText(/never published/i)).not.toBeInTheDocument();
});
});
26 changes: 26 additions & 0 deletions src/library-authoring/generic/filter-by-published/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { useLibraryContext } from '../../common/context/LibraryContext';
import { FilterByPublished, PublishStatus } from '../../../search-manager';

/**
* When browsing library content for insertion into a course, we only show published
* content. In that case, there is no need for a 'Never Published' filter, which will
* never show results. This component removes that option from FilterByPublished
* when not relevant.
*/
const LibraryFilterByPublished : React.FC<Record<never, never>> = () => {
Comment thread
ChrisChV marked this conversation as resolved.
const { showOnlyPublished } = useLibraryContext();

if (showOnlyPublished) {
return (
<FilterByPublished visibleFilters={
[PublishStatus.Published, PublishStatus.Modified]
}
/>
);
}

return <FilterByPublished />;
};

export default LibraryFilterByPublished;
61 changes: 29 additions & 32 deletions src/search-manager/FilterByPublished.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import messages from './messages';
import SearchFilterWidget from './SearchFilterWidget';
import { useSearchContext } from './SearchManager';
import { PublishStatus } from './data/api';
import { allPublishFilters, PublishStatus } from './data/api';

interface FilterByPublishedProps {
visibleFilters?: PublishStatus[],
}

/**
* A button with a dropdown that allows filtering the current search by publish status
*/
const FilterByPublished: React.FC<Record<never, never>> = () => {
const FilterByPublished = ({
visibleFilters = allPublishFilters,
}: FilterByPublishedProps) => {
const intl = useIntl();
const {
publishStatus,
Expand All @@ -42,6 +48,26 @@ const FilterByPublished: React.FC<Record<never, never>> = () => {
};
const appliedFilters = publishStatusFilter.map(mode => ({ label: modeToLabel[mode] }));

const filterLabels = {
[PublishStatus.Published]: intl.formatMessage(messages.publishStatusPublished),
[PublishStatus.Modified]: intl.formatMessage(messages.publishStatusModified),
[PublishStatus.NeverPublished]: intl.formatMessage(messages.publishStatusNeverPublished),
};

const visibleFiltersToRender = visibleFilters.map((filter) => (
<MenuItem
key={filter}
as={Form.Checkbox}
value={filter}
onChange={() => { toggleFilterMode(filter); }}
Comment thread
ChrisChV marked this conversation as resolved.
>
<div>
{filterLabels[filter]}
<Badge variant="light" pill>{publishStatus[filter] ?? 0}</Badge>
</div>
</MenuItem>
));

return (
<SearchFilterWidget
appliedFilters={appliedFilters}
Expand All @@ -55,36 +81,7 @@ const FilterByPublished: React.FC<Record<never, never>> = () => {
value={publishStatusFilter}
>
<Menu className="block-type-refinement-menu" style={{ boxShadow: 'none' }}>
<MenuItem
as={Form.Checkbox}
value={PublishStatus.Published}
onChange={() => { toggleFilterMode(PublishStatus.Published); }}
>
<div>
{intl.formatMessage(messages.publishStatusPublished)}
<Badge variant="light" pill>{publishStatus[PublishStatus.Published] ?? 0}</Badge>
</div>
</MenuItem>
<MenuItem
as={Form.Checkbox}
value={PublishStatus.Modified}
onChange={() => { toggleFilterMode(PublishStatus.Modified); }}
>
<div>
{intl.formatMessage(messages.publishStatusModified)}
<Badge variant="light" pill>{publishStatus[PublishStatus.Modified] ?? 0}</Badge>
</div>
</MenuItem>
<MenuItem
as={Form.Checkbox}
value={PublishStatus.NeverPublished}
onChange={() => { toggleFilterMode(PublishStatus.NeverPublished); }}
>
<div>
{intl.formatMessage(messages.publishStatusNeverPublished)}
<Badge variant="light" pill>{publishStatus[PublishStatus.NeverPublished] ?? 0}</Badge>
</div>
</MenuItem>
{visibleFiltersToRender}
</Menu>
</Form.CheckboxSet>
</Form.Group>
Expand Down
2 changes: 2 additions & 0 deletions src/search-manager/data/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export enum PublishStatus {
NeverPublished = 'never',
}

export const allPublishFilters: PublishStatus[] = Object.values(PublishStatus);

/**
* Get the content search configuration from the CMS.
*/
Expand Down