Skip to content

Commit

Permalink
Merge branch 'new-components' into label-component
Browse files Browse the repository at this point in the history
  • Loading branch information
dzonidoo committed Mar 27, 2024
2 parents 26a5ad6 + e2b60db commit 7c81304
Show file tree
Hide file tree
Showing 229 changed files with 11,920 additions and 13,071 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module.exports = {
'@typescript-eslint',
],
'rules': {
'react/prop-types': 0,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/ban-ts-comment': 0,
'indent': [
Expand Down
16 changes: 16 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "pip" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"

- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
19 changes: 8 additions & 11 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ jobs:
flake8:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- run: pip install flake8
Expand All @@ -17,22 +17,19 @@ jobs:
mypy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- run: |
sudo apt-get update
sudo apt-get install pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl
- run: pip install -Ur mypy-requirements.txt
- run: pip install -r mypy-requirements.txt
- run: mypy .

black:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- run: pip install black~=23.0
- run: pip install -r black-requirements.txt
- run: black --check .
25 changes: 10 additions & 15 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ jobs:
python-version: ['3.8', '3.10']

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: setup python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -37,30 +37,25 @@ jobs:

- name: behave (API)
run: behave --format progress2 --logging-level=ERROR features/news_api

- name: behave (Web)
run: behave --format progress2 --logging-level=ERROR features/web_api

- name: black
run: black --check .

client:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: setup node
uses: actions/setup-node@v1
- uses: actions/setup-node@v4
with:
node-version: 14.x
cache: npm

- name: cache npm
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm
${{ runner.os }}-
- name: npm ci
- name: npm install
run: npm ci || npm install

- name: lint
Expand Down
15 changes: 15 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Security Policy

## Supported Versions

We support last 2 minor versions released.

| Version | Supported |
| ------- | ------------------ |
| 2.6.x | :white_check_mark: |
| 2.5.x | :white_check_mark: |
| < 2.5 | :x: |

## Reporting a Vulnerability

Please report security issues via [email protected].
5 changes: 5 additions & 0 deletions assets/actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import {get, differenceBy} from 'lodash';
import server from 'server';

export const INIT_DATA = 'INIT_DATA';
export function initData(payload: any) {
return {type: INIT_DATA, payload};
}

export const RENDER_MODAL = 'RENDER_MODAL';
export function renderModal(modal: any, data: any) {
return {type: RENDER_MODAL, modal, data};
Expand Down
30 changes: 24 additions & 6 deletions assets/agenda/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {searchParamsSelector, searchFilterSelector} from 'search/selectors';

import {clearAgendaDropdownFilters} from '../local-store';
import {getLocations, getMapSource} from '../maps/utils';
import {ILocation} from 'interfaces/agenda';

const WATCH_URL = '/agenda_watch';
const WATCH_COVERAGE_URL = '/agenda_coverage_watch';
Expand Down Expand Up @@ -254,13 +255,18 @@ function search(state: IAgendaState, fetchFrom: number): Promise<IRestApiRespons
return server.get(`/agenda/search?${queryString}&tick=${Date.now().toString()}`);
}

export const LOADING_AGGREGATIONS = 'LOADING_AGGREGATIONS';
function loadingAggregations() {
return {type: LOADING_AGGREGATIONS};
}
/**
* Fetch items for current query
*/
export function fetchItems(): AgendaThunkAction {
return (dispatch, getState) => {
const start = Date.now();
dispatch(queryItems());
dispatch(loadingAggregations());
return search(getState(), 0)
.then((data) => {
dispatch(recieveItems(data));
Expand Down Expand Up @@ -566,9 +572,9 @@ export const SET_NEW_ITEM = 'SET_NEW_ITEM';
export function setAndUpdateNewItems(data: any) {
return function(dispatch: any, getState: any) {
const item = data.item || {};
const state = getState();

if (item.type !== 'agenda') {
const state = getState();

// Check if the item is used in the preview or opened agenda item
// If yes, make it available to the preview
Expand All @@ -590,8 +596,20 @@ export function setAndUpdateNewItems(data: any) {
return Promise.resolve();
}

dispatch(updateItem(item));
const {itemsById} = state;
const prevItem = itemsById[item['_id']];

// If coverage is updated in the item fetch all items and reintilized group listing.
if (prevItem && prevItem.coverages?.length !== item?.coverages?.length) {
dispatch(fetchItems());
} else {
dispatch(updateItem(item));
if (item.item_type === 'event' && item.planning_items && item.planning_items.length > 0) {
item.planning_items.forEach((plan: IAgendaItem) => {
dispatch(fetchItem(plan._id));}
);
}
}
// Do not use 'killed' items for new-item notifications
if (item.state === 'killed') {
return Promise.resolve();
Expand All @@ -607,24 +625,24 @@ export function updateItem(item: any) {
return {type: UPDATE_ITEM, item: item};
}

export function toggleDropdownFilter(key: any, val: any) {
export function toggleDropdownFilter(key: any, val: any, single = true) {
return (dispatch: any) => {
dispatch(setActive(null));
dispatch(preview(null));

if (key === 'itemType') {
dispatch(setItemTypeFilter(val));
} else if (key === 'location') {
dispatch(setLocationFilter(val));
dispatch(toggleLocationFilter(val));
} else {
dispatch(toggleFilter(key, val, true));
dispatch(toggleFilter(key, val, single));
}

dispatch(fetchItems());
};
}

function setLocationFilter(location: any) {
function toggleLocationFilter(location: ILocation) {
return (dispatch: any, getState: any) => {
const state = getState();
const currentFilters = cloneDeep(searchFilterSelector(state));
Expand Down
4 changes: 2 additions & 2 deletions assets/agenda/components/AgendaApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import {
showSaveTopicSelector,
} from 'search/selectors';

import BaseApp from 'layout/components/BaseApp';
import SearchBase from 'layout/components/SearchBase';
import AgendaPreview from './AgendaPreview';
import AgendaList from './AgendaList';
import SearchBar from 'search/components/SearchBar';
Expand All @@ -62,7 +62,7 @@ const modals = {
downloadItems: DownloadItemsModal,
};

class AgendaApp extends BaseApp {
class AgendaApp extends SearchBase<any> {
static propTypes: any;

modals: any;
Expand Down
107 changes: 54 additions & 53 deletions assets/agenda/components/AgendaCoverageExistsFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,62 @@
import React from 'react';
import PropTypes from 'prop-types';
import {get} from 'lodash';
import {memoize} from 'lodash';

import {gettext} from 'utils';
import {gettext, getConfig} from 'utils';
import {AgendaDropdown} from './AgendaDropdown';

type ICoverageStatusOptionValue = 'planned' | 'not planned' | 'may be' | 'not intended' | 'completed';

interface IProps {
toggleFilter(field: string, value?: ICoverageStatusOptionValue): void;
activeFilter: {coverage_status?: Array<ICoverageStatusOptionValue>};
}

interface ICoverageStatusOptionConfig {
enabled: boolean;
index: number;
option_label: string;
button_label: string;
}

type ICoverageStatusFilterConfig = {[value in ICoverageStatusOptionValue]: ICoverageStatusOptionConfig};

export const agendaCoverageStatusFilter = {
label: gettext('Any coverage status'),
field: 'coverage_status',
nestedField: 'coverage_status',
};

const FILTER_VALUES = {
PLANNED: 'planned',
NOT_PLANNED: 'not planned',
MAY_BE: 'may be',
COMPLETED: 'completed'
};

export function getActiveFilterLabel(filter: any, activeFilter: any) {
const filterValue = get(activeFilter, `${filter.field}[0]`);

switch (filterValue) {
case FILTER_VALUES.PLANNED:
return gettext('Planned');
case FILTER_VALUES.NOT_PLANNED:
return gettext('Not Planned');
case FILTER_VALUES.MAY_BE:
return gettext('Not Decided');
case FILTER_VALUES.COMPLETED:
return gettext('Completed');
export function getActiveFilterLabel(
filter: {label: string; field: string},
activeFilter?: {
coverage_status?: Array<ICoverageStatusOptionValue>;
[field: string]: any;
}
) {
const config: ICoverageStatusFilterConfig = getConfig('coverage_status_filter');

return filter.label;
return activeFilter?.coverage_status?.[0] != null ?
config[activeFilter.coverage_status[0]].button_label :
filter.label;
}

function AgendaCoverageExistsFilter ({toggleFilter, activeFilter}: any) {
const getCoverageStatusOptions = memoize<() => Array<[ICoverageStatusOptionValue, ICoverageStatusOptionConfig]>>(() => {
const config: ICoverageStatusFilterConfig = getConfig('coverage_status_filter');
const enabledOptionValues: Array<ICoverageStatusOptionValue> = [
'planned',
'may be',
'not intended',
'not planned',
'completed',
];

return enabledOptionValues
.filter((optionValue) => config[optionValue]?.enabled == true)
.sort((optionA, optionB) => config[optionA].index - config[optionB].index)
.map((optionValue) => ([optionValue, config[optionValue]]));
});

function AgendaCoverageExistsFilter({toggleFilter, activeFilter}: IProps) {
return (
<AgendaDropdown
filter={agendaCoverageStatusFilter}
Expand All @@ -47,37 +68,17 @@ function AgendaCoverageExistsFilter ({toggleFilter, activeFilter}: any) {
resetOptionLabel={gettext('Clear selection')}
dropdownMenuHeader={gettext('Coverage status')}
>
<button
key='coverage-planned'
className='dropdown-item'
onClick={() => toggleFilter(agendaCoverageStatusFilter.field, FILTER_VALUES.PLANNED)}
>{gettext('Coverage is planned')}
</button>
<button
key='coverage-not-planned'
className='dropdown-item'
onClick={() => toggleFilter(agendaCoverageStatusFilter.field, FILTER_VALUES.NOT_PLANNED)}
>{gettext('Coverage not planned')}
</button>
<button
key='coverage-not-decided'
className='dropdown-item'
onClick={() => toggleFilter(agendaCoverageStatusFilter.field, FILTER_VALUES.MAY_BE)}
>{gettext('Coverage not decided')}
</button>
<button
key='coverage-completed'
className='dropdown-item'
onClick={() => toggleFilter(agendaCoverageStatusFilter.field, FILTER_VALUES.COMPLETED)}
>{gettext('Coverage completed')}
</button>
{getCoverageStatusOptions().map(([value, config]) => (
<button
key={`coverage-${value}`}
className="dropdown-item"
onClick={() => toggleFilter(agendaCoverageStatusFilter.field, value)}
>
{config.option_label}
</button>
))}
</AgendaDropdown>
);
}

AgendaCoverageExistsFilter.propTypes = {
toggleFilter: PropTypes.func,
activeFilter: PropTypes.object,
};

export default AgendaCoverageExistsFilter;
2 changes: 1 addition & 1 deletion assets/agenda/components/AgendaDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface IProps {
label?: string;
activeFilter?: any;
toggleFilter: (filedName: string, value: any) => void;
getFilterLabel?: (filter: string, activeFilter: string, isActive: boolean) => string;
getFilterLabel?: (filter: {field: string; label: string}, activeFilter: {[field: string]: any}, isActive: boolean) => string;
children?: any;
borderless?: boolean;
dropdownMenuHeader?: string;
Expand Down
Loading

0 comments on commit 7c81304

Please sign in to comment.