Skip to content

Commit d7b2e2f

Browse files
feat: #1984 Add test history for the selected seedlot (#2247)
1 parent 1476e7f commit d7b2e2f

File tree

13 files changed

+375
-87
lines changed

13 files changed

+375
-87
lines changed

frontend/src/components/GenericTable/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const GenericTable = <T extends Record<string, any>>({
7676
enableHiding = false,
7777
enableSorting = false,
7878
manualSorting = false,
79-
sorting,
79+
sorting = [],
8080
onSortingChange,
8181
enableFilters = false,
8282
enableRowSelection = false,

frontend/src/types/consep/TestingSearchType.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type TestingSearchResponseType = {
2525
itemId: string;
2626
seedlotSample: string;
2727
riaSkey: number;
28+
activityTypeCd: string;
2829
};
2930

3031
// Type for pagination details

frontend/src/views/CONSEP/TestingActivities/TestSearch/TestListTable.tsx

Lines changed: 76 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
import React, { useRef } from 'react';
2-
import { Row, Column, Button } from '@carbon/react';
1+
/* eslint-disable camelcase */
2+
import React, { useRef, useState } from 'react';
3+
import { type MRT_TableInstance } from 'material-react-table';
4+
import {
5+
Row, Column, Button, Modal, Tooltip
6+
} from '@carbon/react';
37
import * as Icons from '@carbon/icons-react';
48

59
import GenericTable from '../../../../components/GenericTable';
610
import ShowHideColumnControl from './ToolbarControls/ShowHideColumnControl';
11+
import TestHistory from './ToolbarControls/TestHistory';
712
import { getTestingActivityListColumns, columnVisibilityLocalStorageKey } from './constants';
13+
814
import type {
915
TestingSearchResponseType,
1016
PaginationInfoType
@@ -30,6 +36,8 @@ const TestListTable = ({
3036
sorting
3137
}: TestListTableProp) => {
3238
const tableBodyRef = useRef<HTMLTableSectionElement>(null);
39+
const tableRef = useRef<MRT_TableInstance<TestingSearchResponseType> | null>(null);
40+
const [showTestHistory, setShowTestHistory] = useState(false);
3341

3442
const actions = [
3543
{
@@ -45,7 +53,7 @@ const TestListTable = ({
4553
{
4654
label: 'Test history',
4755
type: 'tertiary',
48-
action: () => {}
56+
action: () => setShowTestHistory(true)
4957
},
5058
{
5159
label: 'Add activity',
@@ -75,6 +83,28 @@ const TestListTable = ({
7583

7684
return (
7785
<div className="concep-test-search-table-container">
86+
<Modal
87+
className="concep-test-history-modal"
88+
open={showTestHistory}
89+
passiveModal
90+
size="lg"
91+
modalHeading={
92+
tableRef.current?.getSelectedRowModel().rows?.length === 1
93+
? `Seedlot ${
94+
tableRef.current.getSelectedRowModel().rows[0].original.seedlotDisplay
95+
}: Test history`
96+
: 'Seedlot: Test history'
97+
}
98+
onRequestClose={() => setShowTestHistory(false)}
99+
selectorsFloatingMenus={[
100+
// specify selectors for floating menus
101+
// that should remain accessible and on top of the modal
102+
'.MuiPopover-root',
103+
'.MuiPaper-root'
104+
]}
105+
>
106+
{showTestHistory && tableRef.current && <TestHistory table={tableRef.current} />}
107+
</Modal>
78108
<Row className="concep-test-search-table">
79109
<GenericTable
80110
columns={getTestingActivityListColumns()}
@@ -106,29 +136,49 @@ const TestListTable = ({
106136
renderTopToolbarCustomActions={() => (
107137
<div className="concep-test-search-table-title">{`Total search result: ${paginationInfo.totalElements}`}</div>
108138
)}
109-
renderToolbarInternalActions={({ table }) => (
110-
<Column>
111-
{actions.map(({
112-
label, icon, action, type
113-
}) => (
114-
<Button
115-
key={label}
116-
onClick={action}
117-
kind={type}
118-
aria-label={label}
119-
size="md"
120-
className="concep-test-search-table-toolbar-button"
121-
>
122-
{label}
123-
{icon}
124-
</Button>
125-
))}
126-
<ShowHideColumnControl
127-
table={table}
128-
columnVisibilityLocalStorageKey={columnVisibilityLocalStorageKey}
129-
/>
130-
</Column>
131-
)}
139+
renderToolbarInternalActions={({ table }) => {
140+
tableRef.current = table as MRT_TableInstance<TestingSearchResponseType>;
141+
const selectedRows = table.getSelectedRowModel().rows;
142+
const isTestHistoryEnabled = selectedRows.length === 1;
143+
const testHistoryDisabledReason = selectedRows.length === 0
144+
? 'Select one seedlot to view its test history.'
145+
: 'You can only view test history for one seedlot at a time.';
146+
147+
return (
148+
<Column>
149+
{actions.map(({
150+
label, icon, action, type
151+
}) => {
152+
const button = (
153+
<Button
154+
key={label}
155+
onClick={action}
156+
kind={type}
157+
aria-label={label}
158+
size="md"
159+
className="concep-test-search-table-toolbar-button"
160+
disabled={label === 'Test history' && !isTestHistoryEnabled}
161+
>
162+
{label}
163+
{icon}
164+
</Button>
165+
);
166+
167+
return label === 'Test history' && !isTestHistoryEnabled ? (
168+
<Tooltip key={label} label={testHistoryDisabledReason} align="right">
169+
<span>{button}</span>
170+
</Tooltip>
171+
) : (
172+
button
173+
);
174+
})}
175+
<ShowHideColumnControl
176+
table={table as MRT_TableInstance<TestingSearchResponseType>}
177+
columnVisibilityLocalStorageKey={columnVisibilityLocalStorageKey}
178+
/>
179+
</Column>
180+
);
181+
}}
132182
/>
133183
</Row>
134184
</div>

frontend/src/views/CONSEP/TestingActivities/TestSearch/ToolbarControls/ShowHideColumnControl/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import { Button, Checkbox } from '@carbon/react';
44
import * as Icons from '@carbon/icons-react';
55
import { type MRT_TableInstance } from 'material-react-table';
66
import { Menu, MenuItem } from '@mui/material';
7+
import type { TestingSearchResponseType } from '../../../../../../types/consep/TestingSearchType';
78
import './styles.scss';
89

910
const ShowHideColumnControl = ({
1011
table,
1112
columnVisibilityLocalStorageKey = 'table-columns-visibility'
1213
}: {
13-
table: MRT_TableInstance<any>;
14+
table: MRT_TableInstance<TestingSearchResponseType>;
1415
columnVisibilityLocalStorageKey?: string;
1516
}) => {
1617
// The button element that the menu is attached to
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/* eslint-disable camelcase */
2+
import React from 'react';
3+
import { type MRT_ColumnDef, MRT_Cell } from 'material-react-table';
4+
import { Tag } from '@carbon/react';
5+
import { TestingSearchResponseType } from '../../../../../../types/consep/TestingSearchType';
6+
import { formatDateCell } from '../../constants';
7+
8+
export const getTestHistoryTableColumns = (): MRT_ColumnDef<TestingSearchResponseType>[] => [
9+
{
10+
accessorKey: 'activityTypeCd',
11+
header: 'Type',
12+
enableEditing: false,
13+
size: 50
14+
},
15+
{
16+
accessorKey: 'testCategoryCd',
17+
header: 'Category',
18+
enableEditing: false,
19+
size: 40
20+
},
21+
{
22+
accessorKey: 'actualEndDtTm',
23+
header: 'End Date',
24+
enableEditing: false,
25+
Cell: ({ cell }) => formatDateCell(cell.getValue<string | null>()),
26+
size: 110
27+
},
28+
{
29+
accessorKey: 'requestItem',
30+
header: 'Request ID',
31+
enableEditing: false,
32+
size: 110
33+
},
34+
{
35+
accessorKey: 'currentTestInd',
36+
header: 'Curr',
37+
enableEditing: false,
38+
Cell: ({ cell }: { cell: MRT_Cell<TestingSearchResponseType> }) => {
39+
const value = cell.getValue();
40+
return value === -1 ? (
41+
<Tag type="teal" size="sm">
42+
Curr
43+
</Tag>
44+
) : null;
45+
},
46+
size: 80
47+
},
48+
{
49+
accessorKey: 'germinationPct',
50+
header: 'Germ',
51+
enableEditing: false,
52+
size: 50
53+
},
54+
{
55+
accessorKey: 'testRank',
56+
header: 'Rnk',
57+
enableEditing: false,
58+
size: 50
59+
},
60+
{
61+
accessorKey: 'pv',
62+
header: 'PV',
63+
enableEditing: false,
64+
size: 50
65+
},
66+
{
67+
accessorKey: 'moisturePct',
68+
header: 'MC',
69+
enableEditing: false,
70+
size: 50
71+
},
72+
{
73+
accessorKey: 'purityPct',
74+
header: 'Purity',
75+
enableEditing: false,
76+
size: 50
77+
},
78+
{
79+
accessorKey: 'seedsPerGram',
80+
header: 'SPG',
81+
enableEditing: false,
82+
size: 50
83+
},
84+
{
85+
accessorKey: 'otherTestResult',
86+
header: 'Oth',
87+
enableEditing: false,
88+
size: 50
89+
},
90+
{
91+
accessorKey: 'acceptResultInd',
92+
header: 'Acc',
93+
enableEditing: false,
94+
Cell: ({ cell }: { cell: MRT_Cell<TestingSearchResponseType> }) => {
95+
const value = cell.getValue();
96+
return value === -1 ? (
97+
<Tag type="green" size="sm">
98+
Acc
99+
</Tag>
100+
) : null;
101+
},
102+
size: 80
103+
},
104+
{
105+
accessorKey: 'significntStsInd',
106+
header: 'Sig',
107+
enableEditing: false,
108+
Cell: ({ cell }: { cell: MRT_Cell<TestingSearchResponseType> }) => {
109+
const value = cell.getValue();
110+
return value === -1 ? (
111+
<Tag type="purple" size="sm">
112+
Sig
113+
</Tag>
114+
) : null;
115+
},
116+
size: 80
117+
}
118+
];
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/* eslint-disable camelcase */
2+
import React, {
3+
useState, useRef, useEffect, useMemo
4+
} from 'react';
5+
import { useMutation } from '@tanstack/react-query';
6+
import { type MRT_TableInstance } from 'material-react-table';
7+
import { InlineNotification } from '@carbon/react';
8+
import { searchTestingActivities } from '../../../../../../api-service/consep/searchTestingActivitiesAPI';
9+
import GenericTable from '../../../../../../components/GenericTable';
10+
import { getTestHistoryTableColumns } from './constants';
11+
import type {
12+
PaginatedTestingSearchResponseType,
13+
TestingSearchResponseType,
14+
PaginationInfoType
15+
} from '../../../../../../types/consep/TestingSearchType';
16+
17+
const TestHistory = ({ table }: { table: MRT_TableInstance<TestingSearchResponseType> }) => {
18+
const tableBodyRef = useRef<HTMLTableSectionElement>(null);
19+
const [searchResults, setSearchResults] = useState<TestingSearchResponseType[]>([]);
20+
const [paginationInfo, setPaginationInfo] = useState<PaginationInfoType>({
21+
totalElements: 0,
22+
totalPages: 0,
23+
pageNumber: 0,
24+
pageSize: 10
25+
});
26+
const [alert, setAlert] = useState<{
27+
status: 'error' | 'info' | 'success' | 'warning';
28+
message: string;
29+
} | null>(null);
30+
const columns = useMemo(() => getTestHistoryTableColumns(), []);
31+
32+
const searchMutation = useMutation({
33+
mutationFn: ({ page = 0, size = 10 }: { page?: number; size?: number }) => {
34+
const selectedRows = table.getSelectedRowModel()?.rows ?? [];
35+
const selectedSeedlots = selectedRows.map((row) => row.original.seedlotDisplay);
36+
return searchTestingActivities(
37+
{ lotNumbers: selectedSeedlots },
38+
undefined,
39+
'asc',
40+
false,
41+
size,
42+
page
43+
);
44+
},
45+
onMutate: () => {
46+
setAlert(null);
47+
},
48+
onSuccess: (data: PaginatedTestingSearchResponseType) => {
49+
setSearchResults(data.content);
50+
setPaginationInfo({
51+
totalElements: data.totalElements,
52+
totalPages: data.totalPages,
53+
pageNumber: data.pageNumber,
54+
pageSize: data.pageSize
55+
});
56+
},
57+
onError: (error) => {
58+
setAlert({
59+
status: 'error',
60+
message: `Failed to get the test history: ${error.message}`
61+
});
62+
}
63+
});
64+
65+
useEffect(() => {
66+
searchMutation.mutate({ page: 0, size: paginationInfo.pageSize });
67+
}, []);
68+
69+
const handlePageChange = (pageIndex: number, pageSize: number) => {
70+
searchMutation.mutate({ page: pageIndex, size: pageSize });
71+
};
72+
73+
return (
74+
<div>
75+
{alert?.message && (
76+
<InlineNotification
77+
lowContrast
78+
kind={alert.status}
79+
subtitle={alert?.message}
80+
style={{ marginBottom: '0.8rem' }}
81+
/>
82+
)}
83+
<GenericTable
84+
columns={columns}
85+
data={searchResults}
86+
enablePagination
87+
manualPagination
88+
pageIndex={paginationInfo.pageNumber}
89+
pageSize={paginationInfo.pageSize}
90+
rowCount={paginationInfo.totalElements}
91+
onPaginationChange={handlePageChange}
92+
isLoading={searchMutation.isPending}
93+
tableBodyRef={tableBodyRef}
94+
/>
95+
</div>
96+
);
97+
};
98+
99+
export default TestHistory;

0 commit comments

Comments
 (0)