Skip to content

Commit 007b9ab

Browse files
Merge pull request #5389 from 3drepo/ISSUE_5374
ISSUE #5374 - Tickets filters: initial filters
2 parents 6bb573f + fec87dc commit 007b9ab

File tree

4 files changed

+112
-76
lines changed

4 files changed

+112
-76
lines changed

frontend/src/v5/ui/controls/chip/chip.types.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export const STATUS_TYPE_MAP = {
176176
},
177177
};
178178

179-
enum TicketStatusDefaultValues {
179+
export enum TicketStatusDefaultValues {
180180
OPEN = 'Open',
181181
IN_PROGRESS = 'In Progress',
182182
FOR_APPROVAL = 'For Approval',
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* Copyright (C) 2025 3D Repo Ltd
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Affero General Public License as
6+
* published by the Free Software Foundation, either version 3 of the
7+
* License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Affero General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
import { TicketsCardActionsDispatchers, ViewerGuiActionsDispatchers } from '@/v5/services/actionsDispatchers';
19+
import { TicketsHooksSelectors } from '@/v5/services/selectorsHooks';
20+
import { isEmpty, uniq } from 'lodash';
21+
import { useParams } from 'react-router-dom';
22+
import { useEffect } from 'react';
23+
import { ViewerParams } from '../../routes.constants';
24+
import { Transformers, useSearchParam } from '../../useSearchParam';
25+
import { VIEWER_PANELS } from '@/v4/constants/viewerGui';
26+
import { CardFilter } from '@components/viewer/cards/cardFilters/cardFilters.types';
27+
import { StatusValue } from '@/v5/store/tickets/tickets.types';
28+
import { TicketStatusDefaultValues, TicketStatusTypes, TreatmentStatuses } from '@controls/chip/chip.types';
29+
import { selectStatusConfigByTemplateId } from '@/v5/store/tickets/tickets.selectors';
30+
import { getState } from '@/v5/helpers/redux.helpers';
31+
32+
const TICKET_CODE_REGEX = /^[a-zA-Z]{3}:\d+$/;
33+
export const DefaultTicketFiltersSetter = () => {
34+
const { containerOrFederation } = useParams<ViewerParams>();
35+
const [ticketSearchParam, setTicketSearchParam] = useSearchParam('ticketSearch', Transformers.STRING_ARRAY);
36+
37+
const tickets = TicketsHooksSelectors.selectTickets(containerOrFederation);
38+
const templates = TicketsHooksSelectors.selectTemplates(containerOrFederation);
39+
const hasTicketData = !isEmpty(tickets) && !isEmpty(templates);
40+
41+
const getTicketFiltersFromURL = (values): CardFilter[] => [{
42+
module: '',
43+
property: 'Ticket ID',
44+
type: 'ticketId',
45+
filter: {
46+
operator: 'eq',
47+
values,
48+
},
49+
}];
50+
51+
const getNonCompletedTicketFiltersByStatus = (): CardFilter => {
52+
const isCompletedValue = ({ type }: StatusValue) => [TicketStatusTypes.DONE, TicketStatusTypes.VOID].includes(type);
53+
const getValuesByTemplate = ({ _id }) => selectStatusConfigByTemplateId(getState(), containerOrFederation, _id).values;
54+
55+
const completedValueNames = templates
56+
.flatMap(getValuesByTemplate)
57+
.filter(isCompletedValue)
58+
.map((v) => v.name);
59+
60+
const values = uniq([
61+
TicketStatusDefaultValues.CLOSED,
62+
TicketStatusDefaultValues.VOID,
63+
...completedValueNames,
64+
]);
65+
66+
return {
67+
module: '',
68+
property: 'Status',
69+
type: 'oneOf',
70+
filter: {
71+
operator: 'neq',
72+
values,
73+
},
74+
};
75+
};
76+
const getNonCompletedTicketFiltersBySafetibase = (): CardFilter => ({
77+
module: 'safetibase',
78+
property: 'Treatment Status',
79+
type: 'oneOf',
80+
filter: {
81+
operator: 'neq',
82+
values: [
83+
TreatmentStatuses.REJECTED,
84+
TreatmentStatuses.VOID,
85+
],
86+
},
87+
});
88+
89+
const getNonCompletedTicketFilters = (): CardFilter[] => {
90+
let filters = [getNonCompletedTicketFiltersByStatus()];
91+
const hasSafetibase = templates.some((t) => t?.modules?.some((module) => module.type === 'safetibase'));
92+
if (hasSafetibase) {
93+
filters.push(getNonCompletedTicketFiltersBySafetibase());
94+
}
95+
return filters;
96+
};
97+
98+
useEffect(() => {
99+
if (hasTicketData) {
100+
const ticketCodes = ticketSearchParam.filter((query) => TICKET_CODE_REGEX.test(query)).map((q) => q.toUpperCase());
101+
const filters: CardFilter[] = ticketCodes.length ? getTicketFiltersFromURL(ticketCodes) : getNonCompletedTicketFilters();
102+
filters.forEach(TicketsCardActionsDispatchers.upsertFilter);
103+
ViewerGuiActionsDispatchers.setPanelVisibility(VIEWER_PANELS.TICKETS, true);
104+
setTicketSearchParam();
105+
}
106+
}, [hasTicketData]);
107+
108+
return <></>;
109+
};

frontend/src/v5/ui/routes/viewer/handleTicketsCardSearchParams/handleTicketsCardSearchParams.component.tsx

Lines changed: 0 additions & 73 deletions
This file was deleted.

frontend/src/v5/ui/routes/viewer/viewer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { VIEWER_EVENTS } from '@/v4/constants/viewer';
2424
import { CheckLatestRevisionReadiness } from './checkLatestRevisionReadiness/checkLatestRevisionReadiness.container';
2525
import { ViewerParams } from '../routes.constants';
2626
import { InvalidContainerOverlay, InvalidFederationOverlay } from './invalidViewerOverlay';
27-
import { HandleTicketsCardSearchParams } from './handleTicketsCardSearchParams/handleTicketsCardSearchParams.component';
27+
import { DefaultTicketFiltersSetter } from './defaultTicketFiltersSetter/defaultTicketFiltersSetter.component';
2828
import { SpinnerLoader } from '@controls/spinnerLoader';
2929
import { CentredContainer } from '@controls/centredContainer';
3030
import { TicketsCardViews } from './tickets/tickets.constants';
@@ -111,7 +111,7 @@ export const Viewer = () => {
111111

112112
return (
113113
<>
114-
<HandleTicketsCardSearchParams />
114+
<DefaultTicketFiltersSetter />
115115
<OpenDrawingFromUrl />
116116
<CheckLatestRevisionReadiness />
117117
<ViewerCanvases />

0 commit comments

Comments
 (0)