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

implement ui config for hiding item type filters in agenda #901

Merged
merged 4 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 0 additions & 6 deletions assets/agenda/components/AgendaApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,11 @@ class AgendaApp extends SearchBase<any> {
<div className='wire-column__main-header-container'>
{!this.props.bookmarks && (
<AgendaFilters
aggregations={this.props.aggregations}
toggleFilter={this.props.toggleDropdownFilter}
activeFilter={this.props.activeFilter}
eventsOnlyAccess={this.props.eventsOnlyAccess}
restrictCoverageInfo={this.props.restrictCoverageInfo}
itemTypeFilter={this.props.itemTypeFilter}
locators={this.props.locators}
/>
)}
{
Expand Down Expand Up @@ -350,7 +348,6 @@ AgendaApp.propTypes = {
closePreview: PropTypes.func,
navigations: PropTypes.array.isRequired,
activeNavigation: PropTypes.arrayOf(PropTypes.string),
aggregations: PropTypes.object,
toggleDropdownFilter: PropTypes.func,
selectDate: PropTypes.func,
activeDate: PropTypes.number,
Expand All @@ -365,7 +362,6 @@ AgendaApp.propTypes = {
eventsOnlyAccess: PropTypes.bool,
restrictCoverageInfo: PropTypes.bool,
itemTypeFilter: PropTypes.string,
locators: PropTypes.array,
searchParams: PropTypes.object,
showSaveTopic: PropTypes.bool,
previewConfig: PropTypes.object,
Expand Down Expand Up @@ -395,7 +391,6 @@ const mapStateToProps = (state: any) => ({
activeTopic: activeTopicSelector(state),
activeNavigation: searchNavigationSelector(state),
bookmarks: state.bookmarks,
aggregations: state.aggregations,
activeDate: get(state, 'agenda.activeDate'),
activeGrouping: get(state, 'agenda.activeGrouping'),
eventsOnlyAccess: get(state, 'agenda.eventsOnlyAccess', false),
Expand All @@ -406,7 +401,6 @@ const mapStateToProps = (state: any) => ({
userSections: state.userSections,
featuredOnly: get(state, 'agenda.featuredOnly'),
context: state.context,
locators: get(state, 'locators.items', []),
setQuery: PropTypes.func.isRequired,
searchParams: searchParamsSelector(state),
showSaveTopic: showSaveTopicSelector(state),
Expand Down
51 changes: 28 additions & 23 deletions assets/agenda/components/AgendaFilters.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {get} from 'lodash';

Expand All @@ -12,6 +11,8 @@ import AgendaCoverageExistsFilter from './AgendaCoverageExistsFilter';
import AgendaItemTypeFilter from './AgendaItemTypeFilter';
import {AgendaCalendarAgendaFilter} from './AgendaCalendarAgendaFilter';
import {LocationFilter} from './LocationFilter';
import {IAgendaState} from 'interfaces/agenda';
import {ISearchState} from 'interfaces/search';

export const transformFilterBuckets = (filter: any, aggregations: any, props: any) => {
if (!filter.transformBuckets) {
Expand All @@ -21,17 +22,18 @@ export const transformFilterBuckets = (filter: any, aggregations: any, props: an
return filter.transformBuckets(filter, aggregations, props);
};

const renderFilter: any = {
item_type: (props: any) => (
const renderFilter = {
item_type: (props: IProps) => (
<AgendaItemTypeFilter
key="item_type"
itemTypeFilter={props.itemTypeFilter}
toggleFilter={props.toggleFilter}
eventsOnlyAccess={props.eventsOnlyAccess}
restrictCoverageInfo={props.restrictCoverageInfo}
config={props.itemTypeFilterConfig}
/>
),
calendar: (props: any) => (
calendar: (props: IProps) => (
<AgendaCalendarAgendaFilter
key="calendar"
aggregations={props.aggregations}
Expand All @@ -40,7 +42,7 @@ const renderFilter: any = {
itemTypeFilter={props.itemTypeFilter}
/>
),
location: (props: any) => (
location: (props: IProps) => (
!['events', 'combined'].includes(props.itemTypeFilter || 'combined') ? null : (
<LocationFilter
key="location"
Expand All @@ -49,7 +51,7 @@ const renderFilter: any = {
/>
)
),
region: (props: any) => (
region: (props: IProps) => (
!['events', 'planning', 'combined'].includes(props.itemTypeFilter || 'combined') ? null : (
<DropdownFilter
key="region"
Expand Down Expand Up @@ -84,7 +86,7 @@ const renderFilter: any = {
/>
)
),
coverage_type: (props: any) => (
coverage_type: (props: IProps) => (
!['planning', 'combined'].includes(props.itemTypeFilter || 'combined') ? null : (
<DropdownFilter
filterName={gettext('Coverage types')}
Expand All @@ -105,7 +107,7 @@ const renderFilter: any = {
/>
)
),
coverage_status: (props: any) => (
coverage_status: (props: IProps) => (
(props.eventsOnlyAccess || props.itemTypeFilter === 'events') ? null : (
<AgendaCoverageExistsFilter
key="coverage_status"
Expand All @@ -128,31 +130,34 @@ export function getDropdownItems(filter: any, aggregations: any, toggleFilter: a
return [];
}

function AgendaFiltersComponent(props: any) {
function AgendaFiltersComponent(props: IProps) {
return (
<div className='navbar navbar--flex navbar--quick-filter'>
{props.filtersConfig.map((filterName: any) => (
{props.filtersConfig.map((filterName) => (
renderFilter[filterName](props)
))}
</div>
);
}

AgendaFiltersComponent.propTypes = {
aggregations: PropTypes.object,
toggleFilter: PropTypes.func,
activeFilter: PropTypes.object,
eventsOnlyAccess: PropTypes.bool,
restrictCoverageInfo: PropTypes.bool,
itemTypeFilter: PropTypes.string,
locators: PropTypes.arrayOf(PropTypes.object),
filtersConfig: PropTypes.arrayOf(PropTypes.string),
};
interface IOwnProps {
toggleFilter: (fieldName: string, value?: string | null) => void;
activeFilter: ISearchState['activeFilter'];
eventsOnlyAccess: boolean;
restrictCoverageInfo: boolean;
itemTypeFilter?: 'events' | 'planning' | 'combined';
}

const mapStateToProps = (state: any) => ({
const mapStateToProps = (state: IAgendaState) => ({
aggregations: state.aggregations,
filtersConfig: agendaFiltersConfigSelector(state),
locators: state.locators?.items || [],
itemTypeFilterConfig: state.uiConfig.subnav?.item_type || {},
subnavConfig: state,
});

const AgendaFilters: React.ComponentType<any> = connect(mapStateToProps)(AgendaFiltersComponent);
type StateProps = ReturnType<typeof mapStateToProps>;

type IProps = StateProps & IOwnProps;

export default AgendaFilters;
export default connect<StateProps, null, IOwnProps, IAgendaState>(mapStateToProps)(AgendaFiltersComponent);
40 changes: 21 additions & 19 deletions assets/agenda/components/AgendaItemTypeFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import React from 'react';
import PropTypes from 'prop-types';
import {gettext} from 'utils';
import {AgendaDropdown} from './AgendaDropdown';
import {ItemTypeFilterConfig} from 'interfaces/configs';

function AgendaItemTypeFilter ({toggleFilter, itemTypeFilter, eventsOnlyAccess, restrictCoverageInfo}: any) {
interface IProps {
toggleFilter: (filedName: string, value: string | null) => void;
itemTypeFilter?: 'events' | 'planning' | 'combined';
eventsOnlyAccess: boolean;
restrictCoverageInfo: boolean;
config?: ItemTypeFilterConfig;
}

function AgendaItemTypeFilter ({toggleFilter, itemTypeFilter, eventsOnlyAccess, restrictCoverageInfo, config}: IProps) {
if (eventsOnlyAccess) {
return null;
}
Expand All @@ -16,7 +24,7 @@ function AgendaItemTypeFilter ({toggleFilter, itemTypeFilter, eventsOnlyAccess,
]
};

const filter: any = {
const filter = {
label: gettext('Events & Coverages'),
field: 'itemType',
};
Expand All @@ -32,14 +40,16 @@ function AgendaItemTypeFilter ({toggleFilter, itemTypeFilter, eventsOnlyAccess,
//dropdownMenuHeader={gettext('Item Types')}
hideLabelOnMobile
>
<button
key="events_only"
className="dropdown-item"
onClick={() => toggleFilter(filter.field, 'events')}
>
{gettext('Events Only')}
</button>
{restrictCoverageInfo ? null : (
{config?.events_only === false ? null : (
<button
key="events_only"
className="dropdown-item"
onClick={() => toggleFilter(filter.field, 'events')}
>
{gettext('Events Only')}
</button>
)}
{restrictCoverageInfo || config?.planning_only === false ? null : (
<button
key="planning_only"
className="dropdown-item"
Expand All @@ -52,12 +62,4 @@ function AgendaItemTypeFilter ({toggleFilter, itemTypeFilter, eventsOnlyAccess,
);
}

AgendaItemTypeFilter.propTypes = {
toggleFilter: PropTypes.func,
itemTypeFilter: PropTypes.string,
eventsOnlyAccess: PropTypes.bool,
restrictCoverageInfo: PropTypes.bool,
};


export default AgendaItemTypeFilter;
10 changes: 6 additions & 4 deletions assets/agenda/selectors.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import {get} from 'lodash';
import {uiConfigSelector} from 'ui/selectors';
import {IAgendaState} from 'interfaces/agenda';
import {AgendaFilterTypes} from 'interfaces/configs';

export const agendaFiltersConfigSelector = (state: any) => get(uiConfigSelector(state), 'subnav.filters') || [
export const agendaFiltersConfigSelector = (state: IAgendaState): AgendaFilterTypes[] => (state.uiConfig.subnav?.filters || [
'item_type',
'calendar',
'location',
'region',
'coverage_type',
'coverage_status',
];
]);

export const agendaSubnavItemTypeConfigSelector = (state: IAgendaState) => (state.uiConfig.subnav?.item_type || {});
10 changes: 9 additions & 1 deletion assets/interfaces/agenda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@ export interface IAgendaListGroupItem {
plan?: IAgendaItem['_id'];
}

export interface IAggregation { // incomplete
field: string;
buckets: Array<{
key: string;
doc_count: number;
}>;
}

export interface IAgendaState {
items: Array<IAgendaItem['_id']>;
fetchFrom: number;
Expand All @@ -249,7 +257,7 @@ export interface IAgendaState {
groups: Array<IAgendaListGroup>;
hiddenGroupsShown: {[dateString: string]: boolean};
};
aggregations?: {[field: string]: any}; // Too complex to even bother
aggregations?: {[field: string]: IAggregation};
activeItem?: IAgendaListGroupItem;
previewItem?: IAgendaItem['_id'];
previewGroup?: string;
Expand Down
10 changes: 9 additions & 1 deletion assets/interfaces/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,19 @@ export interface IAgendaPreviewConfig extends IPreviewConfig {
coverage_metadata_fields?: Array<string>;
}

export type AgendaFilterTypes = 'item_type' | 'calendar' | 'location' | 'region' | 'coverage_type' | 'coverage_status';

export interface ItemTypeFilterConfig {
events_only?: boolean;
planning_only?: boolean;
}

export interface IAgendaUIConfig extends IBaseUIConfig {
_id: 'agenda';
open_coverage_content_in_same_page?: boolean;
subnav?: {
filters?: Array<string>;
filters?: Array<AgendaFilterTypes>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be good if we were to have these different UI configs documented somewhere, that way PMs are able to get familiar with the different configurations available.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added some initial docs, will do the setup on readthedocs later

item_type?: ItemTypeFilterConfig;
};
preview?: IAgendaPreviewConfig;
details?: IAgendaPreviewConfig;
Expand Down
19 changes: 19 additions & 0 deletions newsroom/agenda/agenda.py
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,25 @@ def apply_filters(self, search: SearchQuery, section_filters=None):
}
}
)
elif app.config.get("AGENDA_DEFAULT_FILTER_HIDE_PLANNING"):
search.query["bool"]["filter"].append(
{
"bool": {
"should": [
{"term": {"item_type": "event"}},
{
# Match Events before ``item_type`` field was added
"bool": {
"must_not": [{"exists": {"field": "item_type"}}],
"filter": [{"exists": {"field": "event_id"}}],
},
},
],
"minimum_should_match": 1,
},
}
)
_remove_fields(search.source, ["planning_items", "display_dates"])
else:
# Don't include Planning items that are associated with an Event
search.query["bool"]["filter"].append(
Expand Down
6 changes: 6 additions & 0 deletions newsroom/web/default_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -799,3 +799,9 @@
#: .. versionadded: 2.7
#:
AGENDA_HIDE_COVERAGE_ASSIGNEES = False

#: Hides planning items from the default item type filter
#:
#: .. versionadded: 2.8
#:
AGENDA_DEFAULT_FILTER_HIDE_PLANNING = False
Loading