Skip to content

Commit f0f20cf

Browse files
authored
Schreiaj/stacked pr hiccup (#238)
* Linter Cleanup Minor changes to clean up linter errors ghstack-source-id: cb3de56cf9f18ccc20015ab3296c507a85fb66e6 Pull Request resolved: #236 * Highlight Low Confidence Extractions Highlights low confidence extractions: - Dynamic computation of error count - Highlights low confidence rows ghstack-source-id: 014d1a0a5067243cc28c930533762969a1fbb2cb Pull Request resolved: #237
1 parent f7f1fcd commit f0f20cf

File tree

7 files changed

+51
-33
lines changed

7 files changed

+51
-33
lines changed

OCR/frontend/e2e/App.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ test.describe('when templates exist', async () => {
5252
localStorage.setItem('templates', JSON.stringify(templates))
5353
})
5454
})
55-
test('displays list of templates if they exist and sorting functions', async ({page, baseURL}) => {
55+
test('displays list of templates if they exist and sorting functions', async ({page}) => {
5656
await page.goto('/')
5757
await expect(page.getByRole('heading', { name: 'Saved Templates' })).toBeVisible()
5858
await expect(page.locator('tbody').getByRole('row')).toHaveCount(4)

OCR/frontend/e2e/ReviewTemplate.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@ test.describe("ReviewTemplate Page", () => {
5353
const headers = page.locator("th");
5454
await expect(headers.nth(0)).toHaveText("Label"); // First header
5555
await expect(headers.nth(1)).toHaveText("Value"); // Second header
56-
await expect(headers.nth(2)).toHaveText("Label Confidence"); // Third header
56+
await expect(headers.nth(3)).toHaveText("Label Confidence"); // Third header
5757
});
5858
});

OCR/frontend/src/components/SortableTable/SortableTable.tsx

+18-13
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import {FC, useState} from 'react';
2-
import {Icon, Table} from "@trussworks/react-uswds";
2+
import {Table} from "@trussworks/react-uswds";
33
import SortArrow from './sort-direction-arrow.svg'
44
import SortableIcon from './sortable-icon.svg'
55
import './SortableTable.scss'
66

77
interface SortableTableProps {
8-
data: Array<Map<string, any>>,
8+
data: Array<Map<string, object>>,
99
sortableBy: Array<string> | undefined,
1010
defaultSort: string | undefined,
1111
defaultDescending: boolean | undefined,
1212
columns: Array<string> | undefined,
1313
columnNames: Map<string, string> | undefined,
14-
formatters: Map<string, (any) => any> | undefined
14+
formatters: Map<string, (any) => object> | undefined
1515
}
1616

1717
const SORTS = {
@@ -23,17 +23,18 @@ const SORTS = {
2323

2424
export const SortableTable: FC<SortableTableProps> = ({
2525
data,
26-
sortableBy,
27-
defaultSort,
28-
defaultDescending = false,
2926
columns = Object.keys(data[0]),
27+
sortableBy = columns,
28+
defaultSort = columns?.[0],
29+
defaultDescending = false,
30+
3031
formatters = {},
3132
columnNames = {},
3233
}: SortableTableProps) => {
3334

34-
const [sortBy, setSortBy] = useState(defaultSort || columns?.[0])
35+
const [sortBy, setSortBy] = useState(defaultSort)
3536
const [isDescending, setIsDescending] = useState(defaultDescending)
36-
37+
const sortableSet = new Set(sortableBy || [])
3738
const updateSort = (column: string) => {
3839
if (column === sortBy) {
3940
setIsDescending(!isDescending)
@@ -45,6 +46,7 @@ export const SortableTable: FC<SortableTableProps> = ({
4546
const columnData = data?.[0]?.[sortBy]
4647
const columnType = Object.prototype.toString.call(columnData)
4748
const sortFunc = SORTS[columnType] || new Intl.Collator(navigator.language).compare
49+
4850
const sortedData = data?.toSorted((a, b) => sortFunc(a[sortBy], b[sortBy])) || []
4951

5052
if (isDescending) {
@@ -57,7 +59,8 @@ export const SortableTable: FC<SortableTableProps> = ({
5759
<thead>
5860
<tr>
5961
{columns.map((c, idx) => {
60-
return <SortableTableHeader key={String(idx)} sortBy={sortBy as string} column={c} name={columnNames?.[c] || c}
62+
return <SortableTableHeader key={String(idx)} disabled={!sortableSet.has(c)}
63+
sortBy={sortBy as string} column={c} name={columnNames?.[c] || c}
6164
isDescending={isDescending || false} onClick={updateSort}/>
6265
})}
6366
</tr>
@@ -82,22 +85,24 @@ interface SortableTableHeaderProps {
8285
column: string,
8386
isDescending: boolean,
8487
onClick: (string) => void,
85-
key: string
88+
key: string,
89+
disabled: boolean
8690
}
8791

8892
const SortableTableHeader: FC<SortableTableHeaderProps> = ({
8993
sortBy,
9094
name, column, isDescending,
91-
onClick
95+
onClick,
96+
disabled = false
9297
}: SortableTableHeaderProps) => {
9398

9499
const isSortedBy = sortBy === column
95100
return (
96-
<th onClick={() => onClick(column)}>
101+
<th onClick={disabled?() => {}:() => onClick(column)}>
97102
<div className="display-flex flex-row">
98103
<div>{name}</div>
99104
<div className="flex-1"></div>
100-
{isSortedBy ? <SortOrderIcon isDescending={isDescending}/> : <SortIcon/>}
105+
{!disabled && (isSortedBy ? <SortOrderIcon isDescending={isDescending}/> : <SortIcon/>)}
101106
</div>
102107
</th>
103108
)

OCR/frontend/src/components/TemplatesIndex/TemplatesIndex.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import {SortableTable} from "../SortableTable/SortableTable.tsx";
44
import {useNavigate} from "react-router-dom";
55
import extractImage from "../../assets/extract_image.svg";
66

7-
interface TemplateIndexProps {
8-
}
7+
type TemplateIndexProps = unknown
98

10-
export const TemplatesIndex: FC<TemplateIndexProps> = ({}) => {
9+
export const TemplatesIndex: FC<TemplateIndexProps> = () => {
1110
const [templates, setTemplates] = useState([])
1211
const navigate = useNavigate()
1312
useEffect(() => {
@@ -128,7 +127,7 @@ export const TemplatesIndex: FC<TemplateIndexProps> = ({}) => {
128127
delete window.ClearTemplates
129128
delete window.LoadSavedTemplates
130129
}
131-
}, []);
130+
});
132131

133132
if (!templates || templates.length === 0) {
134133
return (
@@ -168,7 +167,8 @@ export const TemplatesIndex: FC<TemplateIndexProps> = ({}) => {
168167
<h2>Saved Templates</h2>
169168
<SortableTable columns={templateColumns} data={templates}
170169
formatters={templateColumnFormatters}
171-
columnNames={templateColumnNames}/>
170+
columnNames={templateColumnNames}
171+
/>
172172
</div>
173173
</div>
174174
</>)

OCR/frontend/src/pages/ReviewTemplate.tsx

+21-11
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ const ReviewTemplate: React.FC = () => {
4343
text: "5",
4444
confidence: 97.1,
4545
},
46+
DateOfService: {
47+
text: "/20/2024",
48+
confidence: 45.2
49+
}
4650
},
4751
};
4852

@@ -74,7 +78,8 @@ const ReviewTemplate: React.FC = () => {
7478
}
7579

7680
const { file_image, results } = submissionData;
77-
81+
const errorCount = Object.values(results).filter(r => r.confidence <= 75.0).length
82+
const hasErrors = errorCount > 0
7883
return (
7984
<div className="display-flex flex-column flex-justify-start width-full height-full padding-1 padding-top-2">
8085
<ExtractDataHeader
@@ -109,27 +114,32 @@ const ReviewTemplate: React.FC = () => {
109114
Review and edit errors before you submit.
110115
</p>
111116
<div className="display-flex flex-align-center text-error">
112-
<span className="font-sans-sm margin-right-1">Errors: 1</span>
113-
<Icon.Warning className="text-error" />
117+
{hasErrors && <><span className="font-sans-sm margin-right-1">Errors: {errorCount}</span>
118+
<Icon.Warning className="text-error"/></>}
114119
</div>
115120
</div>
116121

117122
<Table fullWidth striped>
118123
<thead>
119-
<tr>
124+
<tr>
120125
<th>Label</th>
121126
<th>Value</th>
127+
<th></th>
122128
<th>Label Confidence</th>
123129
</tr>
124130
</thead>
125131
<tbody>
126-
{Object.entries(results).map(([key, value]) => (
127-
<tr key={key}>
128-
<td>{key}</td>
129-
<td>{value.text}</td>
130-
<td>{value.confidence}%</td>
131-
</tr>
132-
))}
132+
{Object.entries(results).map(([key, value]) => {
133+
const isError = value.confidence <= 75.0
134+
return (
135+
<tr key={key}>
136+
<td>{key}</td>
137+
<td className={`${isError ? 'text-error' : ''}`}>{value.text}</td>
138+
<td>{isError && <Icon.Warning className="text-error"/>}</td>
139+
<td className={`${isError ? 'text-error' : ''}`}>{value.confidence}%</td>
140+
</tr>
141+
)
142+
})}
133143
</tbody>
134144
</Table>
135145
</div>

OCR/frontend/src/types/templates.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
interface Template {
1+
interface Template {
22
name: string;
33
lastUpdated: Date | undefined;
44
createdBy: string | undefined;

OCR/frontend/tsconfig.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@
33
"references": [
44
{ "path": "./tsconfig.app.json" },
55
{ "path": "./tsconfig.node.json" }
6-
]
6+
],
7+
"compilerOptions": {
8+
"lib": ["ESNext.Array"]
9+
}
710
}

0 commit comments

Comments
 (0)