Skip to content

Commit

Permalink
#370 add sort button and dropdown in matrix
Browse files Browse the repository at this point in the history
  • Loading branch information
xeronimus committed Sep 30, 2023
1 parent 44a8e7f commit 88f07fc
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 25 deletions.
4 changes: 2 additions & 2 deletions client/app/components/Backlog/BacklogActive.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import {useDrop} from 'react-dnd';
import {trashStories, setSortOrder} from '../../state/actions/commandActions';
import {getActiveStories, getSelectedStoryId} from '../../state/stories/storiesSelectors';
import {L10nContext} from '../../services/l10n';
import {manualSorting} from './backlogSortings';
import {manualSorting} from '../common/storySortings';
import StoryEditForm from './StoryEditForm';
import Story from './Story';
import BacklogToolbar from './BacklogToolbar';
import {DRAG_ITEM_TYPES} from '../Room/Board';
import BacklogFileDropWrapper from './BacklogFileDropWrapper';
import useStorySortingAndFiltering from './useStorySortingAndFiltering';

import {StyledStories, StyledBacklogInfoText, StyledBacklogActive} from './_styled';
import useStorySortingAndFiltering from '../common/useStorySortingAndFiltering';

/**
*
Expand Down
2 changes: 1 addition & 1 deletion client/app/components/Backlog/BacklogToolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';

import {L10nContext} from '../../services/l10n';
import useOutsideClick from '../common/useOutsideClick';
import sortings from './backlogSortings';
import sortings from '../common/storySortings';
import {OpenFileDialogContext} from './BacklogFileDropWrapper';

import {StyledDropdown} from '../common/_styled';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useState, useEffect} from 'react';
import {defaultSorting} from '../Backlog/backlogSortings';
import {defaultSorting} from '../common/storySortings';

/**
*
Expand Down
86 changes: 65 additions & 21 deletions client/app/components/EstimationMatrix/EstimationMatrix.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useContext, useState, useEffect} from 'react';
import React, {useContext, useState, useEffect, useRef} from 'react';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';

Expand All @@ -13,13 +13,20 @@ import {L10nContext} from '../../services/l10n';
import {toggleMatrixIncludeTrashed} from '../../state/actions/uiStateActions';
import {setStoryValue} from '../../state/actions/commandActions';
import EstimationMatrixColumn from './EstimationMatrixColumn';

import {StyledEMColumnsContainer, StyledEstimationMatrix, StyledNoStoriesHint} from './_styled';
import {StyledStoryTitle} from '../_styled';
import {getStoriesWithPendingSetValueCommand} from '../../state/commandTracking/commandTrackingSelectors';
import EstimationMatrixColumnUnestimated from './EstimationMatrixColumnUnestimated';
import useStorySortingAndFiltering from '../common/useStorySortingAndFiltering';
import {defaultSorting} from '../Backlog/backlogSortings';
import {defaultSorting, matrixSortings} from '../common/storySortings';
import useOutsideClick from '../common/useOutsideClick';

import {
StyledEMColumnsContainer,
StyledEstimationMatrix,
StyledMatrixHeader,
StyledMatrixTools,
StyledNoStoriesHint
} from './_styled';
import {StyledDropdown} from '../common/_styled';
import {StyledSortDropdownItem} from '../Backlog/_styled';

/**
* Displays a table with all estimated stories (all stories with consensus), ordered by estimation value
Expand All @@ -36,24 +43,56 @@ const EstimationMatrix = ({
const columnWidth = getColWidth(cardConfig.length + 1);
const {t} = useContext(L10nContext);
const [groupedStories, setGroupedStories] = useState({}); // grouped by consensus value
const [sortedUnestimatedStories, setSortedUnestimatedStories] = useState(unestimatedStories);
const [extendedSort, setExtendedSort] = useState(false);
const [sorting, setSorting] = useState(defaultSorting);

const {sortedStories: sortedUnestimatedStories} = useStorySortingAndFiltering(unestimatedStories);
useEffect(() => {
setGroupedStories(deriveGroupedStories(estimatedStories, pendingSetValueStories, sorting));
}, [estimatedStories, pendingSetValueStories, sorting]);

useEffect(() => {
setGroupedStories(
deriveGroupedStories(estimatedStories, pendingSetValueStories, defaultSorting)
);
}, [estimatedStories, pendingSetValueStories]);
setSortedUnestimatedStories(unestimatedStories.sort(sorting.comp));
}, [unestimatedStories, sorting, setSortedUnestimatedStories]);

const sortDropdownRef = useRef(null);
useOutsideClick(sortDropdownRef, () => setExtendedSort(false));

return (
<StyledEstimationMatrix data-testid="matrix">
<StyledStoryTitle>
{t('matrix')}
<span onClick={toggleMatrixIncludeTrashed} className="clickable">
<i className={includeTrashedStories ? 'icon-check' : 'icon-check-empty'}></i>{' '}
{t('matrixIncludeTrashed')}
</span>
</StyledStoryTitle>
<StyledMatrixHeader>
<h4>{t('matrix')}</h4>

<StyledMatrixTools>
<span onClick={toggleMatrixIncludeTrashed} className="clickable">
<i className={includeTrashedStories ? 'icon-check' : 'icon-check-empty'}></i>{' '}
{t('matrixIncludeTrashed')}
</span>

<div ref={sortDropdownRef}>
<i
onClick={() => setExtendedSort(!extendedSort)}
className="clickable icon-exchange"
title={t('sort')}
data-testid="sortButton"
/>
{extendedSort && (
<StyledDropdown data-testid="sortOptions">
{matrixSortings.map((sortingItem) => (
<StyledSortDropdownItem
$selected={sortingItem.id === sorting.id}
className="clickable"
key={`sorting-item-${sortingItem.id}`}
onClick={() => onSortingOptionClicked(sortingItem)}
>
{t(sortingItem.labelKey)}
</StyledSortDropdownItem>
))}
</StyledDropdown>
)}
</div>
</StyledMatrixTools>
</StyledMatrixHeader>

<StyledEMColumnsContainer>
<EstimationMatrixColumnUnestimated
Expand All @@ -80,6 +119,11 @@ const EstimationMatrix = ({
)}
</StyledEstimationMatrix>
);

function onSortingOptionClicked(sortingItem) {
setExtendedSort(false);
setSorting(sortingItem);
}
};

EstimationMatrix.propTypes = {
Expand Down Expand Up @@ -134,9 +178,9 @@ function deriveGroupedStories(estimatedStories, pendingSetValueStories, sorting)

// now sort each story-array
const groupedStoriesSorted = {};
Object.entries(groupedStoriesUnsorted).forEach(([consensus, stories]) => {
groupedStoriesSorted[consensus] = stories.sort(sorting.comp);
});
Object.entries(groupedStoriesUnsorted).forEach(
([consensus, stories]) => (groupedStoriesSorted[consensus] = stories.sort(sorting.comp))
);

return groupedStoriesSorted;
}
27 changes: 27 additions & 0 deletions client/app/components/EstimationMatrix/_styled.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,30 @@ export const StyledNoStoriesHint = styled.div`
justify-content: center;
align-items: center;
`;

export const StyledMatrixHeader = styled.div`
position: relative;
display: flex;
justify-content: space-between;
> h4 {
margin-top: 8px;
margin-bottom: 0;
line-height: 24px;
overflow-x: hidden;
}
`;

export const StyledMatrixTools = styled.div`
display: flex;
> div {
margin-left: 8px;
}
i.icon-exchange {
margin-left: 4px;
margin-right: 8px;
transform: rotate(90deg);
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,5 @@ export default sortings;
export const defaultSorting = sortings[0];

export const manualSorting = sortings[6];

export const matrixSortings = sortings.slice(0, 4); // in the estimation matrix, we want to provide only a reduced set of sorting options

0 comments on commit 88f07fc

Please sign in to comment.