Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into release/2.5
Browse files Browse the repository at this point in the history
  • Loading branch information
petrjasek committed Oct 3, 2023
2 parents cbb2f44 + 509fe27 commit 4448716
Show file tree
Hide file tree
Showing 145 changed files with 5,570 additions and 3,743 deletions.
7 changes: 6 additions & 1 deletion DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ It will run database migrations when needed.
* Save destination
* Save subscriber

## Running local code against a remote instance


* Generate a SSH key if you don't have one already by running `ssh-keygen -t rsa`
* Share your public key with colleagues to get an account created on a test server
* Choose an instance you want to connect to and set `MONGO_DBNAME` environment variable in `newsroom-app/server/.env`. Example: `MONGO_DBNAME=nra-develop`
* Start **only redis** service via docker `docker-compose up redis`
* Run the following command in a terminal `ssh -L 9200:data-sd:9201 -L 27017:data-sd:27017 host7.sourcefabric.org` - it will connect to the test server and forward ports of mongo db and elastic search services


79 changes: 46 additions & 33 deletions assets/agenda/components/AgendaApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ class AgendaApp extends BaseApp {
}
}

const showFilters = Object.values(this.props.searchParams ?? {}).find((val) => val != null) != null ||
this.props.activeTopic != null ||
Object.keys(this.props.activeFilter ?? {}).length > 0 ||
this.props.activeQuery != null ||
this.props.itemTypeFilter != null;

return (
(this.props.itemToOpen ? [<AgendaItemDetails key="itemDetails"
item={this.props.itemToOpen}
Expand Down Expand Up @@ -225,37 +231,45 @@ class AgendaApp extends BaseApp {
)}
</div>
<div className={mainClassName}>
{!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}
/>
)}

<SearchResultsBar
minimizeSearchResults={this.state.minimizeSearchResults}

showTotalItems={showTotalItems}
showTotalLabel={showTotalLabel}
showSaveTopic={showSaveTopic}

totalItems={this.props.totalItems}
totalItemsLabel={totalItemsLabel}

saveMyTopic={saveMyTopic}
activeTopic={this.props.activeTopic}
topicType="agenda"

newItems={this.props.newItems}
refresh={this.props.fetchItems}

setQuery={this.props.setQuery}
>
<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}
/>
)}
{
showFilters && (
<SearchResultsBar
initiallyOpen={showFilters}
minimizeSearchResults={this.state.minimizeSearchResults}

showTotalItems={showTotalItems}
showTotalLabel={showTotalLabel}
showSaveTopic={showSaveTopic}
onClearAll={() => {
this.props.toggleDropdownFilter('itemType', null);
}}

totalItems={this.props.totalItems}
totalItemsLabel={totalItemsLabel}

saveMyTopic={saveMyTopic}
activeTopic={this.props.activeTopic}
topicType="agenda"

newItems={this.props.newItems}
refresh={this.props.fetchItems}

setQuery={this.props.setQuery}
/>
)
}
<AgendaListViewControls
activeView={this.props.activeView}
setView={this.props.setView}
Expand All @@ -264,8 +278,7 @@ class AgendaApp extends BaseApp {
featuredFilter={this.props.featuredOnly}
hasAgendaFeaturedItems={this.props.hasAgendaFeaturedItems}
/>
</SearchResultsBar>

</div>
<AgendaList
actions={this.props.actions}
activeView={this.props.activeView}
Expand Down
2 changes: 1 addition & 1 deletion assets/agenda/components/AgendaAttachments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function AgendaAttachments({item}: any) {
</div>
<div className="coverage-item__column">
<a className="icon-button" href={attachment.href + '?filename=' + attachment.name} aria-label={gettext('Download')}>
<i className="icon--download icon--gray-dark"></i>
<i className="icon--download"></i>
</a>
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions assets/agenda/components/AgendaContacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ export function AgendaContacs({item, inList = false}: IProps) {
<div
key={contact._id}
className={classNames({
'd-flex': inList,
'wire-articles__item__meta-row': !inList,
'd-flex gap-1': inList,
'wire-articles__item__meta-row wire-articles__item__meta-row--contact': !inList,
})}
>
<i className='icon-small--user icon--gray-dark'></i>
<i className='icon-small--user'></i>
<span>{`${contact.name}${(contact.name && contact.organisation) ? ', ' : ''}${contact.organisation} ${contact.phone} ${contact.mobile} `}
{contact.email && <a href={`mailto:${contact.email}`} target="_blank">{contact.email}</a>}
</span>
Expand Down
3 changes: 2 additions & 1 deletion assets/agenda/components/AgendaCoverageExistsFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ function AgendaCoverageExistsFilter ({toggleFilter, activeFilter}: any) {
activeFilter={activeFilter}
toggleFilter={toggleFilter}
getFilterLabel={getActiveFilterLabel}
optionLabel={gettext('Coverage')}
>
<button
key='coverage-planned'
Expand Down Expand Up @@ -77,4 +78,4 @@ AgendaCoverageExistsFilter.propTypes = {
activeFilter: PropTypes.object,
};

export default AgendaCoverageExistsFilter;
export default AgendaCoverageExistsFilter;
2 changes: 1 addition & 1 deletion assets/agenda/components/AgendaCoverages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function AgendaCoveragesComponent({item, coverages, wireItems, actions, user, on
</span>
{coverage.workflow_status !== WORKFLOW_STATUS.COMPLETED && coverage.scheduled != null && (
<span className='d-flex text-nowrap'>
<i className='icon-small--clock icon--gray-dark me-1'></i>
<i className='icon-small--clock me-1'></i>
<span className='coverage-item__text-label me-1'>{gettext('expected')}:</span>
<span>{formatCoverageDate(coverage)}</span>
</span>
Expand Down
34 changes: 22 additions & 12 deletions assets/agenda/components/AgendaDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';
import {gettext} from 'utils';
import {Dropdown} from '../../components/Dropdown';

export function AgendaDropdown({filter, activeFilter, toggleFilter, children, getFilterLabel}: any) {
interface IProps {
filter: any;
optionLabel?: string;
activeFilter?: any;
toggleFilter: (filedName: string, value: any) => void;
getFilterLabel?: (filter: string, activeFilter: string, isActive: boolean) => string;
children?: any;
}

export function AgendaDropdown({
filter,
optionLabel,
activeFilter,
toggleFilter,
children,
getFilterLabel,
}: IProps) {

const isActive = activeFilter[filter.field];
const getActiveFilterLabel = getFilterLabel != null ?
Expand All @@ -14,25 +29,20 @@ export function AgendaDropdown({filter, activeFilter, toggleFilter, children, ge

return (
<Dropdown
isActive={isActive}
icon={filter.icon}
optionLabel={optionLabel}
label={getActiveFilterLabel(filter, activeFilter, isActive)}
>
<button
type='button'
className='dropdown-item'
onClick={() => toggleFilter(filter.field, null)}
>{gettext(filter.label)}</button>
>
{gettext(filter.label)}
</button>
<div className='dropdown-divider'></div>
{children}
</Dropdown>
);
}

AgendaDropdown.propTypes = {
children: PropTypes.node,
filter: PropTypes.object,
toggleFilter: PropTypes.func,
activeFilter: PropTypes.object,
getFilterLabel: PropTypes.func,
};

2 changes: 1 addition & 1 deletion assets/agenda/components/AgendaFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export function getDropdownItems(filter: any, aggregations: any, toggleFilter: a

function AgendaFiltersComponent(props: any) {
return (
<div className='wire-column__main-header-agenda d-flex m-0 px-3 align-items-center flex-wrap flex-sm-nowrap'>
<div className='navbar navbar--flex navbar--quick-filter'>
{props.filtersConfig.map((filterName: any) => (
renderFilter[filterName](props)
))}
Expand Down
4 changes: 3 additions & 1 deletion assets/agenda/components/AgendaItemTypeFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ function AgendaItemTypeFilter ({toggleFilter, itemTypeFilter, eventsOnlyAccess,
};

return (
<AgendaDropdown key={filter.field}
<AgendaDropdown
key={filter.field}
filter={filter}
activeFilter={activeFilter}
toggleFilter={toggleFilter}
optionLabel={gettext('Item type')}
>
<button
key="events_only"
Expand Down
81 changes: 74 additions & 7 deletions assets/agenda/components/AgendaListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,83 @@ class AgendaListItem extends React.Component<any, any> {
};
}

getSegments(description: string) {
const dom = new DOMParser().parseFromString(description.replace(/\n/g, '<br />'), 'text/html');
const arrayOfParagraphs = dom.body.querySelectorAll('p');
const body = dom.body;

const getSegmentCount = (p: HTMLParagraphElement): number => {
// adding one because if there are 2 <br> tags it means there are 3 segments
return p.getElementsByTagName('br').length + 1;
};

const descriptionHTMLArr: HTMLParagraphElement[] = [];
let segmentsRemainingToBeAdded = 3;
let paragraphsInnerText = '';

[...arrayOfParagraphs].forEach(paragraph => {
if (segmentsRemainingToBeAdded > 0) {
paragraphsInnerText += paragraph.innerText;
paragraph.innerHTML = paragraph.innerHTML.split('<br>').filter((p: string) => p.trim() !== '').slice(0, segmentsRemainingToBeAdded).join('<br>');

segmentsRemainingToBeAdded = segmentsRemainingToBeAdded - getSegmentCount(paragraph);

descriptionHTMLArr.push(paragraph);
}
});

return {
/**
* keep in mind that first 3 segments might be 1-3 paragraphs
*/
firstThreeSegments: descriptionHTMLArr,
hasMoreContent: body.innerText.length > paragraphsInnerText.length,
};
}

renderListItem(isMobile: any, children: any) {
const {item, isExtended, group, planningId, listConfig} = this.props;
const classes = this.getClassNames(isExtended);
const planningItem = (get(item, 'planning_items') || []).find((p: any) => p.guid === planningId) || {};
const description =item.es_highlight ? getHighlightedDescription(item, planningItem) : getDescription(item,planningItem);
const planningItem = (get(item, 'planning_items') || []).find((p: any) => p.guid === planningId) || null;
const description: string = item.es_highlight
? getHighlightedDescription(item, planningItem)
: getDescription(item,planningItem);
// Show headline for adhoc planning items
const showHeadline = !item.event && get(item, 'headline.length', 0) > 0;

const {firstThreeSegments, hasMoreContent} = this.getSegments(description);

const renderDescription = (() => {
const isHTML = (value: string) => {
const doc = new DOMParser().parseFromString(value, 'text/html');
return Array.from(doc.body.childNodes).some(node => node.nodeType === 1);
};

if (item.es_highlight != null && (item.es_highlight.definition_short ?? '').length > 0) {
return <div style={{whiteSpace: 'pre-line'}} dangerouslySetInnerHTML={{__html: description}} />;
} else {
if (isHTML(description)) {
return (
firstThreeSegments.map((paragraph, i: number) => {
const lastChild: boolean = firstThreeSegments.length - 1 === i;
const showThreeDots = lastChild && hasMoreContent;

return <div className={showThreeDots ? 'wire-articles__item__text--last-child' : ''} dangerouslySetInnerHTML={{__html: paragraph.outerHTML}} key={i} />;
})
);
} else {
return (
description.split('\n').slice(0, 3).map((plainText: string, i: number, array: Array<string>) => {
const lastChild = array.length -1 === i;
const showThreeDots: boolean = lastChild && description.length > description.split('\n').slice(0, 3).join('\n').length;

return <p className={showThreeDots ? 'wire-articles__item__text--last-child' : ''} key={i}>{plainText}</p>;
})
);
}
}
})();

return (
<article key={item._id}
className={classes.card}
Expand Down Expand Up @@ -182,11 +251,9 @@ class AgendaListItem extends React.Component<any, any> {
/>

{(isMobile || isExtended) && description && (
<p className="wire-articles__item__text">
{item.es_highlight && item.es_highlight ? <span
dangerouslySetInnerHTML={({__html: description})}
/> : <PlainText text={description} />}
</p>
<div className="wire-articles__item__text">
{renderDescription}
</div>
)}
</div>
{children}
Expand Down
2 changes: 1 addition & 1 deletion assets/agenda/components/AgendaListViewControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ListViewOptions from 'components/ListViewOptions';

function AgendaListViewControls({activeView, setView, hideFeaturedToggle, toggleFeaturedFilter, featuredFilter, hasAgendaFeaturedItems}: any) {
return (
<div className="navbar navbar--flex navbar--small">
<div className="navbar navbar--flex navbar--small navbar--list-controls ">
<div className="navbar__inner navbar__inner--end">
{!hideFeaturedToggle && hasAgendaFeaturedItems && DISPLAY_AGENDA_FEATURED_STORIES_ONLY &&
<AgendaFeaturedStoriesToogle onChange={toggleFeaturedFilter} featuredFilter={featuredFilter}/>
Expand Down
2 changes: 1 addition & 1 deletion assets/agenda/components/AgendaLocation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function AgendaLocation({item, isMobilePhone, border}: any) {
return (
<Fragment>
<span>
<i className='icon-small--location icon--gray-dark' />
<i className='icon-small--location' />
</span>

{isMobilePhone ? (
Expand Down
Loading

0 comments on commit 4448716

Please sign in to comment.