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

Planning: If multilingual Events or Planning items are filtered by language - show them in this language in the list views [SDESK-7060] #1862

Merged
merged 9 commits into from
Oct 16, 2023
5 changes: 5 additions & 0 deletions client/apps/Planning/PlanningList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
LIST_VIEW_TYPE,
IContactItem,
SORT_FIELD,
ICommonSearchParams,
} from '../../interfaces';

import * as actions from '../../actions';
Expand Down Expand Up @@ -59,6 +60,7 @@ interface IProps {
contacts: {[key: string]: IContactItem};
listViewType: LIST_VIEW_TYPE;
sortField: SORT_FIELD;
currentSearch: ICommonSearchParams<IEventOrPlanningItem>;

openPreview(item: IEventOrPlanningItem): void;
edit(item: IEventOrPlanningItem): void;
Expand Down Expand Up @@ -92,6 +94,7 @@ const mapStateToProps = (state) => ({
contacts: selectors.general.contactsById(state),
listViewType: selectors.main.getCurrentListViewType(state),
sortField: selectors.main.getCurrentSortField(state),
currentSearch: selectors.main.currentSearch(state)
});

const mapDispatchToProps = (dispatch) => ({
Expand Down Expand Up @@ -168,6 +171,7 @@ export class PlanningListComponent extends React.PureComponent<IProps> {
contacts,
listViewType,
sortField,
currentSearch
} = this.props;

return (
Expand Down Expand Up @@ -206,6 +210,7 @@ export class PlanningListComponent extends React.PureComponent<IProps> {
listViewType={listViewType}
sortField={sortField}
indexItems
searchParams={currentSearch.advancedSearch}
/>
</React.Fragment>
);
Expand Down
8 changes: 6 additions & 2 deletions client/components/Events/EventItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {renderFields} from '../fields';
import {CreatedUpdatedColumn} from '../UI/List/CreatedUpdatedColumn';
import {EventDateTimeColumn} from './EventDateTimeColumn';
import * as actions from '../../actions';
import {getUserInterfaceLanguageFromCV} from '../../utils/users';

interface IState {
hover: boolean;
Expand All @@ -44,7 +45,8 @@ class EventItemComponent extends React.Component<IProps, IState> {
return isItemDifferent(this.props, nextProps) ||
this.state.hover !== nextState.hover ||
this.props.minTimeWidth !== nextProps.minTimeWidth ||
this.props.lockedItems != nextProps.lockedItems;
this.props.lockedItems != nextProps.lockedItems ||
this.props.filterLanguage !== nextProps.filterLanguage;
}

onItemHoverOn() {
Expand Down Expand Up @@ -156,6 +158,7 @@ class EventItemComponent extends React.Component<IProps, IState> {
active,
refNode,
listViewType,
filterLanguage
} = this.props;

if (!item) {
Expand All @@ -177,6 +180,7 @@ class EventItemComponent extends React.Component<IProps, IState> {
const isExpired = isItemExpired(item);

const secondaryFields = get(listFields, 'event.secondary_fields', EVENTS.LIST.SECONDARY_FIELDS);
const language = filterLanguage || item.language || getUserInterfaceLanguageFromCV();

return (
<Item
Expand Down Expand Up @@ -216,7 +220,7 @@ class EventItemComponent extends React.Component<IProps, IState> {
<Row>
<span className="sd-overflow-ellipsis sd-list-item--element-grow">
{renderFields(get(listFields, 'event.primary_fields',
EVENTS.LIST.PRIMARY_FIELDS), item)}
EVENTS.LIST.PRIMARY_FIELDS), item, {}, language)}
</span>
</Row>
<Row>
Expand Down
5 changes: 4 additions & 1 deletion client/components/Main/ListGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import moment from 'moment-timezone';
import {ListGroupItem} from './';
import {Group, Header} from '../UI/List';
import {IEventOrPlanningItem, LIST_VIEW_TYPE, SORT_FIELD} from '../../interfaces';
import {ICommonAdvancedSearchParams, IEventOrPlanningItem, LIST_VIEW_TYPE, SORT_FIELD} from '../../interfaces';
import {timeUtils} from '../../utils';

const TIME_COLUMN_MIN_WIDTH = {
Expand Down Expand Up @@ -78,6 +78,7 @@ interface IProps {
listViewType?: string;
sortField?: string;
listBoxGroupProps: {};
searchParams:ICommonAdvancedSearchParams;
}

export class ListGroup extends React.Component<IProps> {
Expand Down Expand Up @@ -145,6 +146,7 @@ export class ListGroup extends React.Component<IProps> {
listViewType,
sortField,
listBoxGroupProps,
searchParams,
} = this.props;

// with defaults
Expand Down Expand Up @@ -205,6 +207,7 @@ export class ListGroup extends React.Component<IProps> {
listViewType: listViewType,
sortField: sortField,
minTimeWidth: minTimeWidth,
searchParams: searchParams,
};

if (indexItems) {
Expand Down
7 changes: 5 additions & 2 deletions client/components/Main/ListGroupItem.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React from 'react';
import {debounce, indexOf} from 'lodash';

import {
IEventListItemProps,
IPlanningListItemProps,
IEventOrPlanningItem,
IEventItem, IPlanningItem, IBaseListItemProps
IEventItem, IPlanningItem, IBaseListItemProps, ICommonAdvancedSearchParams
} from '../../interfaces';

import {EventItem, EventItemWithPlanning} from '../Events';
Expand All @@ -27,6 +26,7 @@ interface IProps extends Omit<
index: number;
navigateDown?: boolean;
minTimeWidth?: string;
searchParams?: ICommonAdvancedSearchParams;

onDoubleClick(item: IEventOrPlanningItem): void;
showRelatedPlannings(item: IEventItem): void;
Expand Down Expand Up @@ -122,6 +122,7 @@ export class ListGroupItem extends React.Component<IProps, IState> {
listViewType,
sortField,
minTimeWidth,
searchParams,
} = this.props;
const itemType = getItemType(item);

Expand Down Expand Up @@ -151,6 +152,7 @@ export class ListGroupItem extends React.Component<IProps, IState> {
...itemProps,
item: item as IEventItem,
calendars: calendars,
filterLanguage: searchParams?.language,
multiSelected: indexOf(selectedEventIds, item._id) !== -1,
[EVENTS.ITEM_ACTIONS.EDIT_EVENT.actionName]:
itemActions[EVENTS.ITEM_ACTIONS.EDIT_EVENT.actionName],
Expand Down Expand Up @@ -193,6 +195,7 @@ export class ListGroupItem extends React.Component<IProps, IState> {
contentTypes: contentTypes,
agendas: agendas,
date: date,
filterLanguage: searchParams?.language,
onAddCoverageClick: onAddCoverageClick,
multiSelected: indexOf(selectedPlanningIds, item._id) !== -1,
showAddCoverage: showAddCoverage,
Expand Down
5 changes: 4 additions & 1 deletion client/components/Main/ListPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {superdeskApi} from '../../superdeskApi';
import {IDesk, IUser} from 'superdesk-api';
import {
FILTER_TYPE,
IAgenda, ICalendar, IContactItem,
IAgenda, ICalendar, ICommonAdvancedSearchParams, IContactItem,
IEventItem,
IEventOrPlanningItem, IG2ContentType,
ILockedItems,
Expand Down Expand Up @@ -68,6 +68,7 @@ interface IProps {
listViewType: LIST_VIEW_TYPE;
sortField: SORT_FIELD;
userInitiatedSearch?: boolean;
searchParams?: ICommonAdvancedSearchParams

onItemClick(item: IEventOrPlanningItem): void;
onDoubleClick(item: IEventOrPlanningItem): void;
Expand Down Expand Up @@ -318,6 +319,7 @@ export class ListPanel extends React.Component<IProps, IState> {
contacts,
listViewType,
sortField,
searchParams
} = this.props;

let indexFrom = 0;
Expand Down Expand Up @@ -396,6 +398,7 @@ export class ListPanel extends React.Component<IProps, IState> {
listViewType: listViewType,
sortField: sortField,
listBoxGroupProps: listBoxGroupProps,
searchParams: searchParams,
...propsForNestedListItems,
};

Expand Down
8 changes: 6 additions & 2 deletions client/components/Planning/PlanningItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
} from '../../utils';
import {renderFields} from '../fields';
import * as actions from '../../actions';
import {getUserInterfaceLanguageFromCV} from '../../utils/users';

interface IState {
hover: boolean;
Expand Down Expand Up @@ -64,7 +65,8 @@ class PlanningItemComponent extends React.Component<IProps, IState> {
planningUtils.getAgendaNames(this.props.item, this.props.agendas),
planningUtils.getAgendaNames(nextProps.item, nextProps.agendas)
) ||
this.props.minTimeWidth !== nextProps.minTimeWidth;
this.props.minTimeWidth !== nextProps.minTimeWidth ||
this.props.filterLanguage !== nextProps.filterLanguage;
}

onItemHoverOn() {
Expand Down Expand Up @@ -184,6 +186,7 @@ class PlanningItemComponent extends React.Component<IProps, IState> {
agendas,
contacts,
listViewType,
filterLanguage
} = this.props;

if (!item) {
Expand All @@ -197,6 +200,7 @@ class PlanningItemComponent extends React.Component<IProps, IState> {
const isExpired = isItemExpired(item);
const secondaryFields = get(listFields, 'planning.secondary_fields', PLANNING.LIST.SECONDARY_FIELDS);
const {querySelectorParent} = superdeskApi.utilities;
const language = filterLanguage || item.language || getUserInterfaceLanguageFromCV();

return (
<Item
Expand Down Expand Up @@ -235,7 +239,7 @@ class PlanningItemComponent extends React.Component<IProps, IState> {
<Row>
<span className="sd-overflow-ellipsis sd-list-item--element-grow">
{renderFields(get(listFields, 'planning.primary_fields',
PLANNING.LIST.PRIMARY_FIELDS), item)}
PLANNING.LIST.PRIMARY_FIELDS), item, {}, language)}
</span>

{event && (
Expand Down
8 changes: 6 additions & 2 deletions client/components/fields/headline.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import PropTypes from 'prop-types';
import {getTranslatedValue} from '.';
import {IFieldsProps} from '../../interfaces';

export const headline = ({item}) => item.headline || null;
export const headline = ({item, language}: IFieldsProps) => getTranslatedValue(
language, item, 'headline') || item.headline || null;

headline.propTypes = {
item: PropTypes.shape({
headline: PropTypes.string,
}).isRequired,
};
language: PropTypes.string,
};
31 changes: 25 additions & 6 deletions client/components/fields/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React from 'react';
import {sortBy} from 'lodash';

import {IProfileSchema, IRenderPanelType, ISearchProfile, PREVIEW_PANEL} from '../../interfaces';
import {IEventOrPlanningItem, IProfileSchema, IRenderPanelType, ISearchProfile, PREVIEW_PANEL} from '../../interfaces';
import {superdeskApi} from '../../superdeskApi';
import {getUserInterfaceLanguageFromCV} from '../../utils/users';

import {name} from './name';
import {slugline} from './slugline';
Expand Down Expand Up @@ -42,12 +41,15 @@ export function registerField(id, component) {
/**
* Render list of fields for given item
* @param {Array|String} fields
* @param {Object} item
* @param {IEventOrPlanningItem} item
* @param {Object} props
*/
export function renderFields(fields, item, props = {}) {
const language = getUserInterfaceLanguageFromCV();

export function renderFields(
fields: Array<any>|string,
item: IEventOrPlanningItem,
props: Object = {},
language: string = ''
) {
return (Array.isArray(fields) ? fields : [fields]).map((id) => {
const Component = registeredFields[id];

Expand All @@ -66,6 +68,23 @@ export function renderFields(fields, item, props = {}) {
});
}

/**
* Get translated field value based on language
* @param {String} language
* @param {IEventOrPlanningItem} item
* @param {String} fieldName
*/
export function getTranslatedValue(language: string, item: IEventOrPlanningItem, fieldName: string): string | null {
if (item.translations) {
const matchingTranslation = item.translations.find(
(translation) => translation.field === fieldName && translation.language === language
);

return matchingTranslation ? matchingTranslation.value : null;
}
return null;
}

function getFieldsForPanel(panelType: IRenderPanelType) {
switch (panelType) {
case 'editor':
Expand Down
8 changes: 6 additions & 2 deletions client/components/fields/name.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import PropTypes from 'prop-types';
import {getTranslatedValue} from '.';
import {IFieldsProps} from '../../interfaces';

export const name = ({item}) => item.name || null;
export const name = ({item, language}: IFieldsProps) => getTranslatedValue(language, item, 'name') ||
item.name || null;

name.propTypes = {
item: PropTypes.shape({
name: PropTypes.string,
}).isRequired,
};
language: PropTypes.string,
};
10 changes: 8 additions & 2 deletions client/components/fields/slugline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,23 @@ import React from 'react';
import PropTypes from 'prop-types';

import {get} from 'lodash';
import {getTranslatedValue} from '.';
import {IFieldsProps} from '../../interfaces';

export const slugline = ({item}) => {
export const slugline = ({item, language}: IFieldsProps) => {
if (!get(item, 'slugline', '')) {
return null;
}

return (<span className="sd-list-item__slugline">{item.slugline}</span>);
return (
<span className="sd-list-item__slugline">{getTranslatedValue(language, item, 'slugline') ||
item.slugline}</span>
);
};

slugline.propTypes = {
item: PropTypes.shape({
slugline: PropTypes.string,
}).isRequired,
language: PropTypes.string,
};
7 changes: 7 additions & 0 deletions client/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,7 @@ export interface IBaseListItemProps<T> {
export interface IEventListItemProps extends IBaseListItemProps<IEventItem> {
relatedPlanningText?: string;
calendars: Array<ICalendar>;
filterLanguage?: string;
toggleRelatedPlanning?(event: React.MouseEvent): void;
}

Expand All @@ -863,6 +864,7 @@ export interface IPlanningListItemProps extends IBaseListItemProps<IPlanningItem
agendas: Array<IAgenda>;
users: Array<IUser>;
desks: Array<IDesk>;
filterLanguage?: string;
// showUnlock?: boolean; // Is this used anymore?
hideItemActions: boolean;
showAddCoverage: boolean;
Expand Down Expand Up @@ -1579,6 +1581,11 @@ export interface IContentTemplate extends IBaseRestApiResponse {
};
}

export interface IFieldsProps {
item: IEventOrPlanningItem;
language?: string;
}

interface IMainStateSearch<T> {
lastRequestParams: T;
fulltext?: string;
Expand Down
Loading