Merge pull request #211 from forensic-architecture/feature/allow-for-multiple-categories

Feature/allow for multiple categories
This commit is contained in:
Ebrahem Farooqui
2021-05-24 22:50:20 -07:00
committed by GitHub
3 changed files with 108 additions and 34 deletions

View File

@@ -222,9 +222,7 @@ export function getEventCategories(event, activeCategories) {
* Takes a filter's path and concatenates it like so: Parent 1/Parent 2/Child
*/
export function createFilterPathString(filter) {
return filter.mode === ASSOCIATION_MODES.FILTER
? filter.filter_paths.join("/")
: "";
return filter.filter_paths.join("/");
}
/**
@@ -511,6 +509,11 @@ export function setD3Locale(d3) {
}
}
/**
* Gets the set of associated styles for a given shape type from the entire set of shapes
* @param list shapes - The aggregated set of shapes
* @param list activeShapes - The set of active shapes in the app
*/
export function mapStyleByShape(shapes, activeShapes) {
const styledShapes = shapes.map((s) => {
const { colour, shape, id } = s;
@@ -530,3 +533,43 @@ export function mapStyleByShape(shapes, activeShapes) {
});
return styledShapes;
}
export function mapCategoriesToPaths(categories, panelCategories) {
const mappedCats = categories.reduce((acc, cat) => {
const type = cat.filter_paths[0];
if (!(type in acc)) {
acc[type] = [];
}
acc[type].push(cat);
return acc;
}, {});
const categoryMap =
panelCategories.length > 1 ? mappedCats : { default: categories };
return categoryMap;
}
export function getCategoryIdxs(panelCategories, startingIdx) {
let idxCounter = startingIdx;
// If there are specified categories from the config, filter out the default value; else, leave the default value
const catTypes =
panelCategories.length > 1
? panelCategories.filter((val) => val !== "default")
: panelCategories;
return catTypes.reduce((set, val) => {
set[val] = idxCounter;
idxCounter += 1;
return set;
}, {});
}
export function getFilterIdx(
narrativesExist,
categoriesExist,
numCategoryPanels
) {
if (narrativesExist && !categoriesExist) return 1;
else if (!narrativesExist && categoriesExist) return numCategoryPanels;
else if (narrativesExist && categoriesExist) return numCategoryPanels + 1;
else return 0;
}

View File

@@ -17,6 +17,9 @@ import {
getFilterAncestors,
addToColoringSet,
removeFromColoringSet,
mapCategoriesToPaths,
getCategoryIdxs,
getFilterIdx,
} from "../common/utilities.js";
class Toolbar extends React.Component {
@@ -110,21 +113,31 @@ class Toolbar extends React.Component {
}
renderToolbarCategoriesPanel() {
const { panels } = this.props.toolbarCopy;
if (this.props.features.USE_CATEGORIES) {
return (
<TabPanel>
<CategoriesListPanel
categories={this.props.categories}
activeCategories={this.props.activeCategories}
onCategoryFilter={this.props.methods.onCategoryFilter}
language={this.props.language}
title={panels.categories.label}
description={panels.categories.description}
/>
</TabPanel>
);
}
const { categories: panelCategories } = this.props.toolbarCopy.panels;
const catMap = mapCategoriesToPaths(
this.props.categories,
Object.keys(panelCategories)
);
return (
<div>
{Object.keys(catMap).map((type) => {
const children = catMap[type];
return (
<TabPanel>
<CategoriesListPanel
categories={children}
activeCategories={this.props.activeCategories}
onCategoryFilter={this.props.methods.onCategoryFilter}
language={this.props.language}
title={panelCategories[type].label}
description={panelCategories[type].description}
/>
</TabPanel>
);
})}
</div>
);
}
renderToolbarFilterPanel() {
@@ -181,6 +194,21 @@ class Toolbar extends React.Component {
);
}
renderToolbarCategoryTabs(idxs) {
const { categories: panelCategories } = this.props.toolbarCopy.panels;
return (
<div>
{Object.keys(idxs).map((key) => {
return this.renderToolbarTab(
idxs[key],
panelCategories[key].label,
panelCategories[key].icon
);
})}
</div>
);
}
renderToolbarPanels() {
const { features, narratives } = this.props;
const classes =
@@ -230,14 +258,18 @@ class Toolbar extends React.Component {
const { panels } = toolbarCopy;
const narrativesIdx = 0;
const categoriesIdx = narrativesExist ? 1 : 0;
const filtersIdx =
narrativesExist && features.USE_CATEGORIES
? 2
: narrativesExist || features.USE_CATEGORIES
? 1
: 0;
const categoryIdxs = getCategoryIdxs(
Object.keys(panels.categories),
narrativesExist ? 1 : 0
);
const numCategoryPanels = Object.keys(categoryIdxs).length;
const filtersIdx = getFilterIdx(
narrativesExist,
features.USE_CATEGORIES,
numCategoryPanels || 0
);
const shapesIdx = filtersIdx + 1;
return (
<div className="toolbar">
<div className="toolbar-header" onClick={this.props.methods.onTitle}>
@@ -252,11 +284,7 @@ class Toolbar extends React.Component {
)
: null}
{features.USE_CATEGORIES
? this.renderToolbarTab(
categoriesIdx,
panels.categories.label,
panels.categories.icon
)
? this.renderToolbarCategoryTabs(categoryIdxs)
: null}
{features.USE_ASSOCIATIONS
? this.renderToolbarTab(

View File

@@ -112,10 +112,13 @@ const initial = {
toolbar: {
panels: {
categories: {
icon: DEFAULT_TAB_ICONS.CATEGORY,
label: copy[language].toolbar.categories_label,
title: copy[language].toolbar.explore_by_category__title,
description: copy[language].toolbar.explore_by_category__description,
default: {
icon: DEFAULT_TAB_ICONS.CATEGORY,
label: copy[language].toolbar.categories_label,
title: copy[language].toolbar.explore_by_category__title,
description:
copy[language].toolbar.explore_by_category__description,
},
},
filters: {
icon: DEFAULT_TAB_ICONS.FILTER,