diff --git a/src/Project.js b/src/Project.js index 7a3e053..fae9435 100644 --- a/src/Project.js +++ b/src/Project.js @@ -26,6 +26,7 @@ const Project = ({ }) => { const [splitFinalColumns] = useLocalStorage('splitColumns'); const [slim, setSlim] = useLocalStorage('slim'); + const [rejected] = useLocalStorage('rejected'); const keyMap = useMemo( () => ({ @@ -115,6 +116,18 @@ const Project = ({ slim={slim} /> )} + {rejected && ( + + )} diff --git a/src/ProjectContainer.js b/src/ProjectContainer.js index f049675..655895a 100644 --- a/src/ProjectContainer.js +++ b/src/ProjectContainer.js @@ -38,10 +38,37 @@ function reducer(state, action) { case 'FETCH_BLOCKERS_SUCCESS': { const storiesWithBlockers = { ...state.stories }; + const matchStoryId = str => + (str && str.match(/([0-9]){9}$/)[0]) || 'Unknown'; + + const getStoryBlockers = blockers => { + return blockers + .map(b => { + const storyId = matchStoryId(b.description); + const scopedStory = storiesWithBlockers[storyId]; + return scopedStory + ? { + id: scopedStory.id, + url: scopedStory.url, + name: scopedStory.name, + resolved: b.resolved + } + : { + id: storyId, + url: `https://www.pivotaltracker.com/story/show/${storyId}`, + name: '[Out of current iteration blocker]', + resolved: b.resolved + }; + }) + .filter(b => !b.resolved); + }; + payload.forEach(story => { if (story.blockers.length > 0) { if (storiesWithBlockers[story.id]) { - storiesWithBlockers[story.id].blockers = story.blockers; + storiesWithBlockers[story.id].blockers = getStoryBlockers( + story.blockers + ); } else { console.warn( 'Recieved blockers for unknow story, with id', diff --git a/src/Settings.js b/src/Settings.js index 1ca2b4f..8205642 100644 --- a/src/Settings.js +++ b/src/Settings.js @@ -7,6 +7,9 @@ const Settings = () => { ); const [slim, setSlim] = useLocalStorage('slim'); + const [showRejectedColumn, setShowRejectedColumn] = useLocalStorage( + 'rejected' + ); return (
@@ -60,6 +63,28 @@ const Settings = () => {

+ +
+
+ +
+ +
+

Rejected state column

+

+ Enable this setting to have Rejected state column. +
+ Current state: {showRejectedColumn ? 'enabled' : 'disabled'} +

+
+
); }; diff --git a/src/Story.js b/src/Story.js index c270adb..01c9a0e 100644 --- a/src/Story.js +++ b/src/Story.js @@ -1,7 +1,6 @@ import React from 'react'; import { Owners } from './Owners'; import { - BlockedTag, BugTag, ChoreTag, EstimateTag, @@ -10,6 +9,7 @@ import { SlimTag } from './Tags'; import { hasUnresolvedBlockers } from './FilterContainer'; +import { StoryBlockers } from './StoryBlockers'; const renderTypeTag = type => { switch (type) { @@ -84,10 +84,9 @@ function Story({
- - )} + ); diff --git a/src/Story.test.js b/src/Story.test.js index 09064fb..a80c8af 100644 --- a/src/Story.test.js +++ b/src/Story.test.js @@ -142,31 +142,21 @@ describe('Story', () => { expect(within(getByTestId('owners')).getByText('WT')).toBeInTheDocument(); }); - describe('blocked tag', () => { - it('renders visible blocked tag if blocked', () => { + describe('story blockers', () => { + it('renders blockers if blocked', () => { const { queryByTestId } = renderSubject({ blockers: [{ resolved: false }] }); - expect(queryByTestId('blocked-tag')).toBeVisible(); + expect(queryByTestId('story-blockers')).toBeInTheDocument(); }); - it('renders invisible blocked tag if not blocked', () => { - const { queryByTestId } = renderSubject({ - blockers: [{ resolved: true }] - }); - - expect(queryByTestId('blocked-tag')).toBeInTheDocument(); - expect(queryByTestId('blocked-tag')).not.toBeVisible(); - }); - - it('renders invisible blocked tag if no blockers', () => { + it('does not render blockers if no blockers', () => { const { queryByTestId } = renderSubject({ blockers: [] }); - expect(queryByTestId('blocked-tag')).toBeInTheDocument(); - expect(queryByTestId('blocked-tag')).not.toBeVisible(); + expect(queryByTestId('story-blockers')).not.toBeInTheDocument(); }); }); diff --git a/src/StoryBlockers.js b/src/StoryBlockers.js new file mode 100644 index 0000000..67b1973 --- /dev/null +++ b/src/StoryBlockers.js @@ -0,0 +1,33 @@ +import React from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faBan } from '@fortawesome/free-solid-svg-icons'; + +function StoryBlockers({ blockers }) { + if (!blockers.length) return null; + + return ( +
+
+ + Blockers: + + + +
+ ); +} + +export { StoryBlockers }; diff --git a/src/__snapshots__/ProjectContainer.test.js.snap b/src/__snapshots__/ProjectContainer.test.js.snap index 7f6b87e..c4deb0e 100644 --- a/src/__snapshots__/ProjectContainer.test.js.snap +++ b/src/__snapshots__/ProjectContainer.test.js.snap @@ -146,13 +146,48 @@ exports[`ProjectContainer renders fetched and normalized data 1`] = ` + +
+
- Blocked + + Blockers: +
@@ -245,13 +280,6 @@ exports[`ProjectContainer renders fetched and normalized data 1`] = ` - - Blocked -