Skip to content

Commit cab65a9

Browse files
authored
Merge pull request #540 from AppQuality/UN-801-not-a-bug-toggle
UN-801-not-a-bug-toggle
2 parents b4766cc + 41c68ef commit cab65a9

File tree

11 files changed

+180
-19
lines changed

11 files changed

+180
-19
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { TFunction } from 'i18next';
2+
import { DEFAULT_NOT_A_BUG_CUSTOM_STATUS } from 'src/constants';
3+
4+
export const getExcludeNotABugInfo = (t: TFunction) => ({
5+
customStatusId: DEFAULT_NOT_A_BUG_CUSTOM_STATUS.id,
6+
customStatusName: DEFAULT_NOT_A_BUG_CUSTOM_STATUS.name,
7+
actionIdentifier: 'excludeNotABug',
8+
recapTitle: t('__BUGS_EXCLUDED_NOT_A_BUG'),
9+
drawerTitle: t('__BUGS_EXCLUDE_NOT_A_BUG'),
10+
});

src/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,8 @@ export const RELATIVE_DATE_FORMAT_OPTS: {
5252
other: "EEEE',' d MMMM Y",
5353
},
5454
};
55+
56+
export const DEFAULT_NOT_A_BUG_CUSTOM_STATUS = {
57+
id: 7,
58+
name: 'not a bug',
59+
};

src/features/bugsPage/bugsPageSlice.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ interface initialSimpleState {
4747
orderBy: OrderBy;
4848
order: Order;
4949
isFilterDrawerOpen: boolean;
50+
isNaBugExcluded: boolean;
5051
}
5152

5253
const initialStateSimple: initialSimpleState = {
@@ -55,6 +56,7 @@ const initialStateSimple: initialSimpleState = {
5556
orderBy: 'severity_id',
5657
order: 'DESC',
5758
isFilterDrawerOpen: false,
59+
isNaBugExcluded: false,
5860
};
5961

6062
const bugPageSlice = createSlice({
@@ -193,6 +195,9 @@ const bugPageSlice = createSlice({
193195
setFilterDrawerOpen: (state, action: PayloadAction<boolean>) => {
194196
state.isFilterDrawerOpen = action.payload;
195197
},
198+
setIsNaBugExcluded: (state, action: PayloadAction<boolean>) => {
199+
state.isNaBugExcluded = action.payload;
200+
},
196201
},
197202
});
198203

@@ -255,6 +260,9 @@ export const getSelectedOrderBy = (): OrderBy =>
255260
export const getSelectedOrder = (): Order =>
256261
useAppSelector((state) => state.bugsPage).order;
257262

263+
export const getIsNaBugExcluded = (): boolean =>
264+
useAppSelector((state) => state.bugsPage).isNaBugExcluded;
265+
258266
export const {
259267
selectCampaign,
260268
updateFilters,
@@ -264,4 +272,5 @@ export const {
264272
setOrderBy,
265273
setOrder,
266274
setFilterDrawerOpen,
275+
setIsNaBugExcluded,
267276
} = bugPageSlice.actions;

src/locales/en/translation.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
"__BUG_SEVERITY_MEDIUM": "Medium",
3939
"__BUG_STATUS": "Status",
4040
"__BUGS_CUSTOM_STATUS_FILTER_ITEM_NO_ITEMS": "All statuses",
41+
"__BUGS_EXCLUDED_NOT_A_BUG": "“Not a bug” excluded",
42+
"__BUGS_EXCLUDE_NOT_A_BUG": "Exclude “Not a bug”",
4143
"__BUGS_DEVICES_FILTER_ITEM_NO_ITEMS": "Devices",
4244
"__BUGS_FILTER_VIEW_ALL_LABEL": "All filters",
4345
"__BUGS_FILTER_VIEW_RESET_LABEL": "Reset filters",

src/locales/it/translation.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
"__BUG_SEVERITY_MEDIUM": "Medi",
3939
"__BUG_STATUS": "Stato",
4040
"__BUGS_CUSTOM_STATUS_FILTER_ITEM_NO_ITEMS": "Tutti gli stati",
41+
"__BUGS_EXCLUDED_NOT_A_BUG": "“Non un bug” esclusi",
42+
"__BUGS_EXCLUDE_NOT_A_BUG": "Escludi “Non un bug”",
4143
"__BUGS_DEVICES_FILTER_ITEM_NO_ITEMS": "Dispositivi",
4244
"__BUGS_FILTER_VIEW_ALL_LABEL": "Tutti i filtri",
4345
"__BUGS_FILTER_VIEW_RESET_LABEL": "Cancella filtri",

src/pages/Bugs/Content/BugsTable/hooks/useTableData.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
import { getIsNaBugExcluded } from 'src/features/bugsPage/bugsPageSlice';
2+
import { getExcludeNotABugInfo } from 'src/common/components/utils/getExcludeNotABugInfo';
3+
import { useTranslation } from 'react-i18next';
14
import { useCampaignBugs } from './useCampaignBugs';
25
import { useCampaignBugStates } from './useCampaignBugStates';
36
import { useCampaignUseCases } from './useCampaignUseCases';
47
import { sortByUseCase } from '../utils/sortByUseCase';
58
import { sortByStates } from '../utils/sortByStates';
69

710
export const useTableData = (campaignId: number) => {
11+
const { t } = useTranslation();
12+
813
// get bugs accepted states and usecases
914
const { bugs, bugsError, bugsLoading, bugsFetching } =
1015
useCampaignBugs(campaignId);
@@ -13,6 +18,10 @@ export const useTableData = (campaignId: number) => {
1318
const { useCases, useCasesError, useCasesLoading } =
1419
useCampaignUseCases(campaignId);
1520

21+
const currentIsNaBugExcluded = getIsNaBugExcluded();
22+
23+
const customStatusNotABugInfo = getExcludeNotABugInfo(t);
24+
1625
// if there is no data, return empty array
1726
if (
1827
bugsLoading ||
@@ -35,13 +44,20 @@ export const useTableData = (campaignId: number) => {
3544
};
3645
}
3746

38-
const bugsByStates = sortByStates(bugs.items, bugStates);
39-
const bugsByUseCases = sortByUseCase(bugs.items, useCases);
47+
let bugItems = [...bugs.items];
48+
if (currentIsNaBugExcluded) {
49+
bugItems = bugs.items.filter(
50+
(item) => item.custom_status.id !== customStatusNotABugInfo.customStatusId
51+
);
52+
}
53+
54+
const bugsByStates = sortByStates(bugItems, bugStates);
55+
const bugsByUseCases = sortByUseCase(bugItems, useCases);
4056

4157
/* got the data */
4258
return {
4359
data: {
44-
allBugs: bugs.items,
60+
allBugs: bugItems,
4561
bugsByUseCases,
4662
bugsByStates,
4763
},

src/pages/Bugs/Drawer/CustomStatusField.tsx

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ import { useState } from 'react';
99
import { Trans, useTranslation } from 'react-i18next';
1010
import { useAppDispatch } from 'src/app/hooks';
1111
import { theme as globalTheme } from 'src/app/theme';
12-
import { Field } from '@zendeskgarden/react-forms';
13-
import { updateFilters } from 'src/features/bugsPage/bugsPageSlice';
12+
import { Field, Toggle } from '@zendeskgarden/react-forms';
13+
import {
14+
getIsNaBugExcluded,
15+
setIsNaBugExcluded,
16+
updateFilters,
17+
} from 'src/features/bugsPage/bugsPageSlice';
1418
import { Divider } from 'src/common/components/divider';
1519
import { CustomStatusFilterType } from 'src/features/bugsPage/customStatusFilter';
1620
import { getCustomStatusInfo } from 'src/common/components/utils/getCustomStatusInfo';
21+
import { getExcludeNotABugInfo } from 'src/common/components/utils/getExcludeNotABugInfo';
22+
import { BugCustomStatus } from 'src/features/api';
1723
import { ShowMore } from './ShowMore';
1824
import { useFilterData } from './useFilterData';
1925
import { LabelSpaceBetween, disabledStyle } from './LabelWithCounter';
@@ -31,9 +37,37 @@ export const CustomStatusField = ({
3137
const { t } = useTranslation();
3238
const { available: unsorted, selected } = customStatuses;
3339
const available = [...unsorted].sort((a, b) => a.id - b.id);
40+
const currentIsNaBugExcluded = getIsNaBugExcluded();
3441

3542
if (!counters) return null;
3643

44+
const customStatusNotABugInfo = getExcludeNotABugInfo(t);
45+
46+
const selectedWithNaB = currentIsNaBugExcluded
47+
? [
48+
...selected,
49+
{
50+
id: customStatusNotABugInfo.actionIdentifier,
51+
name: customStatusNotABugInfo.drawerTitle,
52+
},
53+
]
54+
: [...selected];
55+
56+
const shallDisable = (item: BugCustomStatus): boolean => {
57+
if (item.id !== customStatusNotABugInfo.customStatusId)
58+
return !counters[item.id];
59+
if (currentIsNaBugExcluded) return currentIsNaBugExcluded;
60+
return !counters[item.id];
61+
};
62+
63+
const filterNaBug = (arr: BugCustomStatus[]) =>
64+
arr.filter(
65+
(item: BugCustomStatus) =>
66+
item.id !== customStatusNotABugInfo.customStatusId
67+
);
68+
69+
const shouldDisableToggle = !counters[customStatusNotABugInfo.customStatusId];
70+
3771
return (
3872
<>
3973
<Accordion level={3} defaultExpandedSections={[]}>
@@ -51,14 +85,18 @@ export const CustomStatusField = ({
5185
textTransform: 'capitalize',
5286
}}
5387
>
54-
{selected && selected.length
55-
? `${selected
88+
{selectedWithNaB && selectedWithNaB.length
89+
? `${selectedWithNaB
5690
.slice(0, maxItemsToShow)
57-
.map((item) => item.name)
91+
.map((item) =>
92+
item.id === customStatusNotABugInfo.actionIdentifier
93+
? customStatusNotABugInfo.drawerTitle
94+
: getCustomStatusInfo(item?.name as BugState, t).text
95+
)
5896
.join(', ')
5997
.toLowerCase()} ${
60-
selected.length > maxItemsToShow
61-
? `+${selected.length - maxItemsToShow}`
98+
selectedWithNaB.length > maxItemsToShow
99+
? `+${selectedWithNaB.length - maxItemsToShow}`
62100
: ''
63101
}`
64102
: t(
@@ -68,6 +106,33 @@ export const CustomStatusField = ({
68106
</Accordion.Label>
69107
</Accordion.Header>
70108
<Accordion.Panel>
109+
<Field style={{ marginBottom: globalTheme.space.md }}>
110+
<Toggle
111+
disabled={shouldDisableToggle}
112+
checked={currentIsNaBugExcluded}
113+
onChange={(event) => {
114+
dispatch(setIsNaBugExcluded(event.target.checked));
115+
dispatch(
116+
updateFilters({
117+
filters: { customStatuses: [...filterNaBug(selected)] },
118+
})
119+
);
120+
}}
121+
>
122+
<LabelSpaceBetween
123+
isRegular
124+
style={{
125+
color: globalTheme.palette.grey[700],
126+
...(shouldDisableToggle && disabledStyle),
127+
}}
128+
>
129+
{customStatusNotABugInfo.drawerTitle}
130+
<MD>
131+
{counters[customStatusNotABugInfo.customStatusId] || 0}
132+
</MD>
133+
</LabelSpaceBetween>
134+
</Toggle>
135+
</Field>
71136
{available.length
72137
? available
73138
.slice(0, showMore ? undefined : maxItemsToShow)
@@ -76,7 +141,7 @@ export const CustomStatusField = ({
76141
<Checkbox
77142
value={item.name}
78143
name="filter-custom-status"
79-
disabled={!counters[item.id]}
144+
disabled={shallDisable(item)}
80145
checked={selected.map((i) => i.id).includes(item.id)}
81146
onChange={() => {
82147
dispatch(
@@ -98,7 +163,7 @@ export const CustomStatusField = ({
98163
isRegular
99164
style={{
100165
color: globalTheme.palette.grey[700],
101-
...(!counters[item.id] && disabledStyle),
166+
...(shallDisable(item) && disabledStyle),
102167
}}
103168
>
104169
{getCustomStatusInfo(item?.name as BugState, t).text}

src/pages/Bugs/Drawer/index.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ import { useAppSelector, useAppDispatch } from 'src/app/hooks';
1010
import { theme as globalTheme } from 'src/app/theme';
1111
import {
1212
getCurrentCampaignData,
13+
getIsNaBugExcluded,
1314
resetFilters,
1415
setFilterDrawerOpen,
1516
} from 'src/features/bugsPage/bugsPageSlice';
1617
import styled from 'styled-components';
18+
import { Bug } from 'src/features/api';
19+
import { getExcludeNotABugInfo } from 'src/common/components/utils/getExcludeNotABugInfo';
1720
import { useCampaignBugs } from '../Content/BugsTable/hooks/useCampaignBugs';
1821
import { DeviceField } from './DeviceField';
1922
import { OsField } from './OsField';
@@ -26,6 +29,7 @@ import { UniqueField } from './UniqueField';
2629
import { UseCaseField } from './UseCaseField';
2730
import { PriorityField } from './PriorityField';
2831
import { CustomStatusField } from './CustomStatusField';
32+
import { BugItem } from '../types';
2933

3034
export const WaterButton = styled(Button)``;
3135

@@ -43,6 +47,8 @@ const BugsFilterDrawer = () => {
4347

4448
const campaignData = getCurrentCampaignData();
4549

50+
const customStatusNotABugInfo = getExcludeNotABugInfo(t);
51+
4652
const memoizedFilters = useMemo(() => {
4753
if (!campaignData) return <Skeleton />;
4854

@@ -118,6 +124,19 @@ const BugsFilterDrawer = () => {
118124

119125
const { bugs } = useCampaignBugs(currentCampaign ?? 0);
120126

127+
const currentIsNaBugExcluded = getIsNaBugExcluded();
128+
let bugItems: BugItem[] = [];
129+
if (bugs && bugs.items && bugs.items?.length > 0) {
130+
if (currentIsNaBugExcluded) {
131+
bugItems = bugs.items.filter(
132+
(item: Bug) =>
133+
item.custom_status.id !== customStatusNotABugInfo.customStatusId
134+
);
135+
} else {
136+
bugItems = bugs.items;
137+
}
138+
}
139+
121140
if (!campaignData || !currentCampaign) return <Skeleton />;
122141

123142
const onClose = () => {
@@ -152,10 +171,7 @@ const BugsFilterDrawer = () => {
152171
onClick={onCtaClick}
153172
>
154173
{t('__BUGS_PAGE_FILTER_DRAWER_CONFIRM_BUTTON')}
155-
{bugs &&
156-
bugs.items &&
157-
bugs.items?.length > 0 &&
158-
` (${bugs?.items?.length})`}
174+
{bugItems.length && ` (${bugItems.length})`}
159175
</WaterButton>
160176
</Drawer.FooterItem>
161177
</Drawer.Footer>

src/pages/Bugs/Filters/CustomStatusFilter.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
import { CounterMultiselect } from '@appquality/unguess-design-system';
22
import {
33
getCurrentCampaignData,
4+
getIsNaBugExcluded,
45
updateFilters,
56
} from 'src/features/bugsPage/bugsPageSlice';
67
import { useTranslation } from 'react-i18next';
78
import { useAppDispatch } from 'src/app/hooks';
89
import { getCustomStatusInfo } from 'src/common/components/utils/getCustomStatusInfo';
10+
import { BugCustomStatus } from 'src/features/api';
11+
import { getExcludeNotABugInfo } from 'src/common/components/utils/getExcludeNotABugInfo';
912
import { useFilterData } from '../Drawer/useFilterData';
1013

1114
export const CustomStatusFilter = () => {
1215
const dispatch = useAppDispatch();
1316
const data = getCurrentCampaignData();
1417
const { counters } = useFilterData('customStatuses');
1518
const { t } = useTranslation();
19+
const currentIsNaBugExcluded = getIsNaBugExcluded();
1620

1721
if (
1822
!data ||
@@ -23,6 +27,15 @@ export const CustomStatusFilter = () => {
2327
)
2428
return null;
2529

30+
const customStatusNotABugInfo = getExcludeNotABugInfo(t);
31+
32+
const shallDisable = (item: BugCustomStatus): boolean => {
33+
if (item.id !== customStatusNotABugInfo.customStatusId)
34+
return !counters[item.id];
35+
if (currentIsNaBugExcluded) return currentIsNaBugExcluded;
36+
return !counters[item.id];
37+
};
38+
2639
return (
2740
<div style={{ maxWidth: '170px' }}>
2841
<CounterMultiselect
@@ -49,7 +62,7 @@ export const CustomStatusFilter = () => {
4962
.map((item) => ({
5063
itemId: item.id,
5164
label: getCustomStatusInfo(item.name as BugState, t).text,
52-
disabled: !counters[item.id],
65+
disabled: shallDisable(item),
5366
selected: data.customStatuses.selected
5467
.map((i) => i.id)
5568
.includes(item.id),

0 commit comments

Comments
 (0)