Compare commits
10 Commits
cb46970808
...
af067f7360
| Author | SHA1 | Date | |
|---|---|---|---|
| af067f7360 | |||
| 949b543d1f | |||
| 8fdb68fb19 | |||
| 136f767309 | |||
| aa9664c459 | |||
| f60f0b1b5c | |||
| 676cd44d9d | |||
| 1d081bb218 | |||
| 52ae7e10aa | |||
| 153bbecc44 |
43
.VSCodeCounter/2025-03-17_14-20-03/details.md
Normal file
43
.VSCodeCounter/2025-03-17_14-20-03/details.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Details
|
||||
|
||||
Date : 2025-03-17 14:20:03
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 28 files, 6565 codes, 1027 comments, 1053 blanks, all 8645 lines
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md) | Markdown | 39 | 0 | 19 | 58 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx) | TypeScript JSX | 230 | 10 | 8 | 248 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx) | TypeScript JSX | 18 | 0 | 3 | 21 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SaveTemplateDialog.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SaveTemplateDialog.tsx) | TypeScript JSX | 83 | 0 | 4 | 87 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx) | TypeScript JSX | 273 | 19 | 37 | 329 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/TemplateManager.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/TemplateManager.tsx) | TypeScript JSX | 193 | 4 | 15 | 212 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx) | TypeScript JSX | 374 | 42 | 44 | 460 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx) | TypeScript JSX | 1,101 | 234 | 213 | 1,548 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx) | TypeScript JSX | 499 | 48 | 54 | 601 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx) | TypeScript JSX | 112 | 12 | 21 | 145 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx) | TypeScript JSX | 232 | 31 | 32 | 295 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx) | TypeScript JSX | 407 | 56 | 52 | 515 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx) | TypeScript JSX | 193 | 23 | 22 | 238 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx) | TypeScript JSX | 289 | 36 | 31 | 356 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx) | TypeScript JSX | 500 | 75 | 89 | 664 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useFilters.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useFilters.tsx) | TypeScript JSX | 89 | 12 | 16 | 117 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx) | TypeScript JSX | 204 | 26 | 33 | 263 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx) | TypeScript JSX | 93 | 13 | 18 | 124 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx) | TypeScript JSX | 219 | 39 | 47 | 305 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx) | TypeScript JSX | 1,060 | 228 | 229 | 1,517 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx) | TypeScript JSX | 20 | 6 | 2 | 28 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts) | TypeScript | 4 | 0 | 1 | 5 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts) | TypeScript | 16 | 4 | 4 | 24 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts) | TypeScript | 124 | 4 | 14 | 142 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts) | TypeScript | 21 | 15 | 5 | 41 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts) | TypeScript | 43 | 24 | 7 | 74 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js) | JavaScript | 28 | 7 | 9 | 44 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts) | TypeScript | 101 | 59 | 24 | 184 |
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
15
.VSCodeCounter/2025-03-17_14-20-03/diff-details.md
Normal file
15
.VSCodeCounter/2025-03-17_14-20-03/diff-details.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Diff Details
|
||||
|
||||
Date : 2025-03-17 14:20:03
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
19
.VSCodeCounter/2025-03-17_14-20-03/diff.md
Normal file
19
.VSCodeCounter/2025-03-17_14-20-03/diff.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Diff Summary
|
||||
|
||||
Date : 2025-03-17 14:20:03
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
22
.VSCodeCounter/2025-03-17_14-20-03/diff.txt
Normal file
22
.VSCodeCounter/2025-03-17_14-20-03/diff.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
Date : 2025-03-17 14:20:03
|
||||
Directory : /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||
|
||||
Languages
|
||||
+----------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------+------------+------------+------------+------------+------------+
|
||||
+----------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+------+------------+------------+------------+------------+------------+
|
||||
+------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+----------+----------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+----------+----------+------------+------------+------------+------------+
|
||||
| Total | | 0 | 0 | 0 | 0 |
|
||||
+----------+----------+------------+------------+------------+------------+
|
||||
1
.VSCodeCounter/2025-03-17_14-20-03/results.json
Normal file
1
.VSCodeCounter/2025-03-17_14-20-03/results.json
Normal file
File diff suppressed because one or more lines are too long
31
.VSCodeCounter/2025-03-17_14-20-03/results.md
Normal file
31
.VSCodeCounter/2025-03-17_14-20-03/results.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Summary
|
||||
|
||||
Date : 2025-03-17 14:20:03
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 28 files, 6565 codes, 1027 comments, 1053 blanks, all 8645 lines
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| TypeScript JSX | 20 | 6,189 | 914 | 970 | 8,073 |
|
||||
| TypeScript | 6 | 309 | 106 | 55 | 470 |
|
||||
| Markdown | 1 | 39 | 0 | 19 | 58 |
|
||||
| JavaScript | 1 | 28 | 7 | 9 | 44 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 28 | 6,565 | 1,027 | 1,053 | 8,645 |
|
||||
| . (Files) | 3 | 63 | 6 | 22 | 91 |
|
||||
| components | 13 | 4,004 | 515 | 536 | 5,055 |
|
||||
| components (Files) | 8 | 2,771 | 357 | 378 | 3,506 |
|
||||
| components/cells | 5 | 1,233 | 158 | 158 | 1,549 |
|
||||
| hooks | 6 | 2,165 | 393 | 432 | 2,990 |
|
||||
| types | 1 | 16 | 4 | 4 | 24 |
|
||||
| utils | 5 | 317 | 109 | 59 | 485 |
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
62
.VSCodeCounter/2025-03-17_14-20-03/results.txt
Normal file
62
.VSCodeCounter/2025-03-17_14-20-03/results.txt
Normal file
@@ -0,0 +1,62 @@
|
||||
Date : 2025-03-17 14:20:03
|
||||
Directory : /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
Total : 28 files, 6565 codes, 1027 comments, 1053 blanks, all 8645 lines
|
||||
|
||||
Languages
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| TypeScript JSX | 20 | 6,189 | 914 | 970 | 8,073 |
|
||||
| TypeScript | 6 | 309 | 106 | 55 | 470 |
|
||||
| Markdown | 1 | 39 | 0 | 19 | 58 |
|
||||
| JavaScript | 1 | 28 | 7 | 9 | 44 |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 28 | 6,565 | 1,027 | 1,053 | 8,645 |
|
||||
| . (Files) | 3 | 63 | 6 | 22 | 91 |
|
||||
| components | 13 | 4,004 | 515 | 536 | 5,055 |
|
||||
| components (Files) | 8 | 2,771 | 357 | 378 | 3,506 |
|
||||
| components/cells | 5 | 1,233 | 158 | 158 | 1,549 |
|
||||
| hooks | 6 | 2,165 | 393 | 432 | 2,990 |
|
||||
| types | 1 | 16 | 4 | 4 | 24 |
|
||||
| utils | 5 | 317 | 109 | 59 | 485 |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md | Markdown | 39 | 0 | 19 | 58 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx | TypeScript JSX | 230 | 10 | 8 | 248 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx | TypeScript JSX | 18 | 0 | 3 | 21 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SaveTemplateDialog.tsx | TypeScript JSX | 83 | 0 | 4 | 87 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx | TypeScript JSX | 273 | 19 | 37 | 329 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/TemplateManager.tsx | TypeScript JSX | 193 | 4 | 15 | 212 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx | TypeScript JSX | 374 | 42 | 44 | 460 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx | TypeScript JSX | 1,101 | 234 | 213 | 1,548 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx | TypeScript JSX | 499 | 48 | 54 | 601 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx | TypeScript JSX | 112 | 12 | 21 | 145 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx | TypeScript JSX | 232 | 31 | 32 | 295 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx | TypeScript JSX | 407 | 56 | 52 | 515 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx | TypeScript JSX | 193 | 23 | 22 | 238 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx | TypeScript JSX | 289 | 36 | 31 | 356 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx | TypeScript JSX | 500 | 75 | 89 | 664 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useFilters.tsx | TypeScript JSX | 89 | 12 | 16 | 117 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx | TypeScript JSX | 204 | 26 | 33 | 263 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx | TypeScript JSX | 93 | 13 | 18 | 124 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx | TypeScript JSX | 219 | 39 | 47 | 305 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx | TypeScript JSX | 1,060 | 228 | 229 | 1,517 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx | TypeScript JSX | 20 | 6 | 2 | 28 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts | TypeScript | 4 | 0 | 1 | 5 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts | TypeScript | 16 | 4 | 4 | 24 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts | TypeScript | 124 | 4 | 14 | 142 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts | TypeScript | 21 | 15 | 5 | 41 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts | TypeScript | 43 | 24 | 7 | 74 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js | JavaScript | 28 | 7 | 9 | 44 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts | TypeScript | 101 | 59 | 24 | 184 |
|
||||
| Total | | 6,565 | 1,027 | 1,053 | 8,645 |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
43
.VSCodeCounter/2025-03-17_16-02-14/details.md
Normal file
43
.VSCodeCounter/2025-03-17_16-02-14/details.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Details
|
||||
|
||||
Date : 2025-03-17 16:02:14
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 28 files, 6551 codes, 1023 comments, 1050 blanks, all 8624 lines
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md) | Markdown | 39 | 0 | 19 | 58 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx) | TypeScript JSX | 230 | 10 | 8 | 248 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx) | TypeScript JSX | 18 | 0 | 3 | 21 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SaveTemplateDialog.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SaveTemplateDialog.tsx) | TypeScript JSX | 83 | 0 | 4 | 87 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx) | TypeScript JSX | 273 | 19 | 37 | 329 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/TemplateManager.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/TemplateManager.tsx) | TypeScript JSX | 193 | 4 | 15 | 212 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx) | TypeScript JSX | 374 | 42 | 44 | 460 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx) | TypeScript JSX | 971 | 194 | 178 | 1,343 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx) | TypeScript JSX | 499 | 48 | 54 | 601 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx) | TypeScript JSX | 112 | 12 | 21 | 145 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx) | TypeScript JSX | 232 | 31 | 32 | 295 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx) | TypeScript JSX | 407 | 56 | 52 | 515 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx) | TypeScript JSX | 193 | 23 | 22 | 238 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx) | TypeScript JSX | 289 | 36 | 31 | 356 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx) | TypeScript JSX | 500 | 75 | 89 | 664 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useFilters.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useFilters.tsx) | TypeScript JSX | 89 | 12 | 16 | 117 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx) | TypeScript JSX | 204 | 26 | 33 | 263 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx) | TypeScript JSX | 209 | 49 | 50 | 308 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx) | TypeScript JSX | 219 | 39 | 47 | 305 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx) | TypeScript JSX | 1,060 | 228 | 229 | 1,517 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx) | TypeScript JSX | 20 | 6 | 2 | 28 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts) | TypeScript | 4 | 0 | 1 | 5 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts) | TypeScript | 16 | 4 | 4 | 24 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts) | TypeScript | 124 | 4 | 14 | 142 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts) | TypeScript | 21 | 15 | 5 | 41 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts) | TypeScript | 43 | 24 | 7 | 74 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js) | JavaScript | 28 | 7 | 9 | 44 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts) | TypeScript | 101 | 59 | 24 | 184 |
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
17
.VSCodeCounter/2025-03-17_16-02-14/diff-details.md
Normal file
17
.VSCodeCounter/2025-03-17_16-02-14/diff-details.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Diff Details
|
||||
|
||||
Date : 2025-03-17 16:02:14
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 2 files, -14 codes, -4 comments, -3 blanks, all -21 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx) | TypeScript JSX | -130 | -40 | -35 | -205 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx) | TypeScript JSX | 116 | 36 | 32 | 184 |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
23
.VSCodeCounter/2025-03-17_16-02-14/diff.md
Normal file
23
.VSCodeCounter/2025-03-17_16-02-14/diff.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Diff Summary
|
||||
|
||||
Date : 2025-03-17 16:02:14
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 2 files, -14 codes, -4 comments, -3 blanks, all -21 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| TypeScript JSX | 2 | -14 | -4 | -3 | -21 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 2 | -14 | -4 | -3 | -21 |
|
||||
| components | 1 | -130 | -40 | -35 | -205 |
|
||||
| hooks | 1 | 116 | 36 | 32 | 184 |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
28
.VSCodeCounter/2025-03-17_16-02-14/diff.txt
Normal file
28
.VSCodeCounter/2025-03-17_16-02-14/diff.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
Date : 2025-03-17 16:02:14
|
||||
Directory : /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
Total : 2 files, -14 codes, -4 comments, -3 blanks, all -21 lines
|
||||
|
||||
Languages
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| TypeScript JSX | 2 | -14 | -4 | -3 | -21 |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 2 | -14 | -4 | -3 | -21 |
|
||||
| components | 1 | -130 | -40 | -35 | -205 |
|
||||
| hooks | 1 | 116 | 36 | 32 | 184 |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx | TypeScript JSX | -130 | -40 | -35 | -205 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx | TypeScript JSX | 116 | 36 | 32 | 184 |
|
||||
| Total | | -14 | -4 | -3 | -21 |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
1
.VSCodeCounter/2025-03-17_16-02-14/results.json
Normal file
1
.VSCodeCounter/2025-03-17_16-02-14/results.json
Normal file
File diff suppressed because one or more lines are too long
31
.VSCodeCounter/2025-03-17_16-02-14/results.md
Normal file
31
.VSCodeCounter/2025-03-17_16-02-14/results.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Summary
|
||||
|
||||
Date : 2025-03-17 16:02:14
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 28 files, 6551 codes, 1023 comments, 1050 blanks, all 8624 lines
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| TypeScript JSX | 20 | 6,175 | 910 | 967 | 8,052 |
|
||||
| TypeScript | 6 | 309 | 106 | 55 | 470 |
|
||||
| Markdown | 1 | 39 | 0 | 19 | 58 |
|
||||
| JavaScript | 1 | 28 | 7 | 9 | 44 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 28 | 6,551 | 1,023 | 1,050 | 8,624 |
|
||||
| . (Files) | 3 | 63 | 6 | 22 | 91 |
|
||||
| components | 13 | 3,874 | 475 | 501 | 4,850 |
|
||||
| components (Files) | 8 | 2,641 | 317 | 343 | 3,301 |
|
||||
| components/cells | 5 | 1,233 | 158 | 158 | 1,549 |
|
||||
| hooks | 6 | 2,281 | 429 | 464 | 3,174 |
|
||||
| types | 1 | 16 | 4 | 4 | 24 |
|
||||
| utils | 5 | 317 | 109 | 59 | 485 |
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
62
.VSCodeCounter/2025-03-17_16-02-14/results.txt
Normal file
62
.VSCodeCounter/2025-03-17_16-02-14/results.txt
Normal file
@@ -0,0 +1,62 @@
|
||||
Date : 2025-03-17 16:02:14
|
||||
Directory : /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
Total : 28 files, 6551 codes, 1023 comments, 1050 blanks, all 8624 lines
|
||||
|
||||
Languages
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| TypeScript JSX | 20 | 6,175 | 910 | 967 | 8,052 |
|
||||
| TypeScript | 6 | 309 | 106 | 55 | 470 |
|
||||
| Markdown | 1 | 39 | 0 | 19 | 58 |
|
||||
| JavaScript | 1 | 28 | 7 | 9 | 44 |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 28 | 6,551 | 1,023 | 1,050 | 8,624 |
|
||||
| . (Files) | 3 | 63 | 6 | 22 | 91 |
|
||||
| components | 13 | 3,874 | 475 | 501 | 4,850 |
|
||||
| components (Files) | 8 | 2,641 | 317 | 343 | 3,301 |
|
||||
| components/cells | 5 | 1,233 | 158 | 158 | 1,549 |
|
||||
| hooks | 6 | 2,281 | 429 | 464 | 3,174 |
|
||||
| types | 1 | 16 | 4 | 4 | 24 |
|
||||
| utils | 5 | 317 | 109 | 59 | 485 |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md | Markdown | 39 | 0 | 19 | 58 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx | TypeScript JSX | 230 | 10 | 8 | 248 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx | TypeScript JSX | 18 | 0 | 3 | 21 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SaveTemplateDialog.tsx | TypeScript JSX | 83 | 0 | 4 | 87 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx | TypeScript JSX | 273 | 19 | 37 | 329 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/TemplateManager.tsx | TypeScript JSX | 193 | 4 | 15 | 212 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx | TypeScript JSX | 374 | 42 | 44 | 460 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx | TypeScript JSX | 971 | 194 | 178 | 1,343 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx | TypeScript JSX | 499 | 48 | 54 | 601 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx | TypeScript JSX | 112 | 12 | 21 | 145 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx | TypeScript JSX | 232 | 31 | 32 | 295 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx | TypeScript JSX | 407 | 56 | 52 | 515 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx | TypeScript JSX | 193 | 23 | 22 | 238 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx | TypeScript JSX | 289 | 36 | 31 | 356 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx | TypeScript JSX | 500 | 75 | 89 | 664 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useFilters.tsx | TypeScript JSX | 89 | 12 | 16 | 117 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx | TypeScript JSX | 204 | 26 | 33 | 263 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx | TypeScript JSX | 209 | 49 | 50 | 308 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx | TypeScript JSX | 219 | 39 | 47 | 305 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx | TypeScript JSX | 1,060 | 228 | 229 | 1,517 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx | TypeScript JSX | 20 | 6 | 2 | 28 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts | TypeScript | 4 | 0 | 1 | 5 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts | TypeScript | 16 | 4 | 4 | 24 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts | TypeScript | 124 | 4 | 14 | 142 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts | TypeScript | 21 | 15 | 5 | 41 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts | TypeScript | 43 | 24 | 7 | 74 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js | JavaScript | 28 | 7 | 9 | 44 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts | TypeScript | 101 | 59 | 24 | 184 |
|
||||
| Total | | 6,551 | 1,023 | 1,050 | 8,624 |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
41
.VSCodeCounter/2025-03-17_16-24-17/details.md
Normal file
41
.VSCodeCounter/2025-03-17_16-24-17/details.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Details
|
||||
|
||||
Date : 2025-03-17 16:24:17
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 26 files, 6193 codes, 1008 comments, 1017 blanks, all 8218 lines
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md) | Markdown | 39 | 0 | 19 | 58 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx) | TypeScript JSX | 230 | 10 | 8 | 248 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx) | TypeScript JSX | 18 | 0 | 3 | 21 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx) | TypeScript JSX | 273 | 19 | 37 | 329 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx) | TypeScript JSX | 374 | 42 | 44 | 460 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx) | TypeScript JSX | 730 | 126 | 106 | 962 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx) | TypeScript JSX | 499 | 48 | 54 | 601 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx) | TypeScript JSX | 112 | 12 | 21 | 145 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx) | TypeScript JSX | 232 | 31 | 32 | 295 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx) | TypeScript JSX | 407 | 56 | 52 | 515 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx) | TypeScript JSX | 193 | 23 | 22 | 238 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx) | TypeScript JSX | 289 | 36 | 31 | 356 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx) | TypeScript JSX | 500 | 75 | 89 | 664 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx) | TypeScript JSX | 248 | 69 | 74 | 391 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx) | TypeScript JSX | 204 | 26 | 33 | 263 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx) | TypeScript JSX | 209 | 49 | 50 | 308 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx) | TypeScript JSX | 219 | 39 | 47 | 305 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx) | TypeScript JSX | 1,060 | 228 | 229 | 1,517 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx) | TypeScript JSX | 20 | 6 | 2 | 28 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts) | TypeScript | 4 | 0 | 1 | 5 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts) | TypeScript | 16 | 4 | 4 | 24 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts) | TypeScript | 124 | 4 | 14 | 142 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts) | TypeScript | 21 | 15 | 5 | 41 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts) | TypeScript | 43 | 24 | 7 | 74 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js) | JavaScript | 28 | 7 | 9 | 44 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts) | TypeScript | 101 | 59 | 24 | 184 |
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
20
.VSCodeCounter/2025-03-17_16-24-17/diff-details.md
Normal file
20
.VSCodeCounter/2025-03-17_16-24-17/diff-details.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Diff Details
|
||||
|
||||
Date : 2025-03-17 16:24:17
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 5 files, -358 codes, -15 comments, -33 blanks, all -406 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SaveTemplateDialog.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SaveTemplateDialog.tsx) | TypeScript JSX | -83 | 0 | -4 | -87 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/TemplateManager.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/TemplateManager.tsx) | TypeScript JSX | -193 | -4 | -15 | -212 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx) | TypeScript JSX | -241 | -68 | -72 | -381 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useFilters.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useFilters.tsx) | TypeScript JSX | -89 | -12 | -16 | -117 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx) | TypeScript JSX | 248 | 69 | 74 | 391 |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
23
.VSCodeCounter/2025-03-17_16-24-17/diff.md
Normal file
23
.VSCodeCounter/2025-03-17_16-24-17/diff.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Diff Summary
|
||||
|
||||
Date : 2025-03-17 16:24:17
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 5 files, -358 codes, -15 comments, -33 blanks, all -406 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| TypeScript JSX | 5 | -358 | -15 | -33 | -406 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 5 | -358 | -15 | -33 | -406 |
|
||||
| components | 3 | -517 | -72 | -91 | -680 |
|
||||
| hooks | 2 | 159 | 57 | 58 | 274 |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
31
.VSCodeCounter/2025-03-17_16-24-17/diff.txt
Normal file
31
.VSCodeCounter/2025-03-17_16-24-17/diff.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
Date : 2025-03-17 16:24:17
|
||||
Directory : /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
Total : 5 files, -358 codes, -15 comments, -33 blanks, all -406 lines
|
||||
|
||||
Languages
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| TypeScript JSX | 5 | -358 | -15 | -33 | -406 |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 5 | -358 | -15 | -33 | -406 |
|
||||
| components | 3 | -517 | -72 | -91 | -680 |
|
||||
| hooks | 2 | 159 | 57 | 58 | 274 |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SaveTemplateDialog.tsx | TypeScript JSX | -83 | 0 | -4 | -87 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/TemplateManager.tsx | TypeScript JSX | -193 | -4 | -15 | -212 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx | TypeScript JSX | -241 | -68 | -72 | -381 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useFilters.tsx | TypeScript JSX | -89 | -12 | -16 | -117 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx | TypeScript JSX | 248 | 69 | 74 | 391 |
|
||||
| Total | | -358 | -15 | -33 | -406 |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
1
.VSCodeCounter/2025-03-17_16-24-17/results.json
Normal file
1
.VSCodeCounter/2025-03-17_16-24-17/results.json
Normal file
File diff suppressed because one or more lines are too long
31
.VSCodeCounter/2025-03-17_16-24-17/results.md
Normal file
31
.VSCodeCounter/2025-03-17_16-24-17/results.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Summary
|
||||
|
||||
Date : 2025-03-17 16:24:17
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 26 files, 6193 codes, 1008 comments, 1017 blanks, all 8218 lines
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| TypeScript JSX | 18 | 5,817 | 895 | 934 | 7,646 |
|
||||
| TypeScript | 6 | 309 | 106 | 55 | 470 |
|
||||
| Markdown | 1 | 39 | 0 | 19 | 58 |
|
||||
| JavaScript | 1 | 28 | 7 | 9 | 44 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 26 | 6,193 | 1,008 | 1,017 | 8,218 |
|
||||
| . (Files) | 3 | 63 | 6 | 22 | 91 |
|
||||
| components | 11 | 3,357 | 403 | 410 | 4,170 |
|
||||
| components (Files) | 6 | 2,124 | 245 | 252 | 2,621 |
|
||||
| components/cells | 5 | 1,233 | 158 | 158 | 1,549 |
|
||||
| hooks | 6 | 2,440 | 486 | 522 | 3,448 |
|
||||
| types | 1 | 16 | 4 | 4 | 24 |
|
||||
| utils | 5 | 317 | 109 | 59 | 485 |
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
60
.VSCodeCounter/2025-03-17_16-24-17/results.txt
Normal file
60
.VSCodeCounter/2025-03-17_16-24-17/results.txt
Normal file
@@ -0,0 +1,60 @@
|
||||
Date : 2025-03-17 16:24:17
|
||||
Directory : /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
Total : 26 files, 6193 codes, 1008 comments, 1017 blanks, all 8218 lines
|
||||
|
||||
Languages
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| TypeScript JSX | 18 | 5,817 | 895 | 934 | 7,646 |
|
||||
| TypeScript | 6 | 309 | 106 | 55 | 470 |
|
||||
| Markdown | 1 | 39 | 0 | 19 | 58 |
|
||||
| JavaScript | 1 | 28 | 7 | 9 | 44 |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 26 | 6,193 | 1,008 | 1,017 | 8,218 |
|
||||
| . (Files) | 3 | 63 | 6 | 22 | 91 |
|
||||
| components | 11 | 3,357 | 403 | 410 | 4,170 |
|
||||
| components (Files) | 6 | 2,124 | 245 | 252 | 2,621 |
|
||||
| components/cells | 5 | 1,233 | 158 | 158 | 1,549 |
|
||||
| hooks | 6 | 2,440 | 486 | 522 | 3,448 |
|
||||
| types | 1 | 16 | 4 | 4 | 24 |
|
||||
| utils | 5 | 317 | 109 | 59 | 485 |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md | Markdown | 39 | 0 | 19 | 58 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx | TypeScript JSX | 230 | 10 | 8 | 248 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx | TypeScript JSX | 18 | 0 | 3 | 21 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx | TypeScript JSX | 273 | 19 | 37 | 329 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx | TypeScript JSX | 374 | 42 | 44 | 460 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx | TypeScript JSX | 730 | 126 | 106 | 962 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx | TypeScript JSX | 499 | 48 | 54 | 601 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx | TypeScript JSX | 112 | 12 | 21 | 145 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx | TypeScript JSX | 232 | 31 | 32 | 295 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx | TypeScript JSX | 407 | 56 | 52 | 515 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx | TypeScript JSX | 193 | 23 | 22 | 238 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx | TypeScript JSX | 289 | 36 | 31 | 356 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx | TypeScript JSX | 500 | 75 | 89 | 664 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx | TypeScript JSX | 248 | 69 | 74 | 391 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx | TypeScript JSX | 204 | 26 | 33 | 263 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx | TypeScript JSX | 209 | 49 | 50 | 308 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx | TypeScript JSX | 219 | 39 | 47 | 305 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx | TypeScript JSX | 1,060 | 228 | 229 | 1,517 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx | TypeScript JSX | 20 | 6 | 2 | 28 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts | TypeScript | 4 | 0 | 1 | 5 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts | TypeScript | 16 | 4 | 4 | 24 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts | TypeScript | 124 | 4 | 14 | 142 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts | TypeScript | 21 | 15 | 5 | 41 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts | TypeScript | 43 | 24 | 7 | 74 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js | JavaScript | 28 | 7 | 9 | 44 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts | TypeScript | 101 | 59 | 24 | 184 |
|
||||
| Total | | 6,193 | 1,008 | 1,017 | 8,218 |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
42
.VSCodeCounter/2025-03-18_12-39-04/details.md
Normal file
42
.VSCodeCounter/2025-03-18_12-39-04/details.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Details
|
||||
|
||||
Date : 2025-03-18 12:39:04
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 27 files, 6925 codes, 1247 comments, 1248 blanks, all 9420 lines
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md) | Markdown | 39 | 0 | 19 | 58 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx) | TypeScript JSX | 230 | 10 | 8 | 248 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx) | TypeScript JSX | 18 | 0 | 3 | 21 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx) | TypeScript JSX | 273 | 19 | 37 | 329 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/UpcValidationTableAdapter.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/UpcValidationTableAdapter.tsx) | TypeScript JSX | 113 | 17 | 10 | 140 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx) | TypeScript JSX | 377 | 49 | 54 | 480 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx) | TypeScript JSX | 969 | 182 | 158 | 1,309 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx) | TypeScript JSX | 509 | 50 | 57 | 616 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx) | TypeScript JSX | 112 | 12 | 21 | 145 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx) | TypeScript JSX | 233 | 34 | 33 | 300 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx) | TypeScript JSX | 420 | 66 | 59 | 545 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx) | TypeScript JSX | 193 | 23 | 22 | 238 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx) | TypeScript JSX | 227 | 36 | 32 | 295 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx) | TypeScript JSX | 500 | 75 | 89 | 664 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx) | TypeScript JSX | 264 | 75 | 81 | 420 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx) | TypeScript JSX | 204 | 26 | 33 | 263 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx) | TypeScript JSX | 337 | 88 | 92 | 517 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx) | TypeScript JSX | 360 | 78 | 85 | 523 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx) | TypeScript JSX | 1,190 | 288 | 289 | 1,767 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx) | TypeScript JSX | 20 | 6 | 2 | 28 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts) | TypeScript | 4 | 0 | 1 | 5 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts) | TypeScript | 16 | 4 | 4 | 24 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts) | TypeScript | 124 | 4 | 14 | 142 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts) | TypeScript | 21 | 15 | 5 | 41 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts) | TypeScript | 43 | 24 | 7 | 74 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js) | JavaScript | 28 | 7 | 9 | 44 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts) | TypeScript | 101 | 59 | 24 | 184 |
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
26
.VSCodeCounter/2025-03-18_12-39-04/diff-details.md
Normal file
26
.VSCodeCounter/2025-03-18_12-39-04/diff-details.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Diff Details
|
||||
|
||||
Date : 2025-03-18 12:39:04
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 11 files, 732 codes, 239 comments, 231 blanks, all 1202 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/UpcValidationTableAdapter.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/UpcValidationTableAdapter.tsx) | TypeScript JSX | 113 | 17 | 10 | 140 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx) | TypeScript JSX | 3 | 7 | 10 | 20 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx) | TypeScript JSX | 239 | 56 | 52 | 347 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx) | TypeScript JSX | 10 | 2 | 3 | 15 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx) | TypeScript JSX | 1 | 3 | 1 | 5 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx) | TypeScript JSX | 13 | 10 | 7 | 30 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx) | TypeScript JSX | -62 | 0 | 1 | -61 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx) | TypeScript JSX | 16 | 6 | 7 | 29 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx) | TypeScript JSX | 128 | 39 | 42 | 209 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx) | TypeScript JSX | 141 | 39 | 38 | 218 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx) | TypeScript JSX | 130 | 60 | 60 | 250 |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
25
.VSCodeCounter/2025-03-18_12-39-04/diff.md
Normal file
25
.VSCodeCounter/2025-03-18_12-39-04/diff.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Diff Summary
|
||||
|
||||
Date : 2025-03-18 12:39:04
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 11 files, 732 codes, 239 comments, 231 blanks, all 1202 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| TypeScript JSX | 11 | 732 | 239 | 231 | 1,202 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 11 | 732 | 239 | 231 | 1,202 |
|
||||
| components | 7 | 317 | 95 | 84 | 496 |
|
||||
| components (Files) | 4 | 365 | 82 | 75 | 522 |
|
||||
| components/cells | 3 | -48 | 13 | 9 | -26 |
|
||||
| hooks | 4 | 415 | 144 | 147 | 706 |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
39
.VSCodeCounter/2025-03-18_12-39-04/diff.txt
Normal file
39
.VSCodeCounter/2025-03-18_12-39-04/diff.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
Date : 2025-03-18 12:39:04
|
||||
Directory : /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
Total : 11 files, 732 codes, 239 comments, 231 blanks, all 1202 lines
|
||||
|
||||
Languages
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| TypeScript JSX | 11 | 732 | 239 | 231 | 1,202 |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 11 | 732 | 239 | 231 | 1,202 |
|
||||
| components | 7 | 317 | 95 | 84 | 496 |
|
||||
| components (Files) | 4 | 365 | 82 | 75 | 522 |
|
||||
| components/cells | 3 | -48 | 13 | 9 | -26 |
|
||||
| hooks | 4 | 415 | 144 | 147 | 706 |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/UpcValidationTableAdapter.tsx | TypeScript JSX | 113 | 17 | 10 | 140 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx | TypeScript JSX | 3 | 7 | 10 | 20 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx | TypeScript JSX | 239 | 56 | 52 | 347 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx | TypeScript JSX | 10 | 2 | 3 | 15 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx | TypeScript JSX | 1 | 3 | 1 | 5 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx | TypeScript JSX | 13 | 10 | 7 | 30 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx | TypeScript JSX | -62 | 0 | 1 | -61 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx | TypeScript JSX | 16 | 6 | 7 | 29 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx | TypeScript JSX | 128 | 39 | 42 | 209 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx | TypeScript JSX | 141 | 39 | 38 | 218 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx | TypeScript JSX | 130 | 60 | 60 | 250 |
|
||||
| Total | | 732 | 239 | 231 | 1,202 |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
1
.VSCodeCounter/2025-03-18_12-39-04/results.json
Normal file
1
.VSCodeCounter/2025-03-18_12-39-04/results.json
Normal file
File diff suppressed because one or more lines are too long
31
.VSCodeCounter/2025-03-18_12-39-04/results.md
Normal file
31
.VSCodeCounter/2025-03-18_12-39-04/results.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Summary
|
||||
|
||||
Date : 2025-03-18 12:39:04
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 27 files, 6925 codes, 1247 comments, 1248 blanks, all 9420 lines
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| TypeScript JSX | 19 | 6,549 | 1,134 | 1,165 | 8,848 |
|
||||
| TypeScript | 6 | 309 | 106 | 55 | 470 |
|
||||
| Markdown | 1 | 39 | 0 | 19 | 58 |
|
||||
| JavaScript | 1 | 28 | 7 | 9 | 44 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 27 | 6,925 | 1,247 | 1,248 | 9,420 |
|
||||
| . (Files) | 3 | 63 | 6 | 22 | 91 |
|
||||
| components | 12 | 3,674 | 498 | 494 | 4,666 |
|
||||
| components (Files) | 7 | 2,489 | 327 | 327 | 3,143 |
|
||||
| components/cells | 5 | 1,185 | 171 | 167 | 1,523 |
|
||||
| hooks | 6 | 2,855 | 630 | 669 | 4,154 |
|
||||
| types | 1 | 16 | 4 | 4 | 24 |
|
||||
| utils | 5 | 317 | 109 | 59 | 485 |
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
61
.VSCodeCounter/2025-03-18_12-39-04/results.txt
Normal file
61
.VSCodeCounter/2025-03-18_12-39-04/results.txt
Normal file
@@ -0,0 +1,61 @@
|
||||
Date : 2025-03-18 12:39:04
|
||||
Directory : /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
Total : 27 files, 6925 codes, 1247 comments, 1248 blanks, all 9420 lines
|
||||
|
||||
Languages
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| TypeScript JSX | 19 | 6,549 | 1,134 | 1,165 | 8,848 |
|
||||
| TypeScript | 6 | 309 | 106 | 55 | 470 |
|
||||
| Markdown | 1 | 39 | 0 | 19 | 58 |
|
||||
| JavaScript | 1 | 28 | 7 | 9 | 44 |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 27 | 6,925 | 1,247 | 1,248 | 9,420 |
|
||||
| . (Files) | 3 | 63 | 6 | 22 | 91 |
|
||||
| components | 12 | 3,674 | 498 | 494 | 4,666 |
|
||||
| components (Files) | 7 | 2,489 | 327 | 327 | 3,143 |
|
||||
| components/cells | 5 | 1,185 | 171 | 167 | 1,523 |
|
||||
| hooks | 6 | 2,855 | 630 | 669 | 4,154 |
|
||||
| types | 1 | 16 | 4 | 4 | 24 |
|
||||
| utils | 5 | 317 | 109 | 59 | 485 |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md | Markdown | 39 | 0 | 19 | 58 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx | TypeScript JSX | 230 | 10 | 8 | 248 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx | TypeScript JSX | 18 | 0 | 3 | 21 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx | TypeScript JSX | 273 | 19 | 37 | 329 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/UpcValidationTableAdapter.tsx | TypeScript JSX | 113 | 17 | 10 | 140 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx | TypeScript JSX | 377 | 49 | 54 | 480 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx | TypeScript JSX | 969 | 182 | 158 | 1,309 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx | TypeScript JSX | 509 | 50 | 57 | 616 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx | TypeScript JSX | 112 | 12 | 21 | 145 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx | TypeScript JSX | 233 | 34 | 33 | 300 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx | TypeScript JSX | 420 | 66 | 59 | 545 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx | TypeScript JSX | 193 | 23 | 22 | 238 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx | TypeScript JSX | 227 | 36 | 32 | 295 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx | TypeScript JSX | 500 | 75 | 89 | 664 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx | TypeScript JSX | 264 | 75 | 81 | 420 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx | TypeScript JSX | 204 | 26 | 33 | 263 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx | TypeScript JSX | 337 | 88 | 92 | 517 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx | TypeScript JSX | 360 | 78 | 85 | 523 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx | TypeScript JSX | 1,190 | 288 | 289 | 1,767 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx | TypeScript JSX | 20 | 6 | 2 | 28 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts | TypeScript | 4 | 0 | 1 | 5 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts | TypeScript | 16 | 4 | 4 | 24 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts | TypeScript | 124 | 4 | 14 | 142 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts | TypeScript | 21 | 15 | 5 | 41 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts | TypeScript | 43 | 24 | 7 | 74 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js | JavaScript | 28 | 7 | 9 | 44 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts | TypeScript | 101 | 59 | 24 | 184 |
|
||||
| Total | | 6,925 | 1,247 | 1,248 | 9,420 |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
42
.VSCodeCounter/2025-03-18_13-49-23/details.md
Normal file
42
.VSCodeCounter/2025-03-18_13-49-23/details.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Details
|
||||
|
||||
Date : 2025-03-18 13:49:23
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 27 files, 6961 codes, 1254 comments, 1252 blanks, all 9467 lines
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md) | Markdown | 39 | 0 | 19 | 58 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx) | TypeScript JSX | 230 | 10 | 8 | 248 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx) | TypeScript JSX | 18 | 0 | 3 | 21 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx) | TypeScript JSX | 273 | 19 | 37 | 329 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/UpcValidationTableAdapter.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/UpcValidationTableAdapter.tsx) | TypeScript JSX | 113 | 17 | 10 | 140 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx) | TypeScript JSX | 395 | 51 | 55 | 501 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx) | TypeScript JSX | 969 | 182 | 158 | 1,309 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx) | TypeScript JSX | 527 | 55 | 60 | 642 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx) | TypeScript JSX | 112 | 12 | 21 | 145 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx) | TypeScript JSX | 233 | 34 | 33 | 300 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx) | TypeScript JSX | 420 | 66 | 59 | 545 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx) | TypeScript JSX | 193 | 23 | 22 | 238 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx) | TypeScript JSX | 227 | 36 | 32 | 295 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx) | TypeScript JSX | 500 | 75 | 89 | 664 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx) | TypeScript JSX | 264 | 75 | 81 | 420 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx) | TypeScript JSX | 204 | 26 | 33 | 263 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx) | TypeScript JSX | 337 | 88 | 92 | 517 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx) | TypeScript JSX | 360 | 78 | 85 | 523 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx) | TypeScript JSX | 1,190 | 288 | 289 | 1,767 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx) | TypeScript JSX | 20 | 6 | 2 | 28 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts) | TypeScript | 4 | 0 | 1 | 5 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts) | TypeScript | 16 | 4 | 4 | 24 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts) | TypeScript | 124 | 4 | 14 | 142 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts) | TypeScript | 21 | 15 | 5 | 41 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts) | TypeScript | 43 | 24 | 7 | 74 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js) | JavaScript | 28 | 7 | 9 | 44 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts) | TypeScript | 101 | 59 | 24 | 184 |
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
17
.VSCodeCounter/2025-03-18_13-49-23/diff-details.md
Normal file
17
.VSCodeCounter/2025-03-18_13-49-23/diff-details.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Diff Details
|
||||
|
||||
Date : 2025-03-18 13:49:23
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 2 files, 36 codes, 7 comments, 4 blanks, all 47 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx) | TypeScript JSX | 18 | 2 | 1 | 21 |
|
||||
| [inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx](/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx) | TypeScript JSX | 18 | 5 | 3 | 26 |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
22
.VSCodeCounter/2025-03-18_13-49-23/diff.md
Normal file
22
.VSCodeCounter/2025-03-18_13-49-23/diff.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Diff Summary
|
||||
|
||||
Date : 2025-03-18 13:49:23
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 2 files, 36 codes, 7 comments, 4 blanks, all 47 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| TypeScript JSX | 2 | 36 | 7 | 4 | 47 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 2 | 36 | 7 | 4 | 47 |
|
||||
| components | 2 | 36 | 7 | 4 | 47 |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
27
.VSCodeCounter/2025-03-18_13-49-23/diff.txt
Normal file
27
.VSCodeCounter/2025-03-18_13-49-23/diff.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
Date : 2025-03-18 13:49:23
|
||||
Directory : /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
Total : 2 files, 36 codes, 7 comments, 4 blanks, all 47 lines
|
||||
|
||||
Languages
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| TypeScript JSX | 2 | 36 | 7 | 4 | 47 |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+---------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+---------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 2 | 36 | 7 | 4 | 47 |
|
||||
| components | 2 | 36 | 7 | 4 | 47 |
|
||||
+---------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+---------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+---------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx | TypeScript JSX | 18 | 2 | 1 | 21 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx | TypeScript JSX | 18 | 5 | 3 | 26 |
|
||||
| Total | | 36 | 7 | 4 | 47 |
|
||||
+---------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
1
.VSCodeCounter/2025-03-18_13-49-23/results.json
Normal file
1
.VSCodeCounter/2025-03-18_13-49-23/results.json
Normal file
File diff suppressed because one or more lines are too long
31
.VSCodeCounter/2025-03-18_13-49-23/results.md
Normal file
31
.VSCodeCounter/2025-03-18_13-49-23/results.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Summary
|
||||
|
||||
Date : 2025-03-18 13:49:23
|
||||
|
||||
Directory /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
|
||||
Total : 27 files, 6961 codes, 1254 comments, 1252 blanks, all 9467 lines
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| TypeScript JSX | 19 | 6,585 | 1,141 | 1,169 | 8,895 |
|
||||
| TypeScript | 6 | 309 | 106 | 55 | 470 |
|
||||
| Markdown | 1 | 39 | 0 | 19 | 58 |
|
||||
| JavaScript | 1 | 28 | 7 | 9 | 44 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 27 | 6,961 | 1,254 | 1,252 | 9,467 |
|
||||
| . (Files) | 3 | 63 | 6 | 22 | 91 |
|
||||
| components | 12 | 3,710 | 505 | 498 | 4,713 |
|
||||
| components (Files) | 7 | 2,525 | 334 | 331 | 3,190 |
|
||||
| components/cells | 5 | 1,185 | 171 | 167 | 1,523 |
|
||||
| hooks | 6 | 2,855 | 630 | 669 | 4,154 |
|
||||
| types | 1 | 16 | 4 | 4 | 24 |
|
||||
| utils | 5 | 317 | 109 | 59 | 485 |
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
61
.VSCodeCounter/2025-03-18_13-49-23/results.txt
Normal file
61
.VSCodeCounter/2025-03-18_13-49-23/results.txt
Normal file
@@ -0,0 +1,61 @@
|
||||
Date : 2025-03-18 13:49:23
|
||||
Directory : /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew
|
||||
Total : 27 files, 6961 codes, 1254 comments, 1252 blanks, all 9467 lines
|
||||
|
||||
Languages
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
| TypeScript JSX | 19 | 6,585 | 1,141 | 1,169 | 8,895 |
|
||||
| TypeScript | 6 | 309 | 106 | 55 | 470 |
|
||||
| Markdown | 1 | 39 | 0 | 19 | 58 |
|
||||
| JavaScript | 1 | 28 | 7 | 9 | 44 |
|
||||
+----------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 27 | 6,961 | 1,254 | 1,252 | 9,467 |
|
||||
| . (Files) | 3 | 63 | 6 | 22 | 91 |
|
||||
| components | 12 | 3,710 | 505 | 498 | 4,713 |
|
||||
| components (Files) | 7 | 2,525 | 334 | 331 | 3,190 |
|
||||
| components/cells | 5 | 1,185 | 171 | 167 | 1,523 |
|
||||
| hooks | 6 | 2,855 | 630 | 669 | 4,154 |
|
||||
| types | 1 | 16 | 4 | 4 | 24 |
|
||||
| utils | 5 | 317 | 109 | 59 | 485 |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/README.md | Markdown | 39 | 0 | 19 | 58 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/AiValidationDialogs.tsx | TypeScript JSX | 230 | 10 | 8 | 248 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/BaseCellContent.tsx | TypeScript JSX | 18 | 0 | 3 | 21 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx | TypeScript JSX | 273 | 19 | 37 | 329 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/UpcValidationTableAdapter.tsx | TypeScript JSX | 113 | 17 | 10 | 140 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx | TypeScript JSX | 395 | 51 | 55 | 501 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx | TypeScript JSX | 969 | 182 | 158 | 1,309 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx | TypeScript JSX | 527 | 55 | 60 | 642 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/CheckboxCell.tsx | TypeScript JSX | 112 | 12 | 21 | 145 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx | TypeScript JSX | 233 | 34 | 33 | 300 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultiSelectCell.tsx | TypeScript JSX | 420 | 66 | 59 | 545 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/MultilineInput.tsx | TypeScript JSX | 193 | 23 | 22 | 238 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/SelectCell.tsx | TypeScript JSX | 227 | 36 | 32 | 295 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useAiValidation.tsx | TypeScript JSX | 500 | 75 | 89 | 664 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useProductLinesFetching.tsx | TypeScript JSX | 264 | 75 | 81 | 420 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useTemplates.tsx | TypeScript JSX | 204 | 26 | 33 | 263 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useUpcValidation.tsx | TypeScript JSX | 337 | 88 | 92 | 517 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidation.tsx | TypeScript JSX | 360 | 78 | 85 | 523 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx | TypeScript JSX | 1,190 | 288 | 289 | 1,767 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/index.tsx | TypeScript JSX | 20 | 6 | 2 | 28 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types.ts | TypeScript | 4 | 0 | 1 | 5 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/types/index.ts | TypeScript | 16 | 4 | 4 | 24 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/dataMutations.ts | TypeScript | 124 | 4 | 14 | 142 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/errorUtils.ts | TypeScript | 21 | 15 | 5 | 41 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/upcValidation.ts | TypeScript | 43 | 24 | 7 | 74 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validation-helper.js | JavaScript | 28 | 7 | 9 | 44 |
|
||||
| /Users/matt/Dev/inventory/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/utils/validationUtils.ts | TypeScript | 101 | 59 | 24 | 184 |
|
||||
| Total | | 6,961 | 1,254 | 1,252 | 9,467 |
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------+----------------+------------+------------+------------+------------+
|
||||
354
docs/validation-process-issues.md
Normal file
354
docs/validation-process-issues.md
Normal file
@@ -0,0 +1,354 @@
|
||||
## 1. ✅ Error Filtering Logic Inconsistency (RESOLVED)
|
||||
|
||||
> **Note: This issue has been resolved by implementing a type-based error system.**
|
||||
|
||||
The filtering logic in `ValidationCell.tsx` previously relied on string matching, which was fragile:
|
||||
|
||||
```typescript
|
||||
// Old implementation (string-based matching)
|
||||
const filteredErrors = React.useMemo(() => {
|
||||
return !isEmpty(value)
|
||||
? errors.filter(error => !error.message?.toLowerCase().includes('required'))
|
||||
: errors;
|
||||
}, [value, errors]);
|
||||
|
||||
// New implementation (type-based filtering)
|
||||
const filteredErrors = React.useMemo(() => {
|
||||
return !isEmpty(value)
|
||||
? errors.filter(error => error.type !== ErrorType.Required)
|
||||
: errors;
|
||||
}, [value, errors]);
|
||||
```
|
||||
|
||||
The solution implemented:
|
||||
- Added an `ErrorType` enum in `types.ts` to standardize error categorization
|
||||
- Updated all error creation to include the appropriate error type
|
||||
- Modified error filtering to use the type property instead of string matching
|
||||
- Ensured consistent error handling across the application
|
||||
|
||||
**Guidelines for future development:**
|
||||
- Always use the `ErrorType` enum when creating errors
|
||||
- Never rely on string matching for error filtering
|
||||
- Ensure all error objects include the `type` property
|
||||
- Use the appropriate error type for each validation rule:
|
||||
- `ErrorType.Required` for required field validations
|
||||
- `ErrorType.Regex` for regex validations
|
||||
- `ErrorType.Unique` for uniqueness validations
|
||||
- `ErrorType.Custom` for custom validations
|
||||
- `ErrorType.Api` for API-based validations
|
||||
|
||||
## 2. ⚠️ Redundant Error Processing (PARTIALLY RESOLVED)
|
||||
|
||||
> **Note: This issue has been partially resolved by the re-rendering optimizations.**
|
||||
|
||||
The system still processes errors in multiple places:
|
||||
- In `ValidationCell.tsx`, errors are filtered by the optimized `processErrors` function
|
||||
- In `useValidation.tsx`, errors are generated at the field level
|
||||
- In `ValidationContainer.tsx`, errors are manipulated at the container level
|
||||
|
||||
While the error processing has been optimized to be more efficient, there is still some redundancy in how errors are handled across components. However, the current implementation has mitigated the performance impact.
|
||||
|
||||
**Improvements made:**
|
||||
- Created a central `processErrors` function in ValidationCell that efficiently handles error filtering
|
||||
- Implemented a batched update system to reduce redundant error processing
|
||||
- Added better memoization to avoid reprocessing errors when not needed
|
||||
|
||||
**Future improvement opportunities:**
|
||||
- Further consolidate error processing logic into a single location
|
||||
- Create a dedicated error handling service or hook
|
||||
- Implement a more declarative approach to error handling
|
||||
|
||||
## 3. Race Conditions in Async Validation
|
||||
|
||||
async validations could create race conditions:
|
||||
- If a user types quickly, multiple validation requests might be in flight
|
||||
- Later responses could overwrite more recent ones if they complete out of order
|
||||
- The debouncing helps but doesn't fully solve this issue
|
||||
|
||||
## 4. Memory Leaks in Timeout Management
|
||||
|
||||
The validation timeouts are stored in refs:
|
||||
```typescript
|
||||
const validationTimeoutsRef = useRef<Record<number, NodeJS.Timeout>>({});
|
||||
```
|
||||
|
||||
While there is cleanup on unmount, if rows are added/removed dynamically, timeouts for deleted rows might not be properly cleared.
|
||||
|
||||
## 5. ✅ Inefficient Error Storage (RESOLVED)
|
||||
|
||||
**Status: RESOLVED**
|
||||
|
||||
### Problem
|
||||
|
||||
Previously, validation errors were stored in multiple locations:
|
||||
- In the `validationErrors` Map in `useValidationState`
|
||||
- In the row data itself as `__errors`
|
||||
|
||||
This redundancy caused several issues:
|
||||
- Inconsistent error states between the two storage locations
|
||||
- Increased memory usage by storing the same information twice
|
||||
- Complex state management to keep both sources in sync
|
||||
- Difficulty reasoning about where errors should be accessed from
|
||||
|
||||
### Solution
|
||||
|
||||
We've implemented a unified error storage approach by:
|
||||
- Making the `validationErrors` Map in `useValidationState` the single source of truth for all validation errors
|
||||
- Removed the `__errors` property from row data
|
||||
- Updated all validation functions to interact with the central error store instead of modifying row data
|
||||
- Modified UPC validation to use the central error store
|
||||
- Updated all components to read errors from the `validationErrors` Map instead of row data
|
||||
|
||||
### Key Changes
|
||||
|
||||
1. Modified `dataMutations.ts` to stop storing errors in row data
|
||||
2. Updated the `Meta` type to remove the `__errors` property
|
||||
3. Modified the `RowData` type to remove the `__errors` property
|
||||
4. Updated the `useValidation` hook to return errors separately from row data
|
||||
5. Modified the `useAiValidation` hook to work with the central error store
|
||||
6. Updated the `useFilters` hook to check for errors in the `validationErrors` Map
|
||||
7. Modified the `ValidationTable` and `ValidationCell` components to read errors from the `validationErrors` Map
|
||||
|
||||
### Benefits
|
||||
|
||||
- **Single Source of Truth**: All validation errors are now stored in one place
|
||||
- **Reduced Memory Usage**: No duplicate storage of error information
|
||||
- **Simplified State Management**: Only one state to update when errors change
|
||||
- **Cleaner Data Structure**: Row data no longer contains validation metadata
|
||||
- **More Maintainable Code**: Clearer separation of concerns between data and validation
|
||||
|
||||
### Future Improvements
|
||||
|
||||
While this refactoring addresses the core issue of inefficient error storage, there are still opportunities for further optimization:
|
||||
|
||||
1. ✅ **Redundant Error Processing**: ~~The validation process still performs some redundant calculations that could be optimized.~~ This has been largely addressed by the re-rendering optimizations.
|
||||
2. **Race Conditions**: Async validation can lead to race conditions when multiple validations are triggered in quick succession.
|
||||
3. **Memory Leaks**: The timeout management for validation could be improved to prevent potential memory leaks.
|
||||
4. **Tight Coupling**: Components are still tightly coupled to the validation state structure.
|
||||
5. **Error Prioritization**: The system doesn't prioritize errors well, showing all errors at once rather than focusing on the most critical ones first.
|
||||
|
||||
### Validation Flow
|
||||
|
||||
The validation process now works as follows:
|
||||
|
||||
1. **Error Generation**:
|
||||
- Field-level validations generate errors based on validation rules
|
||||
- Row-level hooks add custom validation errors
|
||||
- Table-level validations (like uniqueness checks) add errors across rows
|
||||
|
||||
2. **Error Storage**:
|
||||
- All errors are stored in the `validationErrors` Map in `useValidationState`
|
||||
- The Map uses row indices as keys and objects of field errors as values
|
||||
|
||||
3. **Error Display**:
|
||||
- The `ValidationTable` component checks the `validationErrors` Map to highlight rows with errors
|
||||
- The `ValidationCell` component receives errors for specific fields from the `validationErrors` Map
|
||||
- Errors are filtered in the UI to avoid showing "required" errors for fields with values
|
||||
|
||||
This focused refactoring approach has successfully addressed a critical issue while keeping changes manageable and targeted.
|
||||
|
||||
## 6. ✅ Excessive Re-rendering (RESOLVED)
|
||||
|
||||
**Status: RESOLVED**
|
||||
|
||||
### Problem
|
||||
|
||||
The validation system was suffering from excessive re-renders due to several key issues:
|
||||
|
||||
- **Inefficient Error Filtering**: The ValidationCell component was filtering errors on every render
|
||||
- **Redundant Error Processing**: The same validation work was repeated in multiple components
|
||||
- **Poor Memoization**: Components were inadequately memoized, causing unnecessary re-renders
|
||||
- **Inefficient Batch Updates**: The state update system wasn't optimally batching changes
|
||||
|
||||
These issues led to performance problems, especially with large datasets, and affected the user experience.
|
||||
|
||||
### Solution
|
||||
|
||||
We've implemented a comprehensive optimization approach:
|
||||
|
||||
- **Optimized Error Processing**: Created an efficient `processErrors` function in ValidationCell that calculates all derived state in one pass
|
||||
- **Enhanced Memoization**: Improved memo comparison functions to avoid unnecessary rerenders
|
||||
- **Improved Batch Updates**: Redesigned the batching system to aggregate multiple changes before state updates
|
||||
- **Single Update Pattern**: Implemented a queue-based update mechanism that applies multiple state changes at once
|
||||
|
||||
### Key Changes
|
||||
|
||||
1. Added a more efficient error processing function in ValidationCell
|
||||
2. Created an enhanced error comparison function to properly compare error arrays
|
||||
3. Improved the memo comparison function in ValidationCell
|
||||
4. Added a batch update system in useValidationState
|
||||
5. Implemented a queue-based update mechanism for row modifications
|
||||
|
||||
### Benefits
|
||||
|
||||
- **Improved Performance**: Reduced render cycles = faster UI response
|
||||
- **Better User Experience**: Less lag when editing large datasets
|
||||
- **Reduced Memory Usage**: Fewer component instantiations and temporary objects
|
||||
- **Increased Scalability**: The application can now handle larger datasets without slowdown
|
||||
- **Maintainable Code**: More predictable update flow that's easier to debug and extend
|
||||
|
||||
### Guidelines for future development
|
||||
|
||||
- Use the `processErrors` function for error filtering and processing
|
||||
- Ensure React.memo components have proper comparison functions
|
||||
- Use the batched update system for state changes
|
||||
- Maintain stable references to objects and functions
|
||||
- Use appropriate React hooks (useMemo, useCallback) with correct dependencies
|
||||
- Avoid unnecessary recreations of arrays, objects, and functions
|
||||
|
||||
## 7. Complex Error Merging Logic
|
||||
|
||||
When merging errors from different sources, the logic is complex and potentially error-prone:
|
||||
```typescript
|
||||
// Merge field errors and row hook errors
|
||||
const mergedErrors: Record<string, InfoWithSource> = {}
|
||||
|
||||
// Convert field errors to InfoWithSource
|
||||
Object.entries(fieldErrors).forEach(([key, errors]) => {
|
||||
if (errors.length > 0) {
|
||||
mergedErrors[key] = {
|
||||
message: errors[0].message,
|
||||
level: errors[0].level,
|
||||
source: ErrorSources.Row,
|
||||
type: errors[0].type || ErrorType.Custom
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
This only takes the first error for each field, potentially hiding important validation issues.
|
||||
|
||||
## 8. ✅ Inconsistent Error Handling for Empty Values (PARTIALLY RESOLVED)
|
||||
|
||||
> **Note: This issue has been partially resolved by standardizing the isEmpty function and error type system.**
|
||||
|
||||
The system previously had different approaches to handling empty values:
|
||||
- Some validations skipped empty values unless they're required
|
||||
- Others processed empty values differently
|
||||
- The `isEmpty` function was defined multiple times with slight variations
|
||||
|
||||
The solution implemented:
|
||||
- Standardized the `isEmpty` function implementation
|
||||
- Ensured consistent error type usage for required field validations
|
||||
- Made error filtering consistent across the application
|
||||
|
||||
**Guidelines for future development:**
|
||||
- Always use the shared `isEmpty` function for checking empty values
|
||||
- Ensure consistent handling of empty values across all validation rules
|
||||
- Use the `ErrorType.Required` type for all required field validations
|
||||
|
||||
## 9. Tight Coupling Between Components
|
||||
|
||||
The validation system is tightly coupled across components:
|
||||
- `ValidationCell` needs to understand the structure of errors
|
||||
- `ValidationTable` needs to extract and pass the right errors
|
||||
- `ValidationContainer` directly manipulates the error structure
|
||||
|
||||
This makes it harder to refactor or reuse components independently.
|
||||
|
||||
## 10. Limited Error Prioritization
|
||||
|
||||
There's no clear prioritization of errors:
|
||||
- When multiple errors exist for a field, which one should be shown first?
|
||||
- Are some errors more important than others?
|
||||
- The current system mostly shows the first error it finds
|
||||
|
||||
A more robust approach would be to have a consistent error source identification system and a clear prioritization strategy for displaying errors.
|
||||
|
||||
------------
|
||||
|
||||
Let me explain how these hooks fit together to create the validation errors that eventually get filtered in the `ValidationCell` component:
|
||||
|
||||
## The Validation Flow
|
||||
|
||||
1. **useValidationState Hook**:
|
||||
This is the main state management hook used by the `ValidationContainer` component. It:
|
||||
- Manages the core data state (`data`)
|
||||
- Tracks validation errors in a Map (`validationErrors`)
|
||||
- Provides functions to update and validate rows
|
||||
|
||||
2. **useValidation Hook**:
|
||||
This is a utility hook that provides the core validation logic:
|
||||
- `validateField`: Validates a single field against its validation rules
|
||||
- `validateRow`: Validates an entire row, field by field
|
||||
- `validateTable`: Runs table-level validations
|
||||
- `validateUnique`: Checks for uniqueness constraints
|
||||
- `validateData`: Orchestrates the complete validation process
|
||||
|
||||
## How Errors Are Generated
|
||||
|
||||
Validation errors come from multiple sources:
|
||||
|
||||
1. **Field-Level Validations**:
|
||||
In `useValidation.tsx`, the `validateField` function checks individual fields against rules like:
|
||||
- `required`: Field must have a value
|
||||
- `regex`: Value must match a pattern
|
||||
- `min`/`max`: Numeric constraints
|
||||
|
||||
2. **Row-Level Validations**:
|
||||
The `validateRow` function in `useValidation.tsx` runs:
|
||||
- Field validations for each field in the row
|
||||
- Special validations for required fields like supplier and company
|
||||
- Custom row hooks provided by the application
|
||||
|
||||
3. **Table-Level Validations**:
|
||||
- `validateUnique` checks for duplicate values in fields marked as unique
|
||||
- `validateTable` runs custom table hooks for cross-row validations
|
||||
|
||||
4. **API-Based Validations**:
|
||||
In `useValidationState.tsx` and `ValidationContainer.tsx`:
|
||||
- UPC validation via API calls
|
||||
- Item number uniqueness checks
|
||||
|
||||
## The Error Flow
|
||||
|
||||
1. Errors are collected in the `validationErrors` Map in `useValidationState`
|
||||
2. This Map is passed to `ValidationTable` as a prop
|
||||
3. `ValidationTable` extracts the relevant errors for each cell and passes them to `ValidationCell`
|
||||
4. In `ValidationCell`, the errors are filtered based on whether the cell has a value:
|
||||
```typescript
|
||||
// Updated implementation using type-based filtering
|
||||
const filteredErrors = React.useMemo(() => {
|
||||
return !isEmpty(value)
|
||||
? errors.filter(error => error.type !== ErrorType.Required)
|
||||
: errors;
|
||||
}, [value, errors]);
|
||||
```
|
||||
|
||||
## Key Insights
|
||||
|
||||
1. **Error Structure**:
|
||||
Errors now have a consistent structure with type information:
|
||||
```typescript
|
||||
type ErrorObject = {
|
||||
message: string;
|
||||
level: string; // 'error', 'warning', etc.
|
||||
source?: ErrorSources; // Where the error came from
|
||||
type: ErrorType; // The type of error (Required, Regex, Unique, etc.)
|
||||
}
|
||||
```
|
||||
|
||||
2. **Error Sources**:
|
||||
Errors can come from:
|
||||
- Field validations (required, regex, etc.)
|
||||
- Row validations (custom business logic)
|
||||
- Table validations (uniqueness checks)
|
||||
- API validations (UPC checks)
|
||||
|
||||
3. **Error Types**:
|
||||
Errors are now categorized by type:
|
||||
- `ErrorType.Required`: Field is required but empty
|
||||
- `ErrorType.Regex`: Value doesn't match the regex pattern
|
||||
- `ErrorType.Unique`: Value must be unique across rows
|
||||
- `ErrorType.Custom`: Custom validation errors
|
||||
- `ErrorType.Api`: Errors from API calls
|
||||
|
||||
4. **Error Filtering**:
|
||||
The filtering in `ValidationCell` is now more robust:
|
||||
- When a field has a value, errors of type `ErrorType.Required` are filtered out
|
||||
- When a field is empty, all errors are shown
|
||||
|
||||
5. **Performance Optimizations**:
|
||||
- Batch processing of validations
|
||||
- Debounced updates to avoid excessive re-renders
|
||||
- Memoization of computed values
|
||||
@@ -1188,7 +1188,6 @@ export const MatchColumnsStep = React.memo(<T extends string>({
|
||||
})) as unknown as Fields<T>
|
||||
|
||||
const unmatched = findUnmatchedRequiredFields(typedFields, columns);
|
||||
console.log("Unmatched required fields:", unmatched);
|
||||
return unmatched;
|
||||
}, [fields, columns])
|
||||
|
||||
@@ -1200,7 +1199,6 @@ export const MatchColumnsStep = React.memo(<T extends string>({
|
||||
// Type assertion to handle the DeepReadonly<T> vs string type mismatch
|
||||
return !unmatchedRequiredFields.includes(key as any);
|
||||
});
|
||||
console.log("Matched required fields:", matched);
|
||||
return matched;
|
||||
}, [requiredFields, unmatchedRequiredFields]);
|
||||
|
||||
|
||||
@@ -185,12 +185,10 @@ export const UploadFlow = ({ state, onNext, onBack }: Props) => {
|
||||
|
||||
// Apply global selections to each row of data if they exist
|
||||
const dataWithGlobalSelections = globalSelections
|
||||
? dataWithMeta.map((row: Data<string> & { __errors?: any; __index?: string }) => {
|
||||
? dataWithMeta.map((row: Data<string> & { __index?: string }) => {
|
||||
const newRow = { ...row };
|
||||
if (globalSelections.supplier) newRow.supplier = globalSelections.supplier;
|
||||
if (globalSelections.company) newRow.company = globalSelections.company;
|
||||
if (globalSelections.line) newRow.line = globalSelections.line;
|
||||
if (globalSelections.subline) newRow.subline = globalSelections.subline;
|
||||
return newRow;
|
||||
})
|
||||
: dataWithMeta;
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog"
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
|
||||
interface SaveTemplateDialogProps {
|
||||
isOpen: boolean
|
||||
onClose: () => void
|
||||
onSave: (company: string, productType: string) => void
|
||||
}
|
||||
|
||||
const SaveTemplateDialog: React.FC<SaveTemplateDialogProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
onSave,
|
||||
}) => {
|
||||
const [company, setCompany] = useState("")
|
||||
const [productType, setProductType] = useState("")
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
onClose()
|
||||
setCompany("")
|
||||
setProductType("")
|
||||
}
|
||||
}}>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Save as Template</DialogTitle>
|
||||
<DialogDescription>
|
||||
Enter the company and product type for this template.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4 py-4">
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="company" className="text-sm font-medium">
|
||||
Company
|
||||
</label>
|
||||
<Input
|
||||
id="company"
|
||||
value={company}
|
||||
onChange={(e) => setCompany(e.target.value)}
|
||||
placeholder="Enter company name"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="productType" className="text-sm font-medium">
|
||||
Product Type
|
||||
</label>
|
||||
<Input
|
||||
id="productType"
|
||||
value={productType}
|
||||
onChange={(e) => setProductType(e.target.value)}
|
||||
placeholder="Enter product type"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onSave(company, productType)
|
||||
onClose()
|
||||
setCompany("")
|
||||
setProductType("")
|
||||
}}
|
||||
disabled={!company || !productType}
|
||||
>
|
||||
Save Template
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default SaveTemplateDialog
|
||||
@@ -1,212 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger
|
||||
} from '@/components/ui/popover'
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList
|
||||
} from '@/components/ui/command'
|
||||
import { ChevronsUpDown, Check } from 'lucide-react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Template } from '../hooks/useValidationState'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
interface TemplateManagerProps {
|
||||
templates: Template[]
|
||||
selectedTemplateId: string | null
|
||||
onSelectTemplate: (templateId: string | null) => void
|
||||
onSaveTemplate: (name: string, type: string) => void
|
||||
onApplyTemplate: (templateId: string) => void
|
||||
showDialog: boolean
|
||||
onCloseDialog: () => void
|
||||
selectedCount: number
|
||||
}
|
||||
|
||||
const TemplateManager: React.FC<TemplateManagerProps> = ({
|
||||
templates,
|
||||
selectedTemplateId,
|
||||
onSelectTemplate,
|
||||
onSaveTemplate,
|
||||
onApplyTemplate,
|
||||
showDialog,
|
||||
onCloseDialog,
|
||||
selectedCount,
|
||||
}) => {
|
||||
const [templateName, setTemplateName] = useState('')
|
||||
const [templateType, setTemplateType] = useState('')
|
||||
const [open, setOpen] = useState(false)
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
|
||||
// Filter templates based on search
|
||||
const filteredTemplates = searchQuery
|
||||
? templates.filter(template =>
|
||||
template.product_type.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
template.company.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
)
|
||||
: templates
|
||||
|
||||
const handleSaveTemplate = () => {
|
||||
if (!templateName.trim()) {
|
||||
toast.error('Please enter a template name')
|
||||
return
|
||||
}
|
||||
|
||||
if (!templateType.trim()) {
|
||||
toast.error('Please select a template type')
|
||||
return
|
||||
}
|
||||
|
||||
onSaveTemplate(templateName, templateType)
|
||||
setTemplateName('')
|
||||
setTemplateType('')
|
||||
}
|
||||
|
||||
// Get display text for template
|
||||
const getTemplateDisplayText = (template: Template) => {
|
||||
return `${template.product_type} - ${template.company}`
|
||||
}
|
||||
|
||||
// Find the currently selected template
|
||||
const selectedTemplate = templates.find(t => t.id.toString() === selectedTemplateId)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-col space-y-2">
|
||||
<label className="text-sm font-medium">Template</label>
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className="justify-between w-full"
|
||||
>
|
||||
{selectedTemplate
|
||||
? getTemplateDisplayText(selectedTemplate)
|
||||
: "Select a template"}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0 w-[350px]">
|
||||
<Command>
|
||||
<CommandInput
|
||||
placeholder="Search templates..."
|
||||
value={searchQuery}
|
||||
onValueChange={setSearchQuery}
|
||||
/>
|
||||
<CommandList>
|
||||
<CommandEmpty>No templates found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{filteredTemplates.map((template) => (
|
||||
<CommandItem
|
||||
key={template.id}
|
||||
value={template.id.toString()}
|
||||
onSelect={(value) => {
|
||||
onSelectTemplate(value)
|
||||
setOpen(false)
|
||||
setSearchQuery('')
|
||||
}}
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
selectedTemplateId === template.id.toString()
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{getTemplateDisplayText(template)}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<div className="flex space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => selectedTemplateId && onApplyTemplate(selectedTemplateId)}
|
||||
disabled={!selectedTemplateId || selectedCount === 0}
|
||||
className="flex-1"
|
||||
>
|
||||
Apply Template
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={onCloseDialog}
|
||||
disabled={selectedCount === 0}
|
||||
className="flex-1"
|
||||
>
|
||||
Save as Template
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Template Save Dialog */}
|
||||
<Dialog open={showDialog} onOpenChange={onCloseDialog}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Save Template</DialogTitle>
|
||||
<DialogDescription>
|
||||
Create a template from the selected row.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4 py-4">
|
||||
<div className="flex flex-col space-y-2">
|
||||
<label className="text-sm font-medium">Company</label>
|
||||
<Input
|
||||
value={templateName}
|
||||
onChange={(e) => setTemplateName(e.target.value)}
|
||||
placeholder="Enter company name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col space-y-2">
|
||||
<label className="text-sm font-medium">Product Type</label>
|
||||
<Input
|
||||
value={templateType}
|
||||
onChange={(e) => setTemplateType(e.target.value)}
|
||||
placeholder="Enter product type"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={onCloseDialog}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleSaveTemplate}
|
||||
disabled={!templateName.trim() || !templateType.trim()}
|
||||
>
|
||||
Save Template
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default TemplateManager
|
||||
@@ -0,0 +1,140 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import ValidationTable from './ValidationTable'
|
||||
import { RowSelectionState } from '@tanstack/react-table'
|
||||
import { Fields } from '../../../types'
|
||||
|
||||
interface UpcValidationTableAdapterProps<T extends string> {
|
||||
data: any[]
|
||||
fields: Fields<string>
|
||||
validationErrors: Map<number, Record<string, any[]>>
|
||||
rowSelection: RowSelectionState
|
||||
setRowSelection: (value: RowSelectionState) => void
|
||||
updateRow: (rowIndex: number, key: T, value: any) => void
|
||||
filters: any
|
||||
templates: any[]
|
||||
applyTemplate: (templateId: string, rowIndexes: number[]) => void
|
||||
getTemplateDisplayText: (templateId: string) => string
|
||||
isValidatingUpc: (rowIndex: number) => boolean
|
||||
validatingUpcRows: number[]
|
||||
copyDown: (rowIndex: number, fieldKey: string, endRowIndex?: number) => void
|
||||
validatingCells: Set<string>
|
||||
isLoadingTemplates: boolean
|
||||
rowProductLines: Record<string, any[]>
|
||||
rowSublines: Record<string, any[]>
|
||||
isLoadingLines: Record<string, boolean>
|
||||
isLoadingSublines: Record<string, boolean>
|
||||
upcValidation: {
|
||||
validatingRows: Set<number>
|
||||
getItemNumber: (rowIndex: number) => string | undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* UpcValidationTableAdapter component - connects UPC validation data to ValidationTable
|
||||
*
|
||||
* This component adapts UPC validation data and functionality to work with the core ValidationTable,
|
||||
* transforming item numbers and validation states into a format the table component can render.
|
||||
*/
|
||||
function UpcValidationTableAdapter<T extends string>({
|
||||
data,
|
||||
fields,
|
||||
validationErrors,
|
||||
rowSelection,
|
||||
setRowSelection,
|
||||
updateRow,
|
||||
filters,
|
||||
templates,
|
||||
applyTemplate,
|
||||
getTemplateDisplayText,
|
||||
isValidatingUpc,
|
||||
validatingUpcRows,
|
||||
copyDown,
|
||||
validatingCells: externalValidatingCells,
|
||||
isLoadingTemplates,
|
||||
rowProductLines,
|
||||
rowSublines,
|
||||
isLoadingLines,
|
||||
isLoadingSublines,
|
||||
upcValidation
|
||||
}: UpcValidationTableAdapterProps<T>) {
|
||||
// Prepare the validation table with UPC data
|
||||
const AdaptedTable = useMemo(() => React.memo((props: React.ComponentProps<typeof ValidationTable>) => {
|
||||
// Create validatingCells set from validating rows, but only for item_number fields
|
||||
// This ensures only the item_number column shows loading state during UPC validation
|
||||
const combinedValidatingCells = new Set<string>();
|
||||
|
||||
// Add UPC validation cells
|
||||
upcValidation.validatingRows.forEach(rowIndex => {
|
||||
// Only mark the item_number cells as validating, NOT the UPC or supplier
|
||||
combinedValidatingCells.add(`${rowIndex}-item_number`);
|
||||
});
|
||||
|
||||
// Add any other validating cells from state
|
||||
externalValidatingCells.forEach(cellKey => {
|
||||
combinedValidatingCells.add(cellKey);
|
||||
});
|
||||
|
||||
// Convert the Map to the expected format for the ValidationTable
|
||||
// Create a new Map from the item numbers to ensure proper typing
|
||||
const itemNumbersMap = new Map<number, string>();
|
||||
|
||||
// Merge the item numbers with the data for display purposes only
|
||||
const enhancedData = props.data.map((row: any, index: number) => {
|
||||
const itemNumber = upcValidation.getItemNumber(index);
|
||||
if (itemNumber) {
|
||||
// Add to our map for proper prop passing
|
||||
itemNumbersMap.set(index, itemNumber);
|
||||
|
||||
return {
|
||||
...row,
|
||||
item_number: itemNumber
|
||||
};
|
||||
}
|
||||
return row;
|
||||
});
|
||||
|
||||
return (
|
||||
<ValidationTable
|
||||
{...props}
|
||||
data={enhancedData}
|
||||
validatingCells={combinedValidatingCells}
|
||||
itemNumbers={itemNumbersMap}
|
||||
isLoadingTemplates={isLoadingTemplates}
|
||||
copyDown={copyDown}
|
||||
rowProductLines={rowProductLines}
|
||||
rowSublines={rowSublines}
|
||||
isLoadingLines={isLoadingLines}
|
||||
isLoadingSublines={isLoadingSublines}
|
||||
/>
|
||||
);
|
||||
}), [upcValidation.validatingRows, upcValidation.getItemNumber, isLoadingTemplates, copyDown, externalValidatingCells, rowProductLines, rowSublines, isLoadingLines, isLoadingSublines]);
|
||||
|
||||
// Render the validation table with the provided props and UPC data
|
||||
return (
|
||||
<AdaptedTable
|
||||
data={data}
|
||||
fields={fields}
|
||||
rowSelection={rowSelection}
|
||||
setRowSelection={setRowSelection}
|
||||
updateRow={updateRow as unknown as (rowIndex: number, key: string, value: any) => void}
|
||||
validationErrors={validationErrors}
|
||||
isValidatingUpc={isValidatingUpc}
|
||||
validatingUpcRows={validatingUpcRows}
|
||||
filters={filters}
|
||||
templates={templates}
|
||||
applyTemplate={applyTemplate}
|
||||
getTemplateDisplayText={getTemplateDisplayText}
|
||||
validatingCells={new Set()}
|
||||
itemNumbers={new Map()}
|
||||
isLoadingTemplates={isLoadingTemplates}
|
||||
copyDown={copyDown}
|
||||
upcValidationResults={new Map()}
|
||||
rowProductLines={rowProductLines}
|
||||
rowSublines={rowSublines}
|
||||
isLoadingLines={isLoadingLines}
|
||||
isLoadingSublines={isLoadingSublines}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default UpcValidationTableAdapter
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import { Field } from '../../../types'
|
||||
import { Loader2, AlertCircle, ArrowDown, Check, X } from 'lucide-react'
|
||||
import { Field, ErrorType } from '../../../types'
|
||||
import { Loader2, AlertCircle, ArrowDown, X } from 'lucide-react'
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
@@ -40,6 +40,7 @@ type ErrorObject = {
|
||||
message: string;
|
||||
level: string;
|
||||
source?: string;
|
||||
type?: ErrorType;
|
||||
}
|
||||
|
||||
// Helper function to check if a value is empty - utility function shared by all components
|
||||
@@ -75,7 +76,8 @@ const BaseCellContent = React.memo(({
|
||||
onChange,
|
||||
hasErrors,
|
||||
options = [],
|
||||
className = ''
|
||||
className = '',
|
||||
fieldKey = ''
|
||||
}: {
|
||||
field: Field<string>;
|
||||
value: any;
|
||||
@@ -83,9 +85,12 @@ const BaseCellContent = React.memo(({
|
||||
hasErrors: boolean;
|
||||
options?: readonly any[];
|
||||
className?: string;
|
||||
fieldKey?: string;
|
||||
}) => {
|
||||
// Get field type information
|
||||
const fieldType = typeof field.fieldType === 'string'
|
||||
const fieldType = fieldKey === 'line' || fieldKey === 'subline'
|
||||
? 'select'
|
||||
: typeof field.fieldType === 'string'
|
||||
? field.fieldType
|
||||
: field.fieldType?.type || 'input';
|
||||
|
||||
@@ -99,7 +104,21 @@ const BaseCellContent = React.memo(({
|
||||
(field.fieldType.type === 'input' || field.fieldType.type === 'multi-input') &&
|
||||
field.fieldType.price === true;
|
||||
|
||||
console.log(`BaseCellContent: field.key=${field.key}, fieldType=${fieldType}, disabled=${field.disabled}, options=`, options);
|
||||
// Special case for line and subline - check this first, before any other field type checks
|
||||
if (fieldKey === 'line' || fieldKey === 'subline') {
|
||||
// Force these fields to always use SelectCell regardless of fieldType
|
||||
return (
|
||||
<SelectCell
|
||||
field={{...field, fieldType: { type: 'select', options }}}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
options={options}
|
||||
hasErrors={hasErrors}
|
||||
className={className}
|
||||
disabled={field.disabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (fieldType === 'select') {
|
||||
return (
|
||||
@@ -174,20 +193,17 @@ export interface ValidationCellProps {
|
||||
}
|
||||
|
||||
// Add efficient error message extraction function
|
||||
const getErrorMessage = (error: ErrorObject): string => error.message;
|
||||
|
||||
// Add a utility function to process errors with appropriate caching
|
||||
// Highly optimized error processing function with fast paths for common cases
|
||||
function processErrors(value: any, errors: ErrorObject[]): {
|
||||
filteredErrors: ErrorObject[];
|
||||
hasError: boolean;
|
||||
isRequiredButEmpty: boolean;
|
||||
shouldShowErrorIcon: boolean;
|
||||
errorMessages: string;
|
||||
} {
|
||||
// Fast path - if no errors, return immediately
|
||||
// Fast path - if no errors or empty error array, return immediately
|
||||
if (!errors || errors.length === 0) {
|
||||
return {
|
||||
filteredErrors: [],
|
||||
hasError: false,
|
||||
isRequiredButEmpty: false,
|
||||
shouldShowErrorIcon: false,
|
||||
@@ -195,53 +211,37 @@ function processErrors(value: any, errors: ErrorObject[]): {
|
||||
};
|
||||
}
|
||||
|
||||
// Check if value is empty - using local function for speed
|
||||
const valueIsEmpty = value === undefined ||
|
||||
value === null ||
|
||||
value === '' ||
|
||||
(Array.isArray(value) && value.length === 0) ||
|
||||
(typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0);
|
||||
// Use the shared isEmpty function for value checking
|
||||
const valueIsEmpty = isEmpty(value);
|
||||
|
||||
// If not empty, filter out required errors
|
||||
// Create a new array only if we need to filter (avoid unnecessary allocations)
|
||||
let filteredErrors: ErrorObject[];
|
||||
let hasRequiredError = false;
|
||||
|
||||
if (valueIsEmpty) {
|
||||
// For empty values, check if there are required errors
|
||||
hasRequiredError = errors.some(error =>
|
||||
error.message?.toLowerCase().includes('required')
|
||||
);
|
||||
filteredErrors = errors;
|
||||
} else {
|
||||
// For non-empty values, filter out required errors
|
||||
filteredErrors = errors.filter(error =>
|
||||
!error.message?.toLowerCase().includes('required')
|
||||
);
|
||||
// Fast path for the most common case - required field with empty value
|
||||
if (valueIsEmpty && errors.length === 1 && errors[0].type === ErrorType.Required) {
|
||||
return {
|
||||
hasError: true,
|
||||
isRequiredButEmpty: true,
|
||||
shouldShowErrorIcon: false,
|
||||
errorMessages: ''
|
||||
};
|
||||
}
|
||||
|
||||
// Determine if any actual errors exist after filtering
|
||||
const hasError = filteredErrors.some(error =>
|
||||
error.level === 'error' || error.level === 'warning'
|
||||
);
|
||||
// For non-empty values with errors, we need to show error icons
|
||||
const hasError = errors.some(error => error.level === 'error' || error.level === 'warning');
|
||||
|
||||
// Check if field is required but empty
|
||||
const isRequiredButEmpty = valueIsEmpty && hasRequiredError;
|
||||
// For empty values with required errors, show only a border
|
||||
const isRequiredButEmpty = valueIsEmpty && errors.some(error => error.type === ErrorType.Required);
|
||||
|
||||
// Only show error icons for non-empty fields with actual errors
|
||||
const shouldShowErrorIcon = hasError && !valueIsEmpty;
|
||||
// Show error icons for non-empty fields with errors, or for empty fields with non-required errors
|
||||
const shouldShowErrorIcon = hasError && (!valueIsEmpty || !errors.every(error => error.type === ErrorType.Required));
|
||||
|
||||
// Get error messages for the tooltip - only if we need to show icon
|
||||
let errorMessages = '';
|
||||
if (shouldShowErrorIcon) {
|
||||
errorMessages = filteredErrors
|
||||
// Only compute error messages if we're going to show an icon
|
||||
const errorMessages = shouldShowErrorIcon
|
||||
? errors
|
||||
.filter(e => e.level === 'error' || e.level === 'warning')
|
||||
.map(getErrorMessage)
|
||||
.join('\n');
|
||||
}
|
||||
.map(e => e.message)
|
||||
.join('\n')
|
||||
: '';
|
||||
|
||||
return {
|
||||
filteredErrors,
|
||||
hasError,
|
||||
isRequiredButEmpty,
|
||||
shouldShowErrorIcon,
|
||||
@@ -249,190 +249,33 @@ function processErrors(value: any, errors: ErrorObject[]): {
|
||||
};
|
||||
}
|
||||
|
||||
const ItemNumberCell = React.memo(({
|
||||
value,
|
||||
itemNumber,
|
||||
isValidating,
|
||||
width,
|
||||
errors = [],
|
||||
field,
|
||||
onChange,
|
||||
copyDown,
|
||||
rowIndex,
|
||||
totalRows = 0
|
||||
}: {
|
||||
value: any,
|
||||
itemNumber?: string,
|
||||
isValidating?: boolean,
|
||||
width: number,
|
||||
errors?: ErrorObject[],
|
||||
field: Field<string>,
|
||||
onChange: (value: any) => void,
|
||||
copyDown?: (endRowIndex?: number) => void,
|
||||
rowIndex: number,
|
||||
totalRows?: number
|
||||
}) => {
|
||||
// If we have a value or itemNumber, ignore "required" errors
|
||||
const displayValue = itemNumber || value;
|
||||
// Helper function to compare error arrays efficiently with a hash-based approach
|
||||
function compareErrorArrays(prevErrors: ErrorObject[], nextErrors: ErrorObject[]): boolean {
|
||||
// Fast path for referential equality
|
||||
if (prevErrors === nextErrors) return true;
|
||||
|
||||
// Use the utility function to process errors once
|
||||
const {
|
||||
hasError,
|
||||
isRequiredButEmpty,
|
||||
shouldShowErrorIcon,
|
||||
errorMessages
|
||||
} = React.useMemo(() =>
|
||||
processErrors(displayValue, errors),
|
||||
[displayValue, errors]
|
||||
);
|
||||
// Fast path for length check
|
||||
if (!prevErrors || !nextErrors) return prevErrors === nextErrors;
|
||||
if (prevErrors.length !== nextErrors.length) return false;
|
||||
|
||||
// Add state for hover on copy down button
|
||||
const [isCopyDownHovered, setIsCopyDownHovered] = React.useState(false);
|
||||
// Add state for hover on target row
|
||||
const [isTargetRowHovered, setIsTargetRowHovered] = React.useState(false);
|
||||
|
||||
// Get copy down context
|
||||
const copyDownContext = React.useContext(CopyDownContext);
|
||||
|
||||
// Handle copy down button click
|
||||
const handleCopyDownClick = () => {
|
||||
if (copyDown && totalRows > rowIndex + 1) {
|
||||
// Enter copy down mode
|
||||
copyDownContext.setIsInCopyDownMode(true);
|
||||
copyDownContext.setSourceRowIndex(rowIndex);
|
||||
copyDownContext.setSourceFieldKey('item_number');
|
||||
}
|
||||
// Generate simple hash from error properties
|
||||
const getErrorHash = (error: ErrorObject): string => {
|
||||
return `${error.message}|${error.level}|${error.type || ''}`;
|
||||
};
|
||||
|
||||
// Check if this cell is the source of the current copy down operation
|
||||
const isSourceCell = copyDownContext.isInCopyDownMode &&
|
||||
copyDownContext.sourceRowIndex === rowIndex &&
|
||||
copyDownContext.sourceFieldKey === 'item_number';
|
||||
// Compare using hashes
|
||||
const prevHashes = prevErrors.map(getErrorHash);
|
||||
const nextHashes = nextErrors.map(getErrorHash);
|
||||
|
||||
// Check if this cell is in a row that can be a target for copy down
|
||||
const isInTargetRow = copyDownContext.isInCopyDownMode &&
|
||||
copyDownContext.sourceFieldKey === 'item_number' &&
|
||||
rowIndex > (copyDownContext.sourceRowIndex || 0);
|
||||
// Sort hashes to ensure consistent order
|
||||
prevHashes.sort();
|
||||
nextHashes.sort();
|
||||
|
||||
// Check if this row is the currently selected target row
|
||||
const isSelectedTarget = isInTargetRow && rowIndex <= (copyDownContext.targetRowIndex || 0);
|
||||
// Compare sorted hash arrays
|
||||
return prevHashes.join(',') === nextHashes.join(',');
|
||||
}
|
||||
|
||||
// Handle click on a potential target cell
|
||||
const handleTargetCellClick = () => {
|
||||
if (isInTargetRow && copyDownContext.sourceRowIndex !== null) {
|
||||
copyDownContext.handleCopyDownComplete(
|
||||
copyDownContext.sourceRowIndex,
|
||||
'item_number',
|
||||
rowIndex
|
||||
);
|
||||
}
|
||||
};
|
||||
//item_number fields
|
||||
return (
|
||||
<TableCell
|
||||
className="p-1 group relative"
|
||||
style={{
|
||||
width: `${width}px`,
|
||||
minWidth: `${width}px`,
|
||||
maxWidth: `${width}px`,
|
||||
boxSizing: 'border-box',
|
||||
cursor: isInTargetRow ? 'pointer' : undefined,
|
||||
...(isSourceCell ? { backgroundColor: '#dbeafe', borderRadius: '0.375rem', padding: 0, boxShadow: '0 0 0 2px #3b82f6' } :
|
||||
isSelectedTarget ? { backgroundColor: '#bfdbfe', borderRadius: '0.375rem', padding: 0 } :
|
||||
isInTargetRow && isTargetRowHovered ? { backgroundColor: '#dbeafe', borderRadius: '0.375rem', padding: 0, cursor: 'pointer' } :
|
||||
isInTargetRow ? { borderRadius: '0.375rem', padding: 0, cursor: 'pointer' } : {})
|
||||
}}
|
||||
onClick={isInTargetRow ? handleTargetCellClick : undefined}
|
||||
onMouseEnter={isInTargetRow ? () => setIsTargetRowHovered(true) : undefined}
|
||||
onMouseLeave={isInTargetRow ? () => setIsTargetRowHovered(false) : undefined}
|
||||
>
|
||||
<div className={`relative ${hasError || isRequiredButEmpty ? 'border-red-500' : ''}`}>
|
||||
{shouldShowErrorIcon && !isInTargetRow && (
|
||||
<div className="absolute right-1.5 top-1/2 -translate-y-1/2 z-20">
|
||||
<ValidationIcon error={{
|
||||
message: errorMessages,
|
||||
level: 'error'
|
||||
}} />
|
||||
</div>
|
||||
)}
|
||||
{!shouldShowErrorIcon && copyDown && !isEmpty(displayValue) && !copyDownContext.isInCopyDownMode && (
|
||||
<div className="absolute right-1.5 top-1/2 -translate-y-1/2 z-20 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
onClick={handleCopyDownClick}
|
||||
onMouseEnter={() => setIsCopyDownHovered(true)}
|
||||
onMouseLeave={() => setIsCopyDownHovered(false)}
|
||||
className="p-1 rounded-full hover:bg-blue-100 text-blue-500/70 hover:text-blue-600 transition-colors"
|
||||
aria-label="Copy value to rows below"
|
||||
>
|
||||
<ArrowDown className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">
|
||||
<div className="flex flex-col">
|
||||
<p className="font-medium">Copy value to rows below</p>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
)}
|
||||
{isSourceCell && (
|
||||
<div className="absolute right-1.5 top-1/2 -translate-y-1/2 z-20">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
onClick={() => copyDownContext.setIsInCopyDownMode(false)}
|
||||
className="p-1 rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 transition-colors"
|
||||
aria-label="Cancel copy down"
|
||||
>
|
||||
<X className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">
|
||||
<p>Cancel copy down</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
)}
|
||||
{isValidating ? (
|
||||
<div className={`flex items-center justify-center gap-2 border ${hasError || isRequiredButEmpty ? 'border-red-500' : 'border-input'} rounded-sm px-2 py-1.5`}>
|
||||
<Loader2 className="h-4 w-4 animate-spin text-blue-500" />
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className={`truncate overflow-hidden ${isCopyDownHovered && !copyDownContext.isInCopyDownMode ? 'bg-blue-50/50' : ''}`}>
|
||||
<BaseCellContent
|
||||
field={field}
|
||||
value={displayValue}
|
||||
onChange={onChange}
|
||||
hasErrors={hasError || isRequiredButEmpty}
|
||||
options={(field.fieldType && typeof field.fieldType === 'object' && (field.fieldType as any).options) || []}
|
||||
className={isSourceCell || isSelectedTarget || isInTargetRow ? `${
|
||||
isSourceCell ? '!bg-blue-100 !border-blue-500 !rounded-md' :
|
||||
isSelectedTarget ? '!bg-blue-200 !border-blue-200 !rounded-md' :
|
||||
isInTargetRow ? 'hover:!bg-blue-100 !border-blue-200 !rounded-md' : ''
|
||||
}` : ''}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
);
|
||||
}, (prev, next) => (
|
||||
prev.value === next.value &&
|
||||
prev.itemNumber === next.itemNumber &&
|
||||
prev.isValidating === next.isValidating &&
|
||||
compareErrorArrays(prev.errors || [], next.errors || [])
|
||||
));
|
||||
|
||||
ItemNumberCell.displayName = 'ItemNumberCell';
|
||||
|
||||
const ValidationCell = ({
|
||||
const ValidationCell = React.memo(({
|
||||
field,
|
||||
value,
|
||||
onChange,
|
||||
@@ -444,74 +287,44 @@ const ValidationCell = ({
|
||||
width,
|
||||
copyDown,
|
||||
rowIndex,
|
||||
totalRows = 0}: ValidationCellProps) => {
|
||||
totalRows = 0
|
||||
}: ValidationCellProps) => {
|
||||
// Use the CopyDown context
|
||||
const copyDownContext = React.useContext(CopyDownContext);
|
||||
|
||||
// Display value prioritizes itemNumber if available (for item_number fields)
|
||||
const displayValue = fieldKey === 'item_number' && itemNumber ? itemNumber : value;
|
||||
|
||||
// Use the optimized processErrors function to avoid redundant filtering
|
||||
const {
|
||||
hasError,
|
||||
isRequiredButEmpty,
|
||||
shouldShowErrorIcon,
|
||||
errorMessages
|
||||
} = React.useMemo(() => processErrors(displayValue, errors), [displayValue, errors]);
|
||||
|
||||
// Track whether this cell is the source of a copy-down operation
|
||||
const isSourceCell = copyDownContext.isInCopyDownMode &&
|
||||
rowIndex === copyDownContext.sourceRowIndex &&
|
||||
fieldKey === copyDownContext.sourceFieldKey;
|
||||
|
||||
// Add state for hover on copy down button
|
||||
const [isCopyDownHovered, setIsCopyDownHovered] = React.useState(false);
|
||||
// Add state for hover on target row
|
||||
const [isTargetRowHovered, setIsTargetRowHovered] = React.useState(false);
|
||||
|
||||
// Get copy down context
|
||||
const copyDownContext = React.useContext(CopyDownContext);
|
||||
|
||||
// For item_number fields, use the specialized component
|
||||
if (fieldKey === 'item_number') {
|
||||
return (
|
||||
<ItemNumberCell
|
||||
value={value}
|
||||
itemNumber={itemNumber}
|
||||
isValidating={isValidating}
|
||||
width={width}
|
||||
errors={errors}
|
||||
field={field}
|
||||
onChange={onChange}
|
||||
copyDown={copyDown}
|
||||
rowIndex={rowIndex}
|
||||
totalRows={totalRows}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Memoize filtered errors to avoid recalculation on every render
|
||||
const filteredErrors = React.useMemo(() => {
|
||||
return !isEmpty(value)
|
||||
? errors.filter(error => !error.message?.toLowerCase().includes('required'))
|
||||
: errors;
|
||||
}, [value, errors]);
|
||||
|
||||
// Memoize error state derivations
|
||||
const { hasError, isRequiredButEmpty, shouldShowErrorIcon, errorMessages } = React.useMemo(() => {
|
||||
// Determine if the field has an error after filtering
|
||||
const hasError = filteredErrors.some(error => error.level === 'error' || error.level === 'warning');
|
||||
|
||||
// Determine if the field is required but empty
|
||||
const isRequiredButEmpty = isEmpty(value) &&
|
||||
errors.some(error => error.message?.toLowerCase().includes('required'));
|
||||
|
||||
// Only show error icons for non-empty fields with actual errors (not just required errors)
|
||||
const shouldShowErrorIcon = hasError && !isEmpty(value);
|
||||
|
||||
// Get error messages for the tooltip
|
||||
const errorMessages = shouldShowErrorIcon
|
||||
? filteredErrors.filter(e => e.level === 'error' || e.level === 'warning').map(e => e.message).join('\n')
|
||||
: '';
|
||||
|
||||
return { hasError, isRequiredButEmpty, shouldShowErrorIcon, errorMessages };
|
||||
}, [filteredErrors, value, errors]);
|
||||
// Force isValidating to be a boolean
|
||||
const isLoading = isValidating === true;
|
||||
|
||||
// Handle copy down button click
|
||||
const handleCopyDownClick = () => {
|
||||
const handleCopyDownClick = React.useCallback(() => {
|
||||
if (copyDown && totalRows > rowIndex + 1) {
|
||||
// Enter copy down mode
|
||||
copyDownContext.setIsInCopyDownMode(true);
|
||||
copyDownContext.setSourceRowIndex(rowIndex);
|
||||
copyDownContext.setSourceFieldKey(fieldKey);
|
||||
}
|
||||
};
|
||||
|
||||
// Check if this cell is the source of the current copy down operation
|
||||
const isSourceCell = copyDownContext.isInCopyDownMode &&
|
||||
copyDownContext.sourceRowIndex === rowIndex &&
|
||||
copyDownContext.sourceFieldKey === fieldKey;
|
||||
}, [copyDown, copyDownContext, fieldKey, rowIndex, totalRows]);
|
||||
|
||||
// Check if this cell is in a row that can be a target for copy down
|
||||
const isInTargetRow = copyDownContext.isInCopyDownMode &&
|
||||
@@ -522,7 +335,7 @@ const ValidationCell = ({
|
||||
const isSelectedTarget = isInTargetRow && rowIndex <= (copyDownContext.targetRowIndex || 0);
|
||||
|
||||
// Handle click on a potential target cell
|
||||
const handleTargetCellClick = () => {
|
||||
const handleTargetCellClick = React.useCallback(() => {
|
||||
if (isInTargetRow && copyDownContext.sourceRowIndex !== null && copyDownContext.sourceFieldKey !== null) {
|
||||
copyDownContext.handleCopyDownComplete(
|
||||
copyDownContext.sourceRowIndex,
|
||||
@@ -530,22 +343,35 @@ const ValidationCell = ({
|
||||
rowIndex
|
||||
);
|
||||
}
|
||||
};
|
||||
//normal selects, normal inputs, not item_number or multi-select
|
||||
return (
|
||||
<TableCell
|
||||
className="p-1 group relative"
|
||||
style={{
|
||||
}, [copyDownContext, isInTargetRow, rowIndex]);
|
||||
|
||||
// Memoize the cell style objects to avoid recreating them on every render
|
||||
const cellStyle = React.useMemo(() => ({
|
||||
width: `${width}px`,
|
||||
minWidth: `${width}px`,
|
||||
maxWidth: `${width}px`,
|
||||
boxSizing: 'border-box',
|
||||
boxSizing: 'border-box' as const,
|
||||
cursor: isInTargetRow ? 'pointer' : undefined,
|
||||
...(isSourceCell ? { backgroundColor: '#dbeafe', borderRadius: '0.375rem', padding: 0, boxShadow: '0 0 0 2px #3b82f6' } :
|
||||
isSelectedTarget ? { backgroundColor: '#bfdbfe', borderRadius: '0.375rem', padding: 0 } :
|
||||
isInTargetRow && isTargetRowHovered ? { backgroundColor: '#dbeafe', borderRadius: '0.375rem', padding: 0, cursor: 'pointer' } :
|
||||
isInTargetRow ? { borderRadius: '0.375rem', padding: 0, cursor: 'pointer' } : {})
|
||||
}}
|
||||
}), [width, isInTargetRow, isSourceCell, isSelectedTarget, isTargetRowHovered]);
|
||||
|
||||
// Memoize the cell class name to prevent re-calculating on every render
|
||||
const cellClassName = React.useMemo(() => {
|
||||
if (isSourceCell || isSelectedTarget || isInTargetRow) {
|
||||
return isSourceCell ? '!bg-blue-100 !border-blue-500 !rounded-md' :
|
||||
isSelectedTarget ? '!bg-blue-200 !border-blue-200 !rounded-md' :
|
||||
isInTargetRow ? 'hover:!bg-blue-100 !border-blue-200 !rounded-md' : '';
|
||||
}
|
||||
return '';
|
||||
}, [isSourceCell, isSelectedTarget, isInTargetRow]);
|
||||
|
||||
return (
|
||||
<TableCell
|
||||
className="p-1 group relative"
|
||||
style={cellStyle}
|
||||
onClick={isInTargetRow ? handleTargetCellClick : undefined}
|
||||
onMouseEnter={isInTargetRow ? () => setIsTargetRowHovered(true) : undefined}
|
||||
onMouseLeave={isInTargetRow ? () => setIsTargetRowHovered(false) : undefined}
|
||||
@@ -555,11 +381,12 @@ const ValidationCell = ({
|
||||
<div className="absolute right-1.5 top-1/2 -translate-y-1/2 z-20">
|
||||
<ValidationIcon error={{
|
||||
message: errorMessages,
|
||||
level: 'error'
|
||||
level: 'error',
|
||||
type: ErrorType.Custom
|
||||
}} />
|
||||
</div>
|
||||
)}
|
||||
{!shouldShowErrorIcon && copyDown && !isEmpty(value) && !copyDownContext.isInCopyDownMode && (
|
||||
{!shouldShowErrorIcon && copyDown && !isEmpty(displayValue) && !copyDownContext.isInCopyDownMode && (
|
||||
<div className="absolute right-0.5 top-1/2 -translate-y-1/2 z-20 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
@@ -603,90 +430,72 @@ const ValidationCell = ({
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
)}
|
||||
{isValidating ? (
|
||||
{isLoading ? (
|
||||
<div className={`flex items-center justify-center gap-2 border ${hasError || isRequiredButEmpty ? 'border-red-500' : 'border-input'} rounded-sm px-2 py-1.5`}>
|
||||
<Loader2 className="h-4 w-4 animate-spin text-blue-500" />
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className={`truncate overflow-hidden ${isCopyDownHovered && !copyDownContext.isInCopyDownMode ? 'bg-blue-50/50' : ''}`}>
|
||||
{/* Log options for debugging */}
|
||||
{(() => { console.log(`ValidationCell: fieldKey=${fieldKey}, options=`, options); return null; })()}
|
||||
<BaseCellContent
|
||||
field={field}
|
||||
value={value}
|
||||
value={displayValue}
|
||||
onChange={onChange}
|
||||
hasErrors={hasError || isRequiredButEmpty}
|
||||
options={options}
|
||||
className={isSourceCell || isSelectedTarget || isInTargetRow ? `${
|
||||
isSourceCell ? '!bg-blue-100 !border-blue-500 !rounded-md' :
|
||||
isSelectedTarget ? '!bg-blue-200 !border-blue-200 !rounded-md' :
|
||||
isInTargetRow ? 'hover:!bg-blue-100 !border-blue-200 !rounded-md' : ''
|
||||
}` : ''}
|
||||
className={cellClassName}
|
||||
fieldKey={fieldKey}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
);
|
||||
};
|
||||
}, (prevProps, nextProps) => {
|
||||
// Fast path: if all props are the same object
|
||||
if (prevProps === nextProps) return true;
|
||||
|
||||
export default React.memo(ValidationCell, (prev, next) => {
|
||||
// For validating cells, always re-render
|
||||
if (prev.isValidating !== next.isValidating) {
|
||||
return false;
|
||||
// Optimize the memo comparison function, checking most impactful props first
|
||||
// Check isValidating first as it's most likely to change frequently
|
||||
if (prevProps.isValidating !== nextProps.isValidating) return false;
|
||||
|
||||
// Then check value changes
|
||||
if (prevProps.value !== nextProps.value) return false;
|
||||
|
||||
// Item number is related to validation state
|
||||
if (prevProps.itemNumber !== nextProps.itemNumber) return false;
|
||||
|
||||
// Check errors with our optimized comparison function
|
||||
if (!compareErrorArrays(prevProps.errors, nextProps.errors)) return false;
|
||||
|
||||
// Check field identity
|
||||
if (prevProps.field !== nextProps.field) return false;
|
||||
|
||||
// Shallow options comparison - only if field type is select or multi-select
|
||||
if (prevProps.field.fieldType?.type === 'select' || prevProps.field.fieldType?.type === 'multi-select') {
|
||||
const optionsEqual = prevProps.options === nextProps.options ||
|
||||
(Array.isArray(prevProps.options) &&
|
||||
Array.isArray(nextProps.options) &&
|
||||
prevProps.options.length === nextProps.options.length &&
|
||||
prevProps.options.every((opt, idx) => {
|
||||
const nextOptions = nextProps.options || [];
|
||||
return opt === nextOptions[idx];
|
||||
}));
|
||||
|
||||
if (!optionsEqual) return false;
|
||||
}
|
||||
|
||||
// Quick reference equality checks first for better performance
|
||||
if (prev.value !== next.value || prev.width !== next.width) {
|
||||
return false;
|
||||
}
|
||||
// Check copy down context changes
|
||||
const copyDownContextChanged =
|
||||
prevProps.rowIndex !== nextProps.rowIndex ||
|
||||
prevProps.fieldKey !== nextProps.fieldKey;
|
||||
|
||||
// Check for error arrays equality - avoid JSON.stringify
|
||||
const errorsEqual = compareErrorArrays(prev.errors || [], next.errors || []);
|
||||
if (!errorsEqual) return false;
|
||||
if (copyDownContextChanged) return false;
|
||||
|
||||
// Check options only when needed
|
||||
if (prev.field.fieldType.type === 'select' || prev.field.fieldType.type === 'multi-select') {
|
||||
if (prev.options !== next.options) {
|
||||
// Use safe defaults for options to handle undefined
|
||||
const prevOpts = prev.options || [];
|
||||
const nextOpts = next.options || [];
|
||||
|
||||
// Only do shallow comparison if references are different
|
||||
if (prevOpts.length !== nextOpts.length) return false;
|
||||
|
||||
// Quick length check before detailed comparison
|
||||
for (let i = 0; i < prevOpts.length; i++) {
|
||||
if (prevOpts[i] !== nextOpts[i]) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For item numbers, check itemNumber equality
|
||||
if (prev.fieldKey === 'item_number' && prev.itemNumber !== next.itemNumber) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we got this far, the props are equal
|
||||
// All essential props are the same - we can skip re-rendering
|
||||
return true;
|
||||
});
|
||||
|
||||
// Helper function to compare error arrays efficiently
|
||||
function compareErrorArrays(prevErrors: ErrorObject[], nextErrors: ErrorObject[]): boolean {
|
||||
if (prevErrors === nextErrors) return true;
|
||||
if (prevErrors.length !== nextErrors.length) return false;
|
||||
ValidationCell.displayName = 'ValidationCell';
|
||||
|
||||
for (let i = 0; i < prevErrors.length; i++) {
|
||||
const prevError = prevErrors[i];
|
||||
const nextError = nextErrors[i];
|
||||
|
||||
if (prevError.message !== nextError.message ||
|
||||
prevError.level !== nextError.level ||
|
||||
prevError.source !== nextError.source) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
export default ValidationCell;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ import { RowData, Template } from '../hooks/useValidationState'
|
||||
import ValidationCell, { CopyDownContext } from './ValidationCell'
|
||||
import { useRsi } from '../../../hooks/useRsi'
|
||||
import SearchableTemplateSelect from './SearchableTemplateSelect'
|
||||
import { Table, TableHeader, TableBody, TableHead, TableRow, TableCell } from '@/components/ui/table'
|
||||
import { Table, TableBody, TableRow, TableCell } from '@/components/ui/table'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button } from '@/components/ui/button'
|
||||
@@ -139,15 +139,30 @@ const MemoizedCell = React.memo(({
|
||||
/>
|
||||
);
|
||||
}, (prev, next) => {
|
||||
// Optimize the memo comparison function for better performance
|
||||
// Only re-render if these essential props change
|
||||
return (
|
||||
prev.value === next.value &&
|
||||
prev.isValidating === next.isValidating &&
|
||||
prev.itemNumber === next.itemNumber &&
|
||||
// Deep compare errors
|
||||
prev.errors === next.errors &&
|
||||
prev.options === next.options
|
||||
const valueEqual = prev.value === next.value;
|
||||
const isValidatingEqual = prev.isValidating === next.isValidating;
|
||||
const itemNumberEqual = prev.itemNumber === next.itemNumber;
|
||||
|
||||
// Shallow equality check for errors array
|
||||
const errorsEqual = prev.errors === next.errors || (
|
||||
Array.isArray(prev.errors) &&
|
||||
Array.isArray(next.errors) &&
|
||||
prev.errors.length === next.errors.length &&
|
||||
prev.errors.every((err, idx) => err === next.errors[idx])
|
||||
);
|
||||
|
||||
// Shallow equality check for options array
|
||||
const optionsEqual = prev.options === next.options || (
|
||||
Array.isArray(prev.options) &&
|
||||
Array.isArray(next.options) &&
|
||||
prev.options.length === next.options.length &&
|
||||
prev.options.every((opt, idx) => opt === next.options?.[idx])
|
||||
);
|
||||
|
||||
// Skip checking for props that rarely change
|
||||
return valueEqual && isValidatingEqual && errorsEqual && optionsEqual && itemNumberEqual;
|
||||
});
|
||||
|
||||
MemoizedCell.displayName = 'MemoizedCell';
|
||||
@@ -174,10 +189,6 @@ const ValidationTable = <T extends string>({
|
||||
}: ValidationTableProps<T>) => {
|
||||
const { translations } = useRsi<T>();
|
||||
|
||||
// Debug logs
|
||||
console.log('ValidationTable rowProductLines:', rowProductLines);
|
||||
console.log('ValidationTable rowSublines:', rowSublines);
|
||||
|
||||
// Add state for copy down selection mode
|
||||
const [isInCopyDownMode, setIsInCopyDownMode] = useState(false);
|
||||
const [sourceRowIndex, setSourceRowIndex] = useState<number | null>(null);
|
||||
@@ -293,10 +304,13 @@ const ValidationTable = <T extends string>({
|
||||
const cache = new Map<string, readonly any[]>();
|
||||
|
||||
fields.forEach((field) => {
|
||||
// Don't skip disabled fields
|
||||
|
||||
if (field.fieldType.type === 'select' || field.fieldType.type === 'multi-select') {
|
||||
// Get the field key
|
||||
const fieldKey = String(field.key);
|
||||
|
||||
// Handle all select and multi-select fields the same way
|
||||
if (field.fieldType &&
|
||||
(typeof field.fieldType === 'object') &&
|
||||
(field.fieldType.type === 'select' || field.fieldType.type === 'multi-select')) {
|
||||
cache.set(fieldKey, (field.fieldType as any).options || []);
|
||||
}
|
||||
});
|
||||
@@ -342,30 +356,61 @@ const ValidationTable = <T extends string>({
|
||||
|
||||
if (fieldKey === 'line' && rowId && rowProductLines[rowId]) {
|
||||
options = rowProductLines[rowId];
|
||||
console.log(`Setting line options for row ${rowId}:`, options);
|
||||
} else if (fieldKey === 'subline' && rowId && rowSublines[rowId]) {
|
||||
options = rowSublines[rowId];
|
||||
console.log(`Setting subline options for row ${rowId}:`, options);
|
||||
}
|
||||
|
||||
// Determine if this cell is in loading state
|
||||
let isLoading = validatingCells.has(`${row.index}-${field.key}`);
|
||||
// Determine if this cell is in loading state - use a clear consistent approach
|
||||
let isLoading = false;
|
||||
|
||||
// Check the validatingCells Set first (for item_number and other fields)
|
||||
const cellLoadingKey = `${row.index}-${fieldKey}`;
|
||||
if (validatingCells.has(cellLoadingKey)) {
|
||||
isLoading = true;
|
||||
}
|
||||
// Add loading state for line/subline fields
|
||||
if (fieldKey === 'line' && rowId && isLoadingLines[rowId]) {
|
||||
else if (fieldKey === 'line' && rowId && isLoadingLines[rowId]) {
|
||||
isLoading = true;
|
||||
console.log(`Line field for row ${rowId} is loading`);
|
||||
} else if (fieldKey === 'subline' && rowId && isLoadingSublines[rowId]) {
|
||||
}
|
||||
else if (fieldKey === 'subline' && rowId && isLoadingSublines[rowId]) {
|
||||
isLoading = true;
|
||||
console.log(`Subline field for row ${rowId} is loading`);
|
||||
}
|
||||
|
||||
// Get validation errors for this cell
|
||||
const cellErrors = validationErrors.get(row.index)?.[fieldKey] || [];
|
||||
|
||||
// Create a copy of the field with guaranteed field type for line and subline fields
|
||||
let fieldWithType = field;
|
||||
|
||||
// Ensure line and subline fields always have the correct fieldType
|
||||
if (fieldKey === 'line' || fieldKey === 'subline') {
|
||||
// Create a deep clone of the field to prevent any reference issues
|
||||
fieldWithType = {
|
||||
...JSON.parse(JSON.stringify(field)), // Ensure deep clone
|
||||
fieldType: {
|
||||
type: 'select',
|
||||
options: options
|
||||
},
|
||||
// Explicitly mark as not disabled to ensure dropdown works
|
||||
disabled: false
|
||||
};
|
||||
|
||||
// Debug logging
|
||||
console.log(`Field ${fieldKey} in ValidationTable (after deep clone):`, {
|
||||
originalField: field,
|
||||
modifiedField: fieldWithType,
|
||||
options,
|
||||
hasOptions: options && options.length > 0,
|
||||
disabled: fieldWithType.disabled
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<MemoizedCell
|
||||
field={field as Field<string>}
|
||||
field={fieldWithType as Field<string>}
|
||||
value={row.original[field.key as keyof typeof row.original]}
|
||||
onChange={(value) => handleFieldUpdate(row.index, field.key as T, value)}
|
||||
errors={validationErrors.get(row.index)?.[fieldKey] || []}
|
||||
errors={cellErrors}
|
||||
isValidating={isLoading}
|
||||
fieldKey={fieldKey}
|
||||
options={options}
|
||||
@@ -387,15 +432,13 @@ const ValidationTable = <T extends string>({
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
state: { rowSelection },
|
||||
state: {
|
||||
rowSelection,
|
||||
},
|
||||
enableRowSelection: true,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
getRowId: (row) => {
|
||||
if (row.__index) return row.__index;
|
||||
const index = data.indexOf(row);
|
||||
return String(index);
|
||||
}
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getRowId: useCallback((_row: RowData<T>, index: number) => String(index), []),
|
||||
});
|
||||
|
||||
// Calculate total table width for stable horizontal scrolling
|
||||
@@ -481,13 +524,16 @@ const ValidationTable = <T extends string>({
|
||||
</div>
|
||||
)}
|
||||
<div className="relative">
|
||||
{/* Custom Table Header - Always Visible */}
|
||||
{/* Custom Table Header - Always Visible with GPU acceleration */}
|
||||
<div
|
||||
className={`sticky top-0 z-20 bg-muted border-b shadow-sm`}
|
||||
style={{ width: `${totalWidth}px` }}
|
||||
className="sticky top-0 z-20 bg-muted border-b shadow-sm will-change-transform"
|
||||
style={{
|
||||
width: `${totalWidth}px`,
|
||||
transform: 'translateZ(0)', // Force GPU acceleration
|
||||
}}
|
||||
>
|
||||
<div className="flex">
|
||||
{table.getFlatHeaders().map((header, index) => {
|
||||
{table.getFlatHeaders().map((header) => {
|
||||
const width = header.getSize();
|
||||
return (
|
||||
<div
|
||||
@@ -508,49 +554,57 @@ const ValidationTable = <T extends string>({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Table Body */}
|
||||
<Table style={{ width: `${totalWidth}px`, tableLayout: 'fixed', borderCollapse: 'separate', borderSpacing: 0, marginTop: '-1px' }}>
|
||||
{/* Table Body - With optimized rendering */}
|
||||
<Table style={{
|
||||
width: `${totalWidth}px`,
|
||||
tableLayout: 'fixed',
|
||||
borderCollapse: 'separate',
|
||||
borderSpacing: 0,
|
||||
marginTop: '-1px',
|
||||
willChange: 'transform', // Help browser optimize
|
||||
contain: 'content', // Contain paint operations
|
||||
transform: 'translateZ(0)' // Force GPU acceleration
|
||||
}}>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows.map((row) => (
|
||||
{table.getRowModel().rows.map((row) => {
|
||||
// Precompute validation error status for this row
|
||||
const hasErrors = validationErrors.has(parseInt(row.id)) &&
|
||||
Object.keys(validationErrors.get(parseInt(row.id)) || {}).length > 0;
|
||||
|
||||
// Precompute copy down target status
|
||||
const isCopyDownTarget = isInCopyDownMode &&
|
||||
sourceRowIndex !== null &&
|
||||
parseInt(row.id) > sourceRowIndex;
|
||||
|
||||
// Using CSS variables for better performance on hover/state changes
|
||||
const rowStyle = {
|
||||
cursor: isCopyDownTarget ? 'pointer' : undefined,
|
||||
position: 'relative' as const,
|
||||
willChange: isInCopyDownMode ? 'background-color' : 'auto',
|
||||
contain: 'layout',
|
||||
transition: 'background-color 100ms ease-in-out'
|
||||
};
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
className={cn(
|
||||
"hover:bg-muted/50",
|
||||
row.getIsSelected() ? "bg-muted/50" : "",
|
||||
validationErrors.get(data.indexOf(row.original)) &&
|
||||
Object.keys(validationErrors.get(data.indexOf(row.original)) || {}).length > 0 ? "bg-red-50/40" : "",
|
||||
// Add cursor-pointer class when in copy down mode for target rows
|
||||
isInCopyDownMode && sourceRowIndex !== null && row.index > sourceRowIndex ? "cursor-pointer copy-down-target-row" : ""
|
||||
hasErrors ? "bg-red-50/40" : "",
|
||||
isCopyDownTarget ? "cursor-pointer copy-down-target-row" : ""
|
||||
)}
|
||||
style={{
|
||||
// Force cursor pointer on all target rows
|
||||
cursor: isInCopyDownMode && sourceRowIndex !== null && row.index > sourceRowIndex ? 'pointer' : undefined,
|
||||
position: 'relative' // Ensure we can position the overlay
|
||||
}}
|
||||
onMouseEnter={() => handleRowMouseEnter(row.index)}
|
||||
>
|
||||
{row.getVisibleCells().map((cell, cellIndex) => {
|
||||
const width = cell.column.getSize();
|
||||
return (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
style={{
|
||||
width: `${width}px`,
|
||||
minWidth: `${width}px`,
|
||||
maxWidth: `${width}px`,
|
||||
boxSizing: 'border-box',
|
||||
padding: '0',
|
||||
// Force cursor pointer on all cells in target rows
|
||||
cursor: isInCopyDownMode && sourceRowIndex !== null && row.index > sourceRowIndex ? 'pointer' : undefined
|
||||
}}
|
||||
className={isInCopyDownMode && sourceRowIndex !== null && row.index > sourceRowIndex ? "target-row-cell" : ""}
|
||||
style={rowStyle}
|
||||
onMouseEnter={() => handleRowMouseEnter(parseInt(row.id))}
|
||||
>
|
||||
{row.getVisibleCells().map((cell: any) => (
|
||||
<React.Fragment key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
|
||||
@@ -107,23 +107,28 @@ const InputCell = <T extends string>({
|
||||
|
||||
// Handle blur event - use transition for non-critical updates
|
||||
const handleBlur = useCallback(() => {
|
||||
// First - lock in the current edit value to prevent it from being lost
|
||||
const finalValue = editValue.trim();
|
||||
|
||||
// Then transition to non-editing state
|
||||
startTransition(() => {
|
||||
setIsEditing(false);
|
||||
|
||||
// Format the value for storage (remove formatting like $ for price)
|
||||
let processedValue = deferredEditValue.trim();
|
||||
let processedValue = finalValue;
|
||||
|
||||
if (isPrice && processedValue) {
|
||||
needsProcessingRef.current = true;
|
||||
}
|
||||
|
||||
// Update local display value immediately
|
||||
// Update local display value immediately to prevent UI flicker
|
||||
setLocalDisplayValue(processedValue);
|
||||
|
||||
// Commit the change to parent component
|
||||
onChange(processedValue);
|
||||
onEndEdit?.();
|
||||
});
|
||||
}, [deferredEditValue, onChange, onEndEdit, isPrice]);
|
||||
}, [editValue, onChange, onEndEdit, isPrice]);
|
||||
|
||||
// Handle direct input change - optimized to be synchronous for typing
|
||||
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
|
||||
@@ -167,41 +167,59 @@ const MultiSelectCell = <T extends string>({
|
||||
const commandListRef = useRef<HTMLDivElement>(null)
|
||||
// Add state for hover
|
||||
const [isHovered, setIsHovered] = useState(false)
|
||||
// Add ref to track if we need to sync internal state with external value
|
||||
const shouldSyncWithExternalValue = useRef(true)
|
||||
|
||||
// Create a memoized Set for fast lookups of selected values
|
||||
const selectedValueSet = useMemo(() => new Set(internalValue), [internalValue]);
|
||||
|
||||
// Sync internalValue with external value when component mounts or value changes externally
|
||||
// Modified to prevent infinite loop by checking if values are different before updating
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
// Ensure value is always an array
|
||||
setInternalValue(Array.isArray(value) ? value : [])
|
||||
// Only sync if we should (not during internal edits) and if not open
|
||||
if (shouldSyncWithExternalValue.current && !open) {
|
||||
const externalValue = Array.isArray(value) ? value : [];
|
||||
|
||||
// Only update if values are actually different to prevent infinite loops
|
||||
if (internalValue.length !== externalValue.length ||
|
||||
!internalValue.every(v => externalValue.includes(v)) ||
|
||||
!externalValue.every(v => internalValue.includes(v))) {
|
||||
setInternalValue(externalValue);
|
||||
}
|
||||
}, [value, open])
|
||||
}
|
||||
}, [value, open, internalValue]);
|
||||
|
||||
// Handle open state changes with improved responsiveness
|
||||
const handleOpenChange = useCallback((newOpen: boolean) => {
|
||||
if (open && !newOpen) {
|
||||
// Prevent syncing with external value during our internal update
|
||||
shouldSyncWithExternalValue.current = false;
|
||||
|
||||
// Only update parent state when dropdown closes
|
||||
// Avoid expensive deep comparison if lengths are different
|
||||
if (internalValue.length !== value.length ||
|
||||
internalValue.some((v, i) => v !== value[i])) {
|
||||
onChange(internalValue);
|
||||
}
|
||||
// Make a defensive copy to avoid mutations
|
||||
const valuesToCommit = [...internalValue];
|
||||
|
||||
// Immediate UI update
|
||||
setOpen(false);
|
||||
|
||||
// Update parent with the value immediately
|
||||
onChange(valuesToCommit);
|
||||
if (onEndEdit) onEndEdit();
|
||||
|
||||
// Allow syncing with external value again after a short delay
|
||||
setTimeout(() => {
|
||||
shouldSyncWithExternalValue.current = true;
|
||||
}, 0);
|
||||
} else if (newOpen && !open) {
|
||||
// Sync internal state with external state when opening
|
||||
setInternalValue(Array.isArray(value) ? value : []);
|
||||
// When opening the dropdown, sync with external value
|
||||
const externalValue = Array.isArray(value) ? value : [];
|
||||
setInternalValue(externalValue);
|
||||
setSearchQuery(""); // Reset search query on open
|
||||
setOpen(true);
|
||||
if (onStartEdit) onStartEdit();
|
||||
} else if (!newOpen) {
|
||||
// Handle case when dropdown is already closed but handleOpenChange is called
|
||||
// This ensures values are saved when clicking the chevron to close
|
||||
if (internalValue.length !== value.length ||
|
||||
internalValue.some((v, i) => v !== value[i])) {
|
||||
onChange(internalValue);
|
||||
}
|
||||
if (onEndEdit) onEndEdit();
|
||||
setOpen(false);
|
||||
}
|
||||
}, [open, internalValue, value, onChange, onStartEdit, onEndEdit]);
|
||||
|
||||
@@ -302,13 +320,25 @@ const MultiSelectCell = <T extends string>({
|
||||
|
||||
// Update the handleSelect to operate on internalValue instead of directly calling onChange
|
||||
const handleSelect = useCallback((selectedValue: string) => {
|
||||
// Prevent syncing with external value during our internal update
|
||||
shouldSyncWithExternalValue.current = false;
|
||||
|
||||
setInternalValue(prev => {
|
||||
let newValue;
|
||||
if (prev.includes(selectedValue)) {
|
||||
return prev.filter(v => v !== selectedValue);
|
||||
// Remove the value
|
||||
newValue = prev.filter(v => v !== selectedValue);
|
||||
} else {
|
||||
return [...prev, selectedValue];
|
||||
// Add the value - make a new array to avoid mutations
|
||||
newValue = [...prev, selectedValue];
|
||||
}
|
||||
return newValue;
|
||||
});
|
||||
|
||||
// Allow syncing with external value again after a short delay
|
||||
setTimeout(() => {
|
||||
shouldSyncWithExternalValue.current = true;
|
||||
}, 0);
|
||||
}, []);
|
||||
|
||||
// Handle wheel scroll in dropdown
|
||||
|
||||
@@ -51,8 +51,6 @@ const SelectCell = <T extends string>({
|
||||
// Add state for hover
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
|
||||
console.log(`SelectCell: field.key=${field.key}, disabled=${disabled}, options=`, options);
|
||||
|
||||
// Helper function to check if a class is present in the className string
|
||||
const hasClass = (cls: string): boolean => {
|
||||
const classNames = className.split(' ');
|
||||
@@ -68,7 +66,6 @@ const SelectCell = <T extends string>({
|
||||
|
||||
// Memoize options processing to avoid recalculation on every render
|
||||
const selectOptions = useMemo(() => {
|
||||
console.log(`Processing options for ${field.key}:`, options);
|
||||
// Fast path check - if we have raw options, just use those
|
||||
if (options && options.length > 0) {
|
||||
// Check if options already have the correct structure to avoid mapping
|
||||
@@ -126,8 +123,11 @@ const SelectCell = <T extends string>({
|
||||
|
||||
// Handle selection - UPDATE INTERNAL VALUE FIRST
|
||||
const handleSelect = useCallback((selectedValue: string) => {
|
||||
// Store the selected value to prevent it being lost in async operations
|
||||
const valueToCommit = selectedValue;
|
||||
|
||||
// 1. Update internal value immediately to prevent UI flicker
|
||||
setInternalValue(selectedValue);
|
||||
setInternalValue(valueToCommit);
|
||||
|
||||
// 2. Close the dropdown immediately
|
||||
setOpen(false);
|
||||
@@ -139,37 +139,25 @@ const SelectCell = <T extends string>({
|
||||
// This prevents the parent component from re-rendering and causing dropdown to reopen
|
||||
if (onEndEdit) onEndEdit();
|
||||
|
||||
// 5. Call onChange in the next tick to avoid synchronous re-renders
|
||||
// 5. Call onChange synchronously to avoid race conditions with other cells
|
||||
onChange(valueToCommit);
|
||||
|
||||
// 6. Clear processing state after a short delay
|
||||
setTimeout(() => {
|
||||
onChange(selectedValue);
|
||||
}, 0);
|
||||
setIsProcessing(false);
|
||||
}, 200);
|
||||
}, [onChange, onEndEdit]);
|
||||
|
||||
// If disabled, render a static view
|
||||
if (disabled) {
|
||||
if (disabled && field.key !== 'line' && field.key !== 'subline') {
|
||||
const displayText = displayValue;
|
||||
|
||||
// For debugging, let's render the Popover component even if disabled
|
||||
// This will help us determine if the issue is with the disabled state
|
||||
return (
|
||||
<Popover
|
||||
open={open}
|
||||
onOpenChange={(isOpen) => {
|
||||
setOpen(isOpen);
|
||||
if (isOpen && onStartEdit) onStartEdit();
|
||||
}}
|
||||
>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
<div
|
||||
className={cn(
|
||||
"w-full justify-between font-normal",
|
||||
"w-full px-3 py-2 h-10 rounded-md text-sm flex items-center",
|
||||
"border",
|
||||
!internalValue && "text-muted-foreground",
|
||||
isProcessing && "text-muted-foreground",
|
||||
hasErrors ? "border-destructive" : "",
|
||||
hasErrors ? "border-destructive" : "border-input",
|
||||
className
|
||||
)}
|
||||
style={{
|
||||
@@ -182,62 +170,13 @@ const SelectCell = <T extends string>({
|
||||
hasClass('!border-blue-200') && isHovered ? '#bfdbfe' :
|
||||
undefined,
|
||||
borderRadius: hasClass('!rounded-md') ? '0.375rem' : undefined,
|
||||
borderWidth: hasClass('!border-blue-500') || hasClass('!border-blue-200') ? '0px' : undefined,
|
||||
cursor: hasClass('hover:!bg-blue-100') ? 'pointer' : undefined
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setOpen(!open);
|
||||
if (!open && onStartEdit) onStartEdit();
|
||||
}}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
<span className={isProcessing ? "opacity-70" : ""}>
|
||||
{displayValue}
|
||||
</span>
|
||||
<ChevronsUpDown className="mr-1.5 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
className="p-0 w-[var(--radix-popover-trigger-width)]"
|
||||
align="start"
|
||||
sideOffset={4}
|
||||
>
|
||||
<Command shouldFilter={true}>
|
||||
<CommandInput
|
||||
placeholder="Search..."
|
||||
className="h-9"
|
||||
/>
|
||||
<CommandList
|
||||
ref={commandListRef}
|
||||
onWheel={handleWheel}
|
||||
className="max-h-[200px]"
|
||||
>
|
||||
<CommandEmpty>No options found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{selectOptions.map((option) => (
|
||||
<CommandItem
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
onSelect={(value) => handleSelect(value)}
|
||||
className="flex w-full"
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4 flex-shrink-0",
|
||||
internalValue === option.value ? "opacity-100" : "opacity-0"
|
||||
)}
|
||||
/>
|
||||
<span className="truncate w-full">{option.label}</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
{displayText || ""}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { getApiUrl, RowData } from './useValidationState';
|
||||
import { Fields, InfoWithSource, ErrorSources } from '../../../types';
|
||||
import { Fields, InfoWithSource, ErrorSources, ErrorType } from '../../../types';
|
||||
import { Meta } from '../types';
|
||||
import { addErrorsAndRunHooks } from '../utils/dataMutations';
|
||||
import * as Diff from 'diff';
|
||||
@@ -88,21 +88,10 @@ export const useAiValidation = <T extends string>(
|
||||
// Call the original hook
|
||||
const result = await rowHook(row);
|
||||
// Extract Meta-specific properties
|
||||
const { __index, __errors } = result;
|
||||
// Return a Meta object with properly typed errors
|
||||
const { __index } = result;
|
||||
// Return a Meta object with only the __index property
|
||||
return {
|
||||
__index: __index || row.__index || '',
|
||||
__errors: __errors ?
|
||||
Object.fromEntries(
|
||||
Object.entries(__errors).map(([key, value]) => {
|
||||
const errorArray = Array.isArray(value) ? value : [value];
|
||||
return [key, {
|
||||
message: errorArray[0].message,
|
||||
level: errorArray[0].level,
|
||||
source: ErrorSources.Row
|
||||
} as InfoWithSource]
|
||||
})
|
||||
) : null
|
||||
__index: __index || row.__index || ''
|
||||
};
|
||||
} : undefined;
|
||||
|
||||
@@ -112,18 +101,7 @@ export const useAiValidation = <T extends string>(
|
||||
const results = await tableHook(rows);
|
||||
// Extract Meta-specific properties from each result
|
||||
return results.map((result, index) => ({
|
||||
__index: result.__index || rows[index].__index || '',
|
||||
__errors: result.__errors ?
|
||||
Object.fromEntries(
|
||||
Object.entries(result.__errors).map(([key, value]) => {
|
||||
const errorArray = Array.isArray(value) ? value : [value];
|
||||
return [key, {
|
||||
message: errorArray[0].message,
|
||||
level: errorArray[0].level,
|
||||
source: ErrorSources.Table
|
||||
} as InfoWithSource]
|
||||
})
|
||||
) : null
|
||||
__index: result.__index || rows[index].__index || ''
|
||||
}));
|
||||
} : undefined;
|
||||
|
||||
@@ -283,7 +261,7 @@ export const useAiValidation = <T extends string>(
|
||||
|
||||
// Clean the data to ensure we only send what's needed
|
||||
const cleanedData = data.map(item => {
|
||||
const { __errors, __index, ...rest } = item;
|
||||
const { __index, ...rest } = item;
|
||||
return rest;
|
||||
});
|
||||
|
||||
@@ -399,8 +377,8 @@ export const useAiValidation = <T extends string>(
|
||||
|
||||
// Clean the data to ensure we only send what's needed
|
||||
const cleanedData = data.map(item => {
|
||||
const { __errors, __index, ...cleanProduct } = item;
|
||||
return cleanProduct;
|
||||
const { __index, ...rest } = item;
|
||||
return rest;
|
||||
});
|
||||
|
||||
console.log('Cleaned data for validation:', cleanedData);
|
||||
@@ -601,7 +579,7 @@ export const useAiValidation = <T extends string>(
|
||||
|
||||
console.log('Data updated after AI validation:', {
|
||||
dataLength: validatedData.length,
|
||||
hasErrors: validatedData.some(row => row.__errors && Object.keys(row.__errors).length > 0)
|
||||
hasErrors: false // We no longer check row.__errors
|
||||
});
|
||||
|
||||
// Show changes and warnings in dialog after data is updated
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
import { useState, useCallback, useMemo } from 'react'
|
||||
import type { Fields } from '../../../types'
|
||||
import { RowData } from './useValidationState'
|
||||
|
||||
export interface FilterState {
|
||||
searchText: string
|
||||
showErrorsOnly: boolean
|
||||
filterField: string | null
|
||||
filterValue: string | null
|
||||
}
|
||||
|
||||
export const useFilters = <T extends string>(
|
||||
data: RowData<T>[],
|
||||
fields: Fields<T>
|
||||
) => {
|
||||
// Filter state
|
||||
const [filters, setFilters] = useState<FilterState>({
|
||||
searchText: '',
|
||||
showErrorsOnly: false,
|
||||
filterField: null,
|
||||
filterValue: null
|
||||
})
|
||||
|
||||
// Get available filter fields
|
||||
const filterFields = useMemo(() => {
|
||||
return fields.map(field => ({
|
||||
key: field.key,
|
||||
label: field.label
|
||||
}))
|
||||
}, [fields])
|
||||
|
||||
// Get available filter values for the selected field
|
||||
const filterValues = useMemo(() => {
|
||||
if (!filters.filterField) return []
|
||||
|
||||
// Get unique values for the selected field
|
||||
const uniqueValues = new Set<string>()
|
||||
|
||||
data.forEach(row => {
|
||||
const value = row[filters.filterField as keyof typeof row]
|
||||
if (value !== undefined && value !== null) {
|
||||
uniqueValues.add(String(value))
|
||||
}
|
||||
})
|
||||
|
||||
return Array.from(uniqueValues).map(value => ({
|
||||
value,
|
||||
label: value
|
||||
}))
|
||||
}, [data, filters.filterField])
|
||||
|
||||
// Update filters
|
||||
const updateFilters = useCallback((newFilters: Partial<FilterState>) => {
|
||||
setFilters(prev => ({
|
||||
...prev,
|
||||
...newFilters
|
||||
}))
|
||||
}, [])
|
||||
|
||||
// Apply filters to data
|
||||
const applyFilters = useCallback((dataToFilter: RowData<T>[]) => {
|
||||
return dataToFilter.filter(row => {
|
||||
// Filter by search text
|
||||
if (filters.searchText) {
|
||||
const lowerSearchText = filters.searchText.toLowerCase()
|
||||
const matchesSearch = Object.entries(row).some(([key, value]) => {
|
||||
// Skip metadata fields
|
||||
if (key.startsWith('__')) return false
|
||||
|
||||
// Check if the value contains the search text
|
||||
return value !== undefined &&
|
||||
value !== null &&
|
||||
String(value).toLowerCase().includes(lowerSearchText)
|
||||
})
|
||||
|
||||
if (!matchesSearch) return false
|
||||
}
|
||||
|
||||
// Filter by errors
|
||||
if (filters.showErrorsOnly) {
|
||||
const hasErrors = row.__errors && Object.keys(row.__errors).length > 0
|
||||
if (!hasErrors) return false
|
||||
}
|
||||
|
||||
// Filter by field value
|
||||
if (filters.filterField && filters.filterValue) {
|
||||
const fieldValue = row[filters.filterField as keyof typeof row]
|
||||
return fieldValue !== undefined &&
|
||||
fieldValue !== null &&
|
||||
String(fieldValue) === filters.filterValue
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}, [filters])
|
||||
|
||||
// Reset all filters
|
||||
const resetFilters = useCallback(() => {
|
||||
setFilters({
|
||||
searchText: '',
|
||||
showErrorsOnly: false,
|
||||
filterField: null,
|
||||
filterValue: null
|
||||
})
|
||||
}, [])
|
||||
|
||||
return {
|
||||
filters,
|
||||
filterFields,
|
||||
filterValues,
|
||||
updateFilters,
|
||||
applyFilters,
|
||||
resetFilters
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
import { useState, useCallback, useEffect } from 'react'
|
||||
import axios from 'axios'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
/**
|
||||
* Custom hook for managing product lines and sublines fetching with caching
|
||||
*/
|
||||
export const useProductLinesFetching = (data: Record<string, any>[]) => {
|
||||
// State for tracking product lines and sublines per row
|
||||
const [rowProductLines, setRowProductLines] = useState<Record<string, any[]>>({});
|
||||
const [rowSublines, setRowSublines] = useState<Record<string, any[]>>({});
|
||||
|
||||
// State for tracking loading states
|
||||
const [isLoadingLines, setIsLoadingLines] = useState<Record<string, boolean>>({});
|
||||
const [isLoadingSublines, setIsLoadingSublines] = useState<Record<string, boolean>>({});
|
||||
|
||||
// Add caches for product lines and sublines by company/line ID
|
||||
const [companyLinesCache, setCompanyLinesCache] = useState<Record<string, any[]>>({});
|
||||
const [lineSublineCache, setLineSublineCache] = useState<Record<string, any[]>>({});
|
||||
|
||||
// Function to fetch product lines for a specific company - memoized
|
||||
const fetchProductLines = useCallback(async (rowIndex: string | number, companyId: string) => {
|
||||
try {
|
||||
// Only fetch if we have a valid company ID
|
||||
if (!companyId) return;
|
||||
|
||||
console.log(`Fetching product lines for row ${rowIndex}, company ${companyId}`);
|
||||
|
||||
// Check if we already have this company's lines in the cache
|
||||
if (companyLinesCache[companyId]) {
|
||||
console.log(`Using cached product lines for company ${companyId}`);
|
||||
// Use cached data
|
||||
setRowProductLines(prev => ({ ...prev, [rowIndex]: companyLinesCache[companyId] }));
|
||||
return companyLinesCache[companyId];
|
||||
}
|
||||
|
||||
// Set loading state for this row
|
||||
setIsLoadingLines(prev => ({ ...prev, [rowIndex]: true }));
|
||||
|
||||
// Fetch product lines from API
|
||||
const productLinesUrl = `/api/import/product-lines/${companyId}`;
|
||||
const response = await axios.get(productLinesUrl);
|
||||
|
||||
const lines = response.data;
|
||||
console.log(`Received ${lines.length} product lines for company ${companyId}`);
|
||||
|
||||
// Format the data properly for dropdown display
|
||||
const formattedLines = lines.map((line: any) => ({
|
||||
label: line.name || line.label || String(line.value || line.id),
|
||||
value: String(line.value || line.id)
|
||||
}));
|
||||
|
||||
// Store in company cache
|
||||
setCompanyLinesCache(prev => ({ ...prev, [companyId]: formattedLines }));
|
||||
|
||||
// Store for this specific row
|
||||
setRowProductLines(prev => ({ ...prev, [rowIndex]: formattedLines }));
|
||||
|
||||
return formattedLines;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching product lines for company ${companyId}:`, error);
|
||||
toast.error(`Failed to load product lines for company ${companyId}`);
|
||||
|
||||
// Set empty array for this company to prevent repeated failed requests
|
||||
setCompanyLinesCache(prev => ({ ...prev, [companyId]: [] }));
|
||||
|
||||
// Store empty array for this specific row
|
||||
setRowProductLines(prev => ({ ...prev, [rowIndex]: [] }));
|
||||
|
||||
return [];
|
||||
} finally {
|
||||
// Clear loading state
|
||||
setIsLoadingLines(prev => ({ ...prev, [rowIndex]: false }));
|
||||
}
|
||||
}, [companyLinesCache]);
|
||||
|
||||
// Function to fetch sublines for a specific line - memoized
|
||||
const fetchSublines = useCallback(async (rowIndex: string | number, lineId: string) => {
|
||||
try {
|
||||
// Only fetch if we have a valid line ID
|
||||
if (!lineId) return;
|
||||
|
||||
console.log(`Fetching sublines for row ${rowIndex}, line ${lineId}`);
|
||||
|
||||
// Check if we already have this line's sublines in the cache
|
||||
if (lineSublineCache[lineId]) {
|
||||
console.log(`Using cached sublines for line ${lineId}`);
|
||||
// Use cached data
|
||||
setRowSublines(prev => ({ ...prev, [rowIndex]: lineSublineCache[lineId] }));
|
||||
return lineSublineCache[lineId];
|
||||
}
|
||||
|
||||
// Set loading state for this row
|
||||
setIsLoadingSublines(prev => ({ ...prev, [rowIndex]: true }));
|
||||
|
||||
// Fetch sublines from API
|
||||
const sublinesUrl = `/api/import/sublines/${lineId}`;
|
||||
const response = await axios.get(sublinesUrl);
|
||||
|
||||
const sublines = response.data;
|
||||
console.log(`Received ${sublines.length} sublines for line ${lineId}`);
|
||||
|
||||
// Format the data properly for dropdown display
|
||||
const formattedSublines = sublines.map((subline: any) => ({
|
||||
label: subline.name || subline.label || String(subline.value || subline.id),
|
||||
value: String(subline.value || subline.id)
|
||||
}));
|
||||
|
||||
// Store in line cache
|
||||
setLineSublineCache(prev => ({ ...prev, [lineId]: formattedSublines }));
|
||||
|
||||
// Store for this specific row
|
||||
setRowSublines(prev => ({ ...prev, [rowIndex]: formattedSublines }));
|
||||
|
||||
return formattedSublines;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching sublines for line ${lineId}:`, error);
|
||||
|
||||
// Set empty array for this line to prevent repeated failed requests
|
||||
setLineSublineCache(prev => ({ ...prev, [lineId]: [] }));
|
||||
|
||||
// Store empty array for this specific row
|
||||
setRowSublines(prev => ({ ...prev, [rowIndex]: [] }));
|
||||
|
||||
return [];
|
||||
} finally {
|
||||
// Clear loading state
|
||||
setIsLoadingSublines(prev => ({ ...prev, [rowIndex]: false }));
|
||||
}
|
||||
}, [lineSublineCache]);
|
||||
|
||||
// When data changes, fetch product lines and sublines for rows that have company/line values
|
||||
useEffect(() => {
|
||||
// Skip if there's no data
|
||||
if (!data.length) return;
|
||||
|
||||
// First check if we need to do anything at all
|
||||
let needsFetching = false;
|
||||
|
||||
// Quick check for any rows that would need fetching
|
||||
for (const row of data) {
|
||||
const rowId = row.__index;
|
||||
if (!rowId) continue;
|
||||
|
||||
if ((row.company && !rowProductLines[rowId]) || (row.line && !rowSublines[rowId])) {
|
||||
needsFetching = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing needs fetching, exit early
|
||||
if (!needsFetching) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Starting to fetch product lines and sublines");
|
||||
|
||||
// Group rows by company and line to minimize API calls
|
||||
const companiesNeeded = new Map<string, string[]>(); // company ID -> row IDs
|
||||
const linesNeeded = new Map<string, string[]>(); // line ID -> row IDs
|
||||
|
||||
data.forEach(row => {
|
||||
const rowId = row.__index;
|
||||
if (!rowId) return; // Skip rows without an index
|
||||
|
||||
// If row has company but no product lines fetched yet
|
||||
if (row.company && !rowProductLines[rowId]) {
|
||||
const companyId = row.company.toString();
|
||||
if (!companiesNeeded.has(companyId)) {
|
||||
companiesNeeded.set(companyId, []);
|
||||
}
|
||||
companiesNeeded.get(companyId)?.push(rowId);
|
||||
}
|
||||
|
||||
// If row has line but no sublines fetched yet
|
||||
if (row.line && !rowSublines[rowId]) {
|
||||
const lineId = row.line.toString();
|
||||
if (!linesNeeded.has(lineId)) {
|
||||
linesNeeded.set(lineId, []);
|
||||
}
|
||||
linesNeeded.get(lineId)?.push(rowId);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Need to fetch product lines for ${companiesNeeded.size} companies and sublines for ${linesNeeded.size} lines`);
|
||||
|
||||
// If nothing to fetch, exit early to prevent unnecessary processing
|
||||
if (companiesNeeded.size === 0 && linesNeeded.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create arrays to hold all fetch promises
|
||||
const fetchPromises: Promise<void>[] = [];
|
||||
|
||||
// Set initial loading states for all affected rows
|
||||
const lineLoadingUpdates: Record<string, boolean> = {};
|
||||
const sublineLoadingUpdates: Record<string, boolean> = {};
|
||||
|
||||
// Process companies that need product lines
|
||||
companiesNeeded.forEach((rowIds, companyId) => {
|
||||
// Skip if already in cache
|
||||
if (companyLinesCache[companyId]) {
|
||||
console.log(`Using cached product lines for company ${companyId}`);
|
||||
// Use cached data for all rows with this company
|
||||
const lines = companyLinesCache[companyId];
|
||||
const updates: Record<string, any[]> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
updates[rowId] = lines;
|
||||
});
|
||||
setRowProductLines(prev => ({ ...prev, ...updates }));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set loading state for all affected rows
|
||||
rowIds.forEach(rowId => {
|
||||
lineLoadingUpdates[rowId] = true;
|
||||
});
|
||||
|
||||
// Create fetch promise
|
||||
const fetchPromise = (async () => {
|
||||
// Safety timeout to ensure loading state is cleared after 10 seconds
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.log(`Safety timeout triggered for company ${companyId}`);
|
||||
const clearLoadingUpdates: Record<string, boolean> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
clearLoadingUpdates[rowId] = false;
|
||||
});
|
||||
setIsLoadingLines(prev => ({ ...prev, ...clearLoadingUpdates }));
|
||||
|
||||
// Set empty cache to prevent repeated requests
|
||||
setCompanyLinesCache(prev => ({ ...prev, [companyId]: [] }));
|
||||
|
||||
// Update rows with empty array
|
||||
const updates: Record<string, any[]> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
updates[rowId] = [];
|
||||
});
|
||||
setRowProductLines(prev => ({ ...prev, ...updates }));
|
||||
|
||||
toast.error(`Timeout loading product lines for company ${companyId}`);
|
||||
}, 10000);
|
||||
|
||||
try {
|
||||
console.log(`Fetching product lines for company ${companyId} (affecting ${rowIds.length} rows)`);
|
||||
|
||||
// Fetch product lines from API
|
||||
const productLinesUrl = `/api/import/product-lines/${companyId}`;
|
||||
console.log(`Fetching from URL: ${productLinesUrl}`);
|
||||
|
||||
const response = await axios.get(productLinesUrl);
|
||||
console.log(`Product lines API response status for company ${companyId}:`, response.status);
|
||||
|
||||
const productLines = response.data;
|
||||
console.log(`Received ${productLines.length} product lines for company ${companyId}`);
|
||||
|
||||
// Store in company cache
|
||||
setCompanyLinesCache(prev => ({ ...prev, [companyId]: productLines }));
|
||||
|
||||
// Update all rows with this company
|
||||
const updates: Record<string, any[]> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
updates[rowId] = productLines;
|
||||
});
|
||||
setRowProductLines(prev => ({ ...prev, ...updates }));
|
||||
} catch (error) {
|
||||
console.error(`Error fetching product lines for company ${companyId}:`, error);
|
||||
|
||||
// Set empty array for this company to prevent repeated failed requests
|
||||
setCompanyLinesCache(prev => ({ ...prev, [companyId]: [] }));
|
||||
|
||||
// Update rows with empty array
|
||||
const updates: Record<string, any[]> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
updates[rowId] = [];
|
||||
});
|
||||
setRowProductLines(prev => ({ ...prev, ...updates }));
|
||||
|
||||
// Show error toast
|
||||
toast.error(`Failed to load product lines for company ${companyId}`);
|
||||
} finally {
|
||||
// Clear the safety timeout
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
// Clear loading state for all affected rows
|
||||
const clearLoadingUpdates: Record<string, boolean> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
clearLoadingUpdates[rowId] = false;
|
||||
});
|
||||
setIsLoadingLines(prev => ({ ...prev, ...clearLoadingUpdates }));
|
||||
}
|
||||
})();
|
||||
|
||||
fetchPromises.push(fetchPromise);
|
||||
});
|
||||
|
||||
// Process lines that need sublines
|
||||
linesNeeded.forEach((rowIds, lineId) => {
|
||||
// Skip if already in cache
|
||||
if (lineSublineCache[lineId]) {
|
||||
console.log(`Using cached sublines for line ${lineId}`);
|
||||
// Use cached data for all rows with this line
|
||||
const sublines = lineSublineCache[lineId];
|
||||
const updates: Record<string, any[]> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
updates[rowId] = sublines;
|
||||
});
|
||||
setRowSublines(prev => ({ ...prev, ...updates }));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set loading state for all affected rows
|
||||
rowIds.forEach(rowId => {
|
||||
sublineLoadingUpdates[rowId] = true;
|
||||
});
|
||||
|
||||
// Create fetch promise
|
||||
const fetchPromise = (async () => {
|
||||
// Safety timeout to ensure loading state is cleared after 10 seconds
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.log(`Safety timeout triggered for line ${lineId}`);
|
||||
const clearLoadingUpdates: Record<string, boolean> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
clearLoadingUpdates[rowId] = false;
|
||||
});
|
||||
setIsLoadingSublines(prev => ({ ...prev, ...clearLoadingUpdates }));
|
||||
|
||||
// Set empty cache to prevent repeated requests
|
||||
setLineSublineCache(prev => ({ ...prev, [lineId]: [] }));
|
||||
|
||||
// Update rows with empty array
|
||||
const updates: Record<string, any[]> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
updates[rowId] = [];
|
||||
});
|
||||
setRowSublines(prev => ({ ...prev, ...updates }));
|
||||
|
||||
toast.error(`Timeout loading sublines for line ${lineId}`);
|
||||
}, 10000);
|
||||
|
||||
try {
|
||||
console.log(`Fetching sublines for line ${lineId} (affecting ${rowIds.length} rows)`);
|
||||
|
||||
// Fetch sublines from API
|
||||
const sublinesUrl = `/api/import/sublines/${lineId}`;
|
||||
console.log(`Fetching from URL: ${sublinesUrl}`);
|
||||
|
||||
const response = await axios.get(sublinesUrl);
|
||||
console.log(`Sublines API response status for line ${lineId}:`, response.status);
|
||||
|
||||
const sublines = response.data;
|
||||
console.log(`Received ${sublines.length} sublines for line ${lineId}`);
|
||||
|
||||
// Store in line cache
|
||||
setLineSublineCache(prev => ({ ...prev, [lineId]: sublines }));
|
||||
|
||||
// Update all rows with this line
|
||||
const updates: Record<string, any[]> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
updates[rowId] = sublines;
|
||||
});
|
||||
setRowSublines(prev => ({ ...prev, ...updates }));
|
||||
} catch (error) {
|
||||
console.error(`Error fetching sublines for line ${lineId}:`, error);
|
||||
|
||||
// Set empty array for this line to prevent repeated failed requests
|
||||
setLineSublineCache(prev => ({ ...prev, [lineId]: [] }));
|
||||
|
||||
// Update rows with empty array
|
||||
const updates: Record<string, any[]> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
updates[rowId] = [];
|
||||
});
|
||||
setRowSublines(prev => ({ ...prev, ...updates }));
|
||||
|
||||
// Show error toast
|
||||
toast.error(`Failed to load sublines for line ${lineId}`);
|
||||
} finally {
|
||||
// Clear the safety timeout
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
// Clear loading state for all affected rows
|
||||
const clearLoadingUpdates: Record<string, boolean> = {};
|
||||
rowIds.forEach(rowId => {
|
||||
clearLoadingUpdates[rowId] = false;
|
||||
});
|
||||
setIsLoadingSublines(prev => ({ ...prev, ...clearLoadingUpdates }));
|
||||
}
|
||||
})();
|
||||
|
||||
fetchPromises.push(fetchPromise);
|
||||
});
|
||||
|
||||
// Set initial loading states
|
||||
if (Object.keys(lineLoadingUpdates).length > 0) {
|
||||
console.log(`Setting loading state for ${Object.keys(lineLoadingUpdates).length} rows (product lines)`);
|
||||
setIsLoadingLines(prev => ({ ...prev, ...lineLoadingUpdates }));
|
||||
}
|
||||
if (Object.keys(sublineLoadingUpdates).length > 0) {
|
||||
console.log(`Setting loading state for ${Object.keys(sublineLoadingUpdates).length} rows (sublines)`);
|
||||
setIsLoadingSublines(prev => ({ ...prev, ...sublineLoadingUpdates }));
|
||||
}
|
||||
|
||||
// Run all fetch operations in parallel
|
||||
Promise.all(fetchPromises).then(() => {
|
||||
console.log("All product lines and sublines fetch operations completed");
|
||||
}).catch(error => {
|
||||
console.error('Error in fetch operations:', error);
|
||||
});
|
||||
|
||||
}, [data, rowProductLines, rowSublines, companyLinesCache, lineSublineCache]);
|
||||
|
||||
return {
|
||||
rowProductLines,
|
||||
rowSublines,
|
||||
isLoadingLines,
|
||||
isLoadingSublines,
|
||||
fetchProductLines,
|
||||
fetchSublines
|
||||
};
|
||||
};
|
||||
@@ -82,13 +82,11 @@ export const useTemplates = <T extends string>(
|
||||
}
|
||||
|
||||
// Remove metadata fields
|
||||
delete (template as any).__errors
|
||||
delete (template as any).__meta
|
||||
delete (template as any).__template
|
||||
delete (template as any).__original
|
||||
delete (template as any).__corrected
|
||||
delete (template as any).__changes
|
||||
delete (template as any).__index
|
||||
|
||||
// Send to API
|
||||
const response = await fetch(`${getApiUrl()}/templates`, {
|
||||
|
||||
@@ -1,27 +1,41 @@
|
||||
import { useState, useCallback, useRef } from 'react'
|
||||
import { useState, useCallback, useRef, useEffect } from 'react'
|
||||
import config from '@/config'
|
||||
|
||||
interface UpcValidationResult {
|
||||
error?: boolean
|
||||
message?: string
|
||||
data?: Record<string, any>
|
||||
}
|
||||
|
||||
interface ValidationState {
|
||||
validatingCells: Set<string>; // Using rowIndex-fieldKey as identifier
|
||||
itemNumbers: Map<number, string>; // Using rowIndex as key
|
||||
validatingRows: Set<number>; // Rows currently being validated
|
||||
activeValidations: Set<string>; // Active validations
|
||||
}
|
||||
|
||||
export const useUpcValidation = () => {
|
||||
export const useUpcValidation = (
|
||||
data: any[],
|
||||
setData: (updater: any[] | ((prevData: any[]) => any[])) => void
|
||||
) => {
|
||||
// Use a ref for validation state to avoid triggering re-renders
|
||||
const validationStateRef = useRef<ValidationState>({
|
||||
validatingCells: new Set(),
|
||||
itemNumbers: new Map()
|
||||
itemNumbers: new Map(),
|
||||
validatingRows: new Set(),
|
||||
activeValidations: new Set()
|
||||
});
|
||||
|
||||
// Use state only for forcing re-renders of specific cells
|
||||
const [validatingCellKeys, setValidatingCellKeys] = useState<Set<string>>(new Set());
|
||||
const [itemNumberUpdates, setItemNumberUpdates] = useState<Map<number, string>>(new Map());
|
||||
const [, setValidatingCellKeys] = useState<Set<string>>(new Set());
|
||||
const [, setItemNumberUpdates] = useState<Map<number, string>>(new Map());
|
||||
const [validatingRows, setValidatingRows] = useState<Set<number>>(new Set());
|
||||
const [, setIsValidatingUpc] = useState(false);
|
||||
|
||||
// Cache for UPC validation results
|
||||
const processedUpcMapRef = useRef(new Map<string, string>());
|
||||
const initialUpcValidationDoneRef = useRef(false);
|
||||
|
||||
// For batch validation
|
||||
const validationQueueRef = useRef<Array<{rowIndex: number, supplierId: string, upcValue: string}>>([]);
|
||||
const isProcessingBatchRef = useRef(false);
|
||||
|
||||
// For validation results
|
||||
const [upcValidationResults] = useState<Map<number, { itemNumber: string }>>(new Map());
|
||||
|
||||
// Helper to create cell key
|
||||
const getCellKey = (rowIndex: number, fieldKey: string) => `${rowIndex}-${fieldKey}`;
|
||||
@@ -42,83 +56,462 @@ export const useUpcValidation = () => {
|
||||
|
||||
// Update item number
|
||||
const updateItemNumber = useCallback((rowIndex: number, itemNumber: string) => {
|
||||
console.log(`Setting item number for row ${rowIndex} to ${itemNumber}`);
|
||||
validationStateRef.current.itemNumbers.set(rowIndex, itemNumber);
|
||||
setItemNumberUpdates(new Map(validationStateRef.current.itemNumbers));
|
||||
}, []);
|
||||
|
||||
// Mark a row as being validated
|
||||
const startValidatingRow = useCallback((rowIndex: number) => {
|
||||
validationStateRef.current.validatingRows.add(rowIndex);
|
||||
setValidatingRows(new Set(validationStateRef.current.validatingRows));
|
||||
setIsValidatingUpc(true);
|
||||
}, []);
|
||||
|
||||
// Mark a row as no longer being validated
|
||||
const stopValidatingRow = useCallback((rowIndex: number) => {
|
||||
validationStateRef.current.validatingRows.delete(rowIndex);
|
||||
setValidatingRows(new Set(validationStateRef.current.validatingRows));
|
||||
|
||||
// If no more rows are being validated, set global validation state to false
|
||||
if (validationStateRef.current.validatingRows.size === 0) {
|
||||
setIsValidatingUpc(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Check if a specific cell is being validated
|
||||
const isValidatingCell = useCallback((rowIndex: number, fieldKey: string): boolean => {
|
||||
return validationStateRef.current.validatingCells.has(getCellKey(rowIndex, fieldKey));
|
||||
}, []);
|
||||
|
||||
// Check if a specific row is being validated
|
||||
const isRowValidatingUpc = useCallback((rowIndex: number): boolean => {
|
||||
return validationStateRef.current.validatingRows.has(rowIndex);
|
||||
}, []);
|
||||
|
||||
// Get item number for a row
|
||||
const getItemNumber = useCallback((rowIndex: number): string | undefined => {
|
||||
return validationStateRef.current.itemNumbers.get(rowIndex);
|
||||
}, []);
|
||||
|
||||
// Validate a UPC value
|
||||
const validateUpc = useCallback(async (
|
||||
upcValue: string,
|
||||
rowIndex: number,
|
||||
supplier: string
|
||||
): Promise<UpcValidationResult> => {
|
||||
// Start validating UPC and item number cells
|
||||
startValidatingCell(rowIndex, 'upc');
|
||||
startValidatingCell(rowIndex, 'item_number');
|
||||
|
||||
// Fetch product by UPC from API
|
||||
const fetchProductByUpc = useCallback(async (supplierId: string, upcValue: string) => {
|
||||
try {
|
||||
// Call the UPC validation API
|
||||
const response = await fetch(`${config.apiUrl}/import/check-upc-and-generate-sku?upc=${encodeURIComponent(upcValue)}&supplierId=${encodeURIComponent(supplier)}`);
|
||||
console.log(`Fetching product for UPC ${upcValue} with supplier ${supplierId}`);
|
||||
const response = await fetch(`${config.apiUrl}/import/check-upc-and-generate-sku?upc=${encodeURIComponent(upcValue)}&supplierId=${encodeURIComponent(supplierId)}`);
|
||||
|
||||
// Handle error responses
|
||||
if (response.status === 409) {
|
||||
const errorData = await response.json();
|
||||
return {
|
||||
error: true,
|
||||
message: `UPC already exists (${errorData.existingItemNumber})`,
|
||||
data: errorData
|
||||
};
|
||||
console.log(`UPC ${upcValue} already exists`);
|
||||
return { error: true, message: 'UPC already exists' };
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API error (${response.status})`);
|
||||
console.error(`API error: ${response.status}`);
|
||||
return { error: true, message: `API error (${response.status})` };
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
// Process successful response
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.success) {
|
||||
return { error: true, message: data.message || 'Unknown error' };
|
||||
}
|
||||
|
||||
if (result.success && result.itemNumber) {
|
||||
// Update item number in our state
|
||||
updateItemNumber(rowIndex, result.itemNumber);
|
||||
return {
|
||||
error: false,
|
||||
data: {
|
||||
itemNumber: result.itemNumber,
|
||||
...result
|
||||
itemNumber: data.itemNumber || '',
|
||||
...data
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
error: true,
|
||||
message: 'Invalid response from server'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error validating UPC:', error);
|
||||
return {
|
||||
error: true,
|
||||
message: 'Failed to validate UPC'
|
||||
};
|
||||
} finally {
|
||||
// Stop validating both cells
|
||||
stopValidatingCell(rowIndex, 'upc');
|
||||
stopValidatingCell(rowIndex, 'item_number');
|
||||
console.error('Network error:', error);
|
||||
return { error: true, message: 'Network error' };
|
||||
}
|
||||
}, [startValidatingCell, stopValidatingCell, updateItemNumber]);
|
||||
}, []);
|
||||
|
||||
// Validate a UPC for a row - returns a promise that resolves when complete
|
||||
const validateUpc = useCallback(async (rowIndex: number, supplierId: string, upcValue: string) => {
|
||||
// Clear any previous validation keys for this row to avoid cancellations
|
||||
const previousKeys = Array.from(validationStateRef.current.activeValidations).filter(key =>
|
||||
key.startsWith(`${rowIndex}-`)
|
||||
);
|
||||
previousKeys.forEach(key => validationStateRef.current.activeValidations.delete(key));
|
||||
|
||||
// Start validation - track this with the ref to avoid race conditions
|
||||
startValidatingRow(rowIndex);
|
||||
startValidatingCell(rowIndex, 'item_number');
|
||||
|
||||
console.log(`Validating UPC: rowIndex=${rowIndex}, supplierId=${supplierId}, upc=${upcValue}`);
|
||||
|
||||
try {
|
||||
// Create a unique key for this validation to track it
|
||||
const validationKey = `${rowIndex}-${supplierId}-${upcValue}`;
|
||||
validationStateRef.current.activeValidations.add(validationKey);
|
||||
|
||||
// IMPORTANT: First update the data with the new UPC value to prevent UI flicker
|
||||
// This ensures the UPC field keeps showing the new value while validation runs
|
||||
setData(prevData => {
|
||||
const newData = [...prevData];
|
||||
if (newData[rowIndex]) {
|
||||
newData[rowIndex] = {
|
||||
...newData[rowIndex],
|
||||
upc: upcValue
|
||||
};
|
||||
}
|
||||
return newData;
|
||||
});
|
||||
|
||||
// Fetch the product by UPC
|
||||
const product = await fetchProductByUpc(supplierId, upcValue);
|
||||
|
||||
// Check if this validation is still relevant (hasn't been superseded by another)
|
||||
if (!validationStateRef.current.activeValidations.has(validationKey)) {
|
||||
console.log(`Validation ${validationKey} was cancelled`);
|
||||
return { success: false };
|
||||
}
|
||||
|
||||
// Extract the item number from the API response - check for !error since API returns { error: boolean, data: any }
|
||||
if (product && !product.error && product.data?.itemNumber) {
|
||||
// Store this validation result
|
||||
updateItemNumber(rowIndex, product.data.itemNumber);
|
||||
|
||||
return {
|
||||
validateUpc,
|
||||
isValidatingCell,
|
||||
getItemNumber,
|
||||
itemNumbers: itemNumberUpdates,
|
||||
validatingCells: validatingCellKeys
|
||||
success: true,
|
||||
itemNumber: product.data.itemNumber
|
||||
};
|
||||
} else {
|
||||
// No item number found but validation was still attempted
|
||||
console.log(`No item number found for UPC ${upcValue}`);
|
||||
|
||||
// Clear any existing item number to show validation was attempted and failed
|
||||
if (validationStateRef.current.itemNumbers.has(rowIndex)) {
|
||||
validationStateRef.current.itemNumbers.delete(rowIndex);
|
||||
setItemNumberUpdates(new Map(validationStateRef.current.itemNumbers));
|
||||
}
|
||||
}
|
||||
|
||||
return { success: false };
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error validating UPC:', error);
|
||||
return { success: false };
|
||||
} finally {
|
||||
// End validation
|
||||
stopValidatingRow(rowIndex);
|
||||
stopValidatingCell(rowIndex, 'item_number');
|
||||
}
|
||||
}, [fetchProductByUpc, updateItemNumber, startValidatingCell, stopValidatingCell, startValidatingRow, stopValidatingRow, setData]);
|
||||
|
||||
// Apply item numbers to data
|
||||
const applyItemNumbersToData = useCallback((onApplied?: (updatedRowIds: number[]) => void) => {
|
||||
// Create a copy of the current item numbers map to avoid race conditions
|
||||
const currentItemNumbers = new Map(validationStateRef.current.itemNumbers);
|
||||
|
||||
// Only apply if we have any item numbers
|
||||
if (currentItemNumbers.size === 0) return;
|
||||
|
||||
// Track updated row indices to pass to callback
|
||||
const updatedRowIndices: number[] = [];
|
||||
|
||||
// Log for debugging
|
||||
console.log(`Applying ${currentItemNumbers.size} item numbers to data`);
|
||||
|
||||
setData(prevData => {
|
||||
// Create a new copy of the data
|
||||
const newData = [...prevData];
|
||||
|
||||
// Update each row with its item number without affecting other fields
|
||||
currentItemNumbers.forEach((itemNumber, rowIndex) => {
|
||||
if (rowIndex < newData.length) {
|
||||
console.log(`Setting item_number for row ${rowIndex} to ${itemNumber}`);
|
||||
|
||||
// Only update the item_number field, leaving other fields unchanged
|
||||
newData[rowIndex] = {
|
||||
...newData[rowIndex],
|
||||
item_number: itemNumber
|
||||
};
|
||||
|
||||
// Track which rows were updated
|
||||
updatedRowIndices.push(rowIndex);
|
||||
}
|
||||
});
|
||||
|
||||
return newData;
|
||||
});
|
||||
|
||||
// Call the callback if provided, after state updates are processed
|
||||
if (onApplied && updatedRowIndices.length > 0) {
|
||||
// Use setTimeout to ensure this happens after the state update
|
||||
setTimeout(() => {
|
||||
onApplied(updatedRowIndices);
|
||||
}, 100); // Use 100ms to ensure the data update is fully processed
|
||||
}
|
||||
}, [setData]);
|
||||
|
||||
// Process validation queue in batches - faster processing with smaller batches
|
||||
const processBatchValidation = useCallback(async () => {
|
||||
if (isProcessingBatchRef.current) return;
|
||||
if (validationQueueRef.current.length === 0) return;
|
||||
|
||||
console.log(`Processing validation batch with ${validationQueueRef.current.length} items`);
|
||||
isProcessingBatchRef.current = true;
|
||||
|
||||
// Process in smaller batches for better UI responsiveness
|
||||
const BATCH_SIZE = 5;
|
||||
const queue = [...validationQueueRef.current];
|
||||
validationQueueRef.current = [];
|
||||
|
||||
// Track if any updates were made
|
||||
let updatesApplied = false;
|
||||
|
||||
// Track updated row indices
|
||||
const updatedRows: number[] = [];
|
||||
|
||||
try {
|
||||
// Process in small batches
|
||||
for (let i = 0; i < queue.length; i += BATCH_SIZE) {
|
||||
const batch = queue.slice(i, i + BATCH_SIZE);
|
||||
|
||||
// Process batch in parallel
|
||||
const results = await Promise.all(batch.map(async ({ rowIndex, supplierId, upcValue }) => {
|
||||
try {
|
||||
// Skip if already validated
|
||||
const cacheKey = `${supplierId}-${upcValue}`;
|
||||
if (processedUpcMapRef.current.has(cacheKey)) {
|
||||
const cachedItemNumber = processedUpcMapRef.current.get(cacheKey);
|
||||
if (cachedItemNumber) {
|
||||
console.log(`Using cached item number for row ${rowIndex}: ${cachedItemNumber}`);
|
||||
updateItemNumber(rowIndex, cachedItemNumber);
|
||||
updatesApplied = true;
|
||||
updatedRows.push(rowIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fetch from API
|
||||
const result = await fetchProductByUpc(supplierId, upcValue);
|
||||
|
||||
if (!result.error && result.data?.itemNumber) {
|
||||
const itemNumber = result.data.itemNumber;
|
||||
|
||||
// Store in cache
|
||||
processedUpcMapRef.current.set(cacheKey, itemNumber);
|
||||
|
||||
// Update item number
|
||||
updateItemNumber(rowIndex, itemNumber);
|
||||
updatesApplied = true;
|
||||
updatedRows.push(rowIndex);
|
||||
|
||||
console.log(`Set item number for row ${rowIndex} to ${itemNumber}`);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error(`Error processing row ${rowIndex}:`, error);
|
||||
return false;
|
||||
} finally {
|
||||
// Clear validation state
|
||||
stopValidatingRow(rowIndex);
|
||||
}
|
||||
}));
|
||||
|
||||
// If any updates were applied in this batch, update the data
|
||||
if (results.some(Boolean) && updatesApplied) {
|
||||
applyItemNumbersToData(updatedRowIds => {
|
||||
console.log(`Processed batch UPC validation for rows: ${updatedRowIds.join(', ')}`);
|
||||
});
|
||||
updatesApplied = false;
|
||||
updatedRows.length = 0; // Clear the array
|
||||
}
|
||||
|
||||
// Small delay between batches to allow UI to update
|
||||
if (i + BATCH_SIZE < queue.length) {
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in batch processing:', error);
|
||||
} finally {
|
||||
isProcessingBatchRef.current = false;
|
||||
|
||||
// Process any new items
|
||||
if (validationQueueRef.current.length > 0) {
|
||||
setTimeout(processBatchValidation, 0);
|
||||
}
|
||||
}
|
||||
}, [fetchProductByUpc, updateItemNumber, stopValidatingRow, applyItemNumbersToData]);
|
||||
|
||||
// For immediate processing
|
||||
|
||||
// Batch validate all UPCs in the data
|
||||
const validateAllUPCs = useCallback(async () => {
|
||||
// Skip if we've already done the initial validation
|
||||
if (initialUpcValidationDoneRef.current) {
|
||||
console.log('Initial UPC validation already done, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark that we've started the initial validation
|
||||
initialUpcValidationDoneRef.current = true;
|
||||
|
||||
console.log('Starting initial UPC validation...');
|
||||
|
||||
// Set validation state
|
||||
setIsValidatingUpc(true);
|
||||
|
||||
// Find all rows that have both supplier and UPC/barcode
|
||||
const rowsToValidate = data
|
||||
.map((row, index) => ({ row, index }))
|
||||
.filter(({ row }) => {
|
||||
const rowAny = row as Record<string, any>;
|
||||
const hasSupplier = rowAny.supplier;
|
||||
const hasUpc = rowAny.upc || rowAny.barcode;
|
||||
return hasSupplier && hasUpc;
|
||||
});
|
||||
|
||||
const totalRows = rowsToValidate.length;
|
||||
console.log(`Found ${totalRows} rows with both supplier and UPC for initial validation`);
|
||||
|
||||
if (totalRows === 0) {
|
||||
setIsValidatingUpc(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark all rows as being validated
|
||||
const newValidatingRows = new Set(rowsToValidate.map(({ index }) => index));
|
||||
validationStateRef.current.validatingRows = newValidatingRows;
|
||||
setValidatingRows(newValidatingRows);
|
||||
|
||||
try {
|
||||
// Process rows in batches for better UX
|
||||
const BATCH_SIZE = 100;
|
||||
const batches = [];
|
||||
|
||||
// Split rows into batches
|
||||
for (let i = 0; i < rowsToValidate.length; i += BATCH_SIZE) {
|
||||
batches.push(rowsToValidate.slice(i, i + BATCH_SIZE));
|
||||
}
|
||||
|
||||
console.log(`Processing ${batches.length} batches for ${totalRows} rows`);
|
||||
|
||||
// Process each batch sequentially
|
||||
for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {
|
||||
const batch = batches[batchIndex];
|
||||
console.log(`Processing batch ${batchIndex + 1}/${batches.length} with ${batch.length} rows`);
|
||||
|
||||
// Track updated rows in this batch
|
||||
const batchUpdatedRows: number[] = [];
|
||||
|
||||
// Process all rows in current batch in parallel
|
||||
await Promise.all(
|
||||
batch.map(async ({ row, index }) => {
|
||||
try {
|
||||
const rowAny = row as Record<string, any>;
|
||||
const supplierId = rowAny.supplier.toString();
|
||||
const upcValue = (rowAny.upc || rowAny.barcode).toString();
|
||||
|
||||
console.log(`Validating UPC in initial batch: row=${index}, supplier=${supplierId}, upc=${upcValue}`);
|
||||
|
||||
// Mark the item_number cell as validating
|
||||
startValidatingCell(index, 'item_number');
|
||||
|
||||
// Validate the UPC directly (don't use validateUpc to avoid duplicate UI updates)
|
||||
const cacheKey = `${supplierId}-${upcValue}`;
|
||||
|
||||
// Check cache first
|
||||
if (processedUpcMapRef.current.has(cacheKey)) {
|
||||
const cachedItemNumber = processedUpcMapRef.current.get(cacheKey);
|
||||
if (cachedItemNumber) {
|
||||
console.log(`Using cached item number for row ${index}: ${cachedItemNumber}`);
|
||||
updateItemNumber(index, cachedItemNumber);
|
||||
batchUpdatedRows.push(index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Make API call
|
||||
const result = await fetchProductByUpc(supplierId, upcValue);
|
||||
|
||||
if (!result.error && result.data?.itemNumber) {
|
||||
const itemNumber = result.data.itemNumber;
|
||||
console.log(`Got item number from API for row ${index}: ${itemNumber}`);
|
||||
|
||||
// Cache the result
|
||||
processedUpcMapRef.current.set(cacheKey, itemNumber);
|
||||
|
||||
// Update item number
|
||||
updateItemNumber(index, itemNumber);
|
||||
batchUpdatedRows.push(index);
|
||||
} else {
|
||||
console.warn(`No item number found for row ${index} UPC ${upcValue}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error validating row ${index}:`, error);
|
||||
} finally {
|
||||
// Clear validation state
|
||||
stopValidatingCell(index, 'item_number');
|
||||
stopValidatingRow(index);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Apply updates for this batch
|
||||
if (validationStateRef.current.itemNumbers.size > 0) {
|
||||
console.log(`Applying item numbers after batch ${batchIndex + 1}`);
|
||||
applyItemNumbersToData(updatedRowIds => {
|
||||
console.log(`Processed initial UPC validation batch ${batchIndex + 1} for rows: ${updatedRowIds.join(', ')}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Small delay between batches to update UI
|
||||
if (batchIndex < batches.length - 1) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in batch validation:', error);
|
||||
} finally {
|
||||
// Make sure all validation states are cleared
|
||||
validationStateRef.current.validatingRows.clear();
|
||||
setValidatingRows(new Set());
|
||||
setIsValidatingUpc(false);
|
||||
|
||||
console.log('Completed initial UPC validation');
|
||||
}
|
||||
}, [data, fetchProductByUpc, updateItemNumber, startValidatingCell, stopValidatingCell, stopValidatingRow, applyItemNumbersToData]);
|
||||
|
||||
// Run initial UPC validation when data changes
|
||||
useEffect(() => {
|
||||
// Skip if there's no data or we've already done the validation
|
||||
if (data.length === 0 || initialUpcValidationDoneRef.current) return;
|
||||
|
||||
// Run validation
|
||||
validateAllUPCs();
|
||||
}, [data, validateAllUPCs]);
|
||||
|
||||
// Return public API
|
||||
return {
|
||||
// Validation methods
|
||||
validateUpc,
|
||||
validateAllUPCs,
|
||||
|
||||
// Cell state
|
||||
isValidatingCell,
|
||||
isRowValidatingUpc,
|
||||
|
||||
// Row state
|
||||
validatingRows: validatingRows, // Expose as a Set to components
|
||||
|
||||
// Item number management
|
||||
getItemNumber,
|
||||
applyItemNumbersToData,
|
||||
|
||||
// Results
|
||||
upcValidationResults,
|
||||
|
||||
// Initialization state
|
||||
initialValidationDone: initialUpcValidationDoneRef.current
|
||||
};
|
||||
};
|
||||
@@ -1,18 +1,16 @@
|
||||
import { useCallback } from 'react'
|
||||
import type { Field, Fields, RowHook, TableHook } from '../../../types'
|
||||
import type { Meta } from '../types'
|
||||
import { ErrorSources } from '../../../types'
|
||||
import { ErrorSources, ErrorType, ValidationError } from '../../../types'
|
||||
import { RowData } from './useValidationState'
|
||||
|
||||
interface ValidationError {
|
||||
message: string
|
||||
level: 'info' | 'warning' | 'error'
|
||||
}
|
||||
|
||||
interface InfoWithSource {
|
||||
message: string
|
||||
level: 'info' | 'warning' | 'error'
|
||||
source: ErrorSources
|
||||
// Define InfoWithSource to match the expected structure
|
||||
// Make sure source is required (not optional)
|
||||
export interface InfoWithSource {
|
||||
message: string;
|
||||
level: 'info' | 'warning' | 'error';
|
||||
source: ErrorSources;
|
||||
type: ErrorType;
|
||||
}
|
||||
|
||||
// Shared utility function for checking empty values - defined once to avoid duplication
|
||||
@@ -23,6 +21,40 @@ const isEmpty = (value: any): boolean =>
|
||||
(Array.isArray(value) && value.length === 0) ||
|
||||
(typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0);
|
||||
|
||||
// Cache validation results to avoid running expensive validations repeatedly
|
||||
const validationResultCache = new Map<string, ValidationError[]>();
|
||||
|
||||
// Add debounce to prevent rapid successive validations
|
||||
let validateDataTimeoutId: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
// Add a function to clear cache for a specific field value
|
||||
export const clearValidationCacheForField = (fieldKey: string, value: any) => {
|
||||
// Create a pattern to match cache keys for this field
|
||||
const pattern = new RegExp(`^${fieldKey}-`);
|
||||
|
||||
// Find and clear matching cache entries
|
||||
validationResultCache.forEach((_, key) => {
|
||||
if (pattern.test(key)) {
|
||||
validationResultCache.delete(key);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Add a special function to clear all uniqueness validation caches
|
||||
export const clearAllUniquenessCaches = () => {
|
||||
// Clear cache for common unique fields
|
||||
['item_number', 'upc', 'barcode', 'supplier_no', 'notions_no'].forEach(fieldKey => {
|
||||
clearValidationCacheForField(fieldKey, null);
|
||||
});
|
||||
|
||||
// Also clear any cache entries that might involve uniqueness validation
|
||||
validationResultCache.forEach((_, key) => {
|
||||
if (key.includes('unique')) {
|
||||
validationResultCache.delete(key);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useValidation = <T extends string>(
|
||||
fields: Fields<T>,
|
||||
rowHook?: RowHook<T>,
|
||||
@@ -37,6 +69,14 @@ export const useValidation = <T extends string>(
|
||||
|
||||
if (!field.validations) return errors
|
||||
|
||||
// Create a cache key using field key, value, and validation rules
|
||||
const cacheKey = `${field.key}-${String(value)}-${JSON.stringify(field.validations)}`;
|
||||
|
||||
// Check cache first to avoid redundant validation
|
||||
if (validationResultCache.has(cacheKey)) {
|
||||
return validationResultCache.get(cacheKey) || [];
|
||||
}
|
||||
|
||||
field.validations.forEach(validation => {
|
||||
switch (validation.rule) {
|
||||
case 'required':
|
||||
@@ -44,7 +84,8 @@ export const useValidation = <T extends string>(
|
||||
if (isEmpty(value)) {
|
||||
errors.push({
|
||||
message: validation.errorMessage || 'This field is required',
|
||||
level: validation.level || 'error'
|
||||
level: validation.level || 'error',
|
||||
type: ErrorType.Required
|
||||
})
|
||||
}
|
||||
break
|
||||
@@ -60,7 +101,8 @@ export const useValidation = <T extends string>(
|
||||
if (!regex.test(String(value))) {
|
||||
errors.push({
|
||||
message: validation.errorMessage,
|
||||
level: validation.level || 'error'
|
||||
level: validation.level || 'error',
|
||||
type: ErrorType.Regex
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -71,6 +113,9 @@ export const useValidation = <T extends string>(
|
||||
}
|
||||
})
|
||||
|
||||
// Store results in cache to speed up future validations
|
||||
validationResultCache.set(cacheKey, errors);
|
||||
|
||||
return errors
|
||||
}, [])
|
||||
|
||||
@@ -98,56 +143,38 @@ export const useValidation = <T extends string>(
|
||||
if (fields.some(field => String(field.key) === 'supplier') && isEmpty(row.supplier)) {
|
||||
fieldErrors['supplier'] = [{
|
||||
message: 'Supplier is required',
|
||||
level: 'error'
|
||||
level: 'error',
|
||||
type: ErrorType.Required
|
||||
}]
|
||||
}
|
||||
|
||||
if (fields.some(field => String(field.key) === 'company') && isEmpty(row.company)) {
|
||||
fieldErrors['company'] = [{
|
||||
message: 'Company is required',
|
||||
level: 'error'
|
||||
level: 'error',
|
||||
type: ErrorType.Required
|
||||
}]
|
||||
}
|
||||
|
||||
// Run row hook if provided
|
||||
let rowHookResult: Meta = {
|
||||
__index: row.__index || String(rowIndex),
|
||||
__errors: {}
|
||||
__index: row.__index || String(rowIndex)
|
||||
}
|
||||
if (rowHook) {
|
||||
try {
|
||||
rowHookResult = await rowHook(row, rowIndex, allRows)
|
||||
// Call the row hook and extract only the __index property
|
||||
const result = await rowHook(row, rowIndex, allRows);
|
||||
rowHookResult.__index = result.__index || rowHookResult.__index;
|
||||
} catch (error) {
|
||||
console.error('Error in row hook:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Merge field errors and row hook errors
|
||||
const mergedErrors: Record<string, InfoWithSource> = {}
|
||||
|
||||
// Convert field errors to InfoWithSource
|
||||
Object.entries(fieldErrors).forEach(([key, errors]) => {
|
||||
if (errors.length > 0) {
|
||||
mergedErrors[key] = {
|
||||
message: errors[0].message,
|
||||
level: errors[0].level,
|
||||
source: ErrorSources.Row
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Merge row hook errors
|
||||
if (rowHookResult.__errors) {
|
||||
Object.entries(rowHookResult.__errors).forEach(([key, error]) => {
|
||||
if (error) {
|
||||
mergedErrors[key] = error
|
||||
}
|
||||
})
|
||||
}
|
||||
// We no longer need to merge errors since we're not storing them in the row data
|
||||
// The calling code should handle storing errors in the validationErrors Map
|
||||
|
||||
return {
|
||||
__index: row.__index || String(rowIndex),
|
||||
__errors: mergedErrors
|
||||
__index: row.__index || String(rowIndex)
|
||||
}
|
||||
}, [fields, validateField, rowHook])
|
||||
|
||||
@@ -155,8 +182,7 @@ export const useValidation = <T extends string>(
|
||||
const validateTable = useCallback(async (data: RowData<T>[]): Promise<Meta[]> => {
|
||||
if (!tableHook) {
|
||||
return data.map((row, index) => ({
|
||||
__index: row.__index || String(index),
|
||||
__errors: {}
|
||||
__index: row.__index || String(index)
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -165,159 +191,333 @@ export const useValidation = <T extends string>(
|
||||
|
||||
// Process table validation results
|
||||
return tableResults.map((result, index) => {
|
||||
// Ensure errors are properly formatted
|
||||
const formattedErrors: Record<string, InfoWithSource> = {}
|
||||
|
||||
if (result.__errors) {
|
||||
Object.entries(result.__errors).forEach(([key, error]) => {
|
||||
if (error) {
|
||||
formattedErrors[key] = {
|
||||
...error,
|
||||
source: ErrorSources.Table
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
__index: result.__index || data[index].__index || String(index),
|
||||
__errors: formattedErrors
|
||||
__index: result.__index || data[index].__index || String(index)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error in table hook:', error)
|
||||
return data.map((row, index) => ({
|
||||
__index: row.__index || String(index),
|
||||
__errors: {}
|
||||
__index: row.__index || String(index)
|
||||
}))
|
||||
}
|
||||
}, [tableHook])
|
||||
|
||||
// Validate unique fields across the table
|
||||
const validateUnique = useCallback((data: RowData<T>[]) => {
|
||||
const uniqueErrors: Meta[] = data.map((row, index) => ({
|
||||
__index: row.__index || String(index),
|
||||
__errors: {}
|
||||
}))
|
||||
// Create a map to store errors for each row
|
||||
const uniqueErrors = new Map<number, Record<string, InfoWithSource>>();
|
||||
|
||||
// Find fields with unique validation
|
||||
const uniqueFields = fields.filter(field =>
|
||||
field.validations?.some(v => v.rule === 'unique')
|
||||
)
|
||||
);
|
||||
|
||||
if (uniqueFields.length === 0) {
|
||||
return uniqueErrors
|
||||
return uniqueErrors;
|
||||
}
|
||||
|
||||
// Check each unique field
|
||||
uniqueFields.forEach(field => {
|
||||
const { key } = field
|
||||
const validation = field.validations?.find(v => v.rule === 'unique')
|
||||
const allowEmpty = validation?.allowEmpty ?? false
|
||||
const errorMessage = validation?.errorMessage || `${field.label} must be unique`
|
||||
const level = validation?.level || 'error'
|
||||
const { key } = field;
|
||||
const validation = field.validations?.find(v => v.rule === 'unique');
|
||||
const allowEmpty = validation?.allowEmpty ?? false;
|
||||
const errorMessage = validation?.errorMessage || `${field.label} must be unique`;
|
||||
const level = validation?.level || 'error';
|
||||
|
||||
// Track values for uniqueness check
|
||||
const valueMap = new Map<string, number[]>()
|
||||
const valueMap = new Map<string, number[]>();
|
||||
|
||||
// Build value map
|
||||
data.forEach((row, rowIndex) => {
|
||||
const value = String(row[String(key) as keyof typeof row] || '')
|
||||
const value = String(row[String(key) as keyof typeof row] || '');
|
||||
|
||||
// Skip empty values if allowed
|
||||
if (allowEmpty && isEmpty(value)) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
if (!valueMap.has(value)) {
|
||||
valueMap.set(value, [rowIndex])
|
||||
valueMap.set(value, [rowIndex]);
|
||||
} else {
|
||||
valueMap.get(value)?.push(rowIndex)
|
||||
valueMap.get(value)?.push(rowIndex);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Add errors for duplicate values
|
||||
valueMap.forEach((rowIndexes) => {
|
||||
if (rowIndexes.length > 1) {
|
||||
// Add error to all duplicate rows
|
||||
rowIndexes.forEach(rowIndex => {
|
||||
const rowErrors = uniqueErrors[rowIndex].__errors || {}
|
||||
// Get existing errors for this row or create a new object
|
||||
const rowErrors = uniqueErrors.get(rowIndex) || {};
|
||||
|
||||
rowErrors[String(key)] = {
|
||||
message: errorMessage,
|
||||
level,
|
||||
source: ErrorSources.Table
|
||||
source: ErrorSources.Table,
|
||||
type: ErrorType.Unique
|
||||
};
|
||||
|
||||
uniqueErrors.set(rowIndex, rowErrors);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return uniqueErrors;
|
||||
}, [fields]);
|
||||
|
||||
// Additional function to explicitly validate uniqueness for specified fields
|
||||
const validateUniqueField = useCallback((data: RowData<T>[], fieldKey: string) => {
|
||||
// Field keys that need special handling for uniqueness
|
||||
const uniquenessFields = ['item_number', 'upc', 'barcode', 'supplier_no', 'notions_no'];
|
||||
|
||||
// If the field doesn't need uniqueness validation, return empty errors
|
||||
if (!uniquenessFields.includes(fieldKey)) {
|
||||
const field = fields.find(f => String(f.key) === fieldKey);
|
||||
if (!field || !field.validations?.some(v => v.rule === 'unique')) {
|
||||
return new Map<number, Record<string, InfoWithSource>>();
|
||||
}
|
||||
}
|
||||
|
||||
uniqueErrors[rowIndex].__errors = rowErrors
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
// Create map to track errors
|
||||
const uniqueErrors = new Map<number, Record<string, InfoWithSource>>();
|
||||
|
||||
return uniqueErrors
|
||||
}, [fields])
|
||||
// Find the field definition
|
||||
const field = fields.find(f => String(f.key) === fieldKey);
|
||||
if (!field) return uniqueErrors;
|
||||
|
||||
// Get validation properties
|
||||
const validation = field.validations?.find(v => v.rule === 'unique');
|
||||
const allowEmpty = validation?.allowEmpty ?? false;
|
||||
const errorMessage = validation?.errorMessage || `${field.label} must be unique`;
|
||||
const level = validation?.level || 'error';
|
||||
|
||||
// Track values for uniqueness check
|
||||
const valueMap = new Map<string, number[]>();
|
||||
|
||||
// Build value map
|
||||
data.forEach((row, rowIndex) => {
|
||||
const value = String(row[fieldKey as keyof typeof row] || '');
|
||||
|
||||
// Skip empty values if allowed
|
||||
if (allowEmpty && isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!valueMap.has(value)) {
|
||||
valueMap.set(value, [rowIndex]);
|
||||
} else {
|
||||
valueMap.get(value)?.push(rowIndex);
|
||||
}
|
||||
});
|
||||
|
||||
// Add errors for duplicate values
|
||||
valueMap.forEach((rowIndexes, value) => {
|
||||
if (rowIndexes.length > 1) {
|
||||
// Skip empty values
|
||||
if (!value || value.trim() === '') return;
|
||||
|
||||
// Add error to all duplicate rows
|
||||
rowIndexes.forEach(rowIndex => {
|
||||
// Create errors object if needed
|
||||
if (!uniqueErrors.has(rowIndex)) {
|
||||
uniqueErrors.set(rowIndex, {});
|
||||
}
|
||||
|
||||
// Add error for this field
|
||||
uniqueErrors.get(rowIndex)![fieldKey] = {
|
||||
message: errorMessage,
|
||||
level: level as 'info' | 'warning' | 'error',
|
||||
source: ErrorSources.Table,
|
||||
type: ErrorType.Unique
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return uniqueErrors;
|
||||
}, [fields]);
|
||||
|
||||
// Run complete validation
|
||||
const validateData = useCallback(async (data: RowData<T>[]) => {
|
||||
// Use the shared isEmpty function
|
||||
const validateData = useCallback(async (data: RowData<T>[], fieldToUpdate?: { rowIndex: number, fieldKey: string }) => {
|
||||
const validationErrors = new Map<number, Record<string, InfoWithSource>>();
|
||||
|
||||
// Step 1: Run field and row validation
|
||||
const rowValidations = await Promise.all(
|
||||
data.map((row, index) => validateRow(row, index, data))
|
||||
)
|
||||
// If we're updating a specific field, only validate that field for that row
|
||||
if (fieldToUpdate) {
|
||||
const { rowIndex, fieldKey } = fieldToUpdate;
|
||||
|
||||
// Step 2: Run unique validations
|
||||
const uniqueValidations = validateUnique(data)
|
||||
// Special handling for fields that often update item_number
|
||||
const triggersItemNumberValidation = fieldKey === 'upc' || fieldKey === 'barcode' || fieldKey === 'supplier';
|
||||
|
||||
// Step 3: Run table hook
|
||||
const tableValidations = await validateTable(data)
|
||||
// If updating a uniqueness field or field that affects item_number, clear ALL related validation caches
|
||||
const isUniqueField = fieldKey === 'upc' || fieldKey === 'item_number' ||
|
||||
fieldKey === 'supplier_no' || fieldKey === 'notions_no' ||
|
||||
fieldKey === 'name' || triggersItemNumberValidation;
|
||||
|
||||
// Merge all validation results
|
||||
return data.map((row, index) => {
|
||||
const rowValidation = rowValidations[index]
|
||||
const uniqueValidation = uniqueValidations[index]
|
||||
const tableValidation = tableValidations[index]
|
||||
// Force cache clearing for uniqueness-validated fields to ensure fresh validation
|
||||
if (isUniqueField) {
|
||||
console.log(`Clearing validation cache for uniqueness field: ${fieldKey}`);
|
||||
clearValidationCacheForField(fieldKey, null);
|
||||
|
||||
// Start with the original data
|
||||
const newRow = { ...row }
|
||||
|
||||
// Combine all errors
|
||||
const combinedErrors = {
|
||||
...(rowValidation.__errors || {}),
|
||||
...(uniqueValidation.__errors || {}),
|
||||
...(tableValidation.__errors || {})
|
||||
// If a field that might affect item_number, also clear item_number cache
|
||||
if (triggersItemNumberValidation) {
|
||||
console.log('Also clearing item_number validation cache');
|
||||
clearValidationCacheForField('item_number', null);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out "required" errors for fields that have values
|
||||
const filteredErrors: Record<string, InfoWithSource> = {}
|
||||
if (rowIndex >= 0 && rowIndex < data.length) {
|
||||
const row = data[rowIndex];
|
||||
|
||||
Object.entries(combinedErrors).forEach(([key, error]) => {
|
||||
const fieldValue = row[key as keyof typeof row]
|
||||
// Find the field definition
|
||||
const field = fields.find(f => String(f.key) === fieldKey);
|
||||
|
||||
// If the field has a value and the only error is "required", skip it
|
||||
if (!isEmpty(fieldValue) &&
|
||||
error &&
|
||||
typeof error === 'object' &&
|
||||
'message' in error &&
|
||||
error.message?.toLowerCase().includes('required')) {
|
||||
return
|
||||
if (field) {
|
||||
// Validate just this field for this row
|
||||
const value = row[fieldKey as keyof typeof row];
|
||||
const errors = validateField(value, field as Field<T>);
|
||||
|
||||
if (errors.length > 0) {
|
||||
// Store the validation error
|
||||
validationErrors.set(rowIndex, {
|
||||
[fieldKey]: {
|
||||
message: errors[0].message,
|
||||
level: errors[0].level as 'info' | 'warning' | 'error',
|
||||
source: ErrorSources.Row,
|
||||
type: errors[0].type
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
filteredErrors[key] = error as InfoWithSource
|
||||
})
|
||||
// Check if the field requires uniqueness validation or if it's item_number after UPC/Supplier change
|
||||
const needsUniquenessCheck = isUniqueField ||
|
||||
field.validations?.some(v => v.rule === 'unique');
|
||||
|
||||
newRow.__errors = Object.keys(filteredErrors).length > 0 ? filteredErrors : undefined
|
||||
if (needsUniquenessCheck) {
|
||||
console.log(`Running immediate uniqueness validation for field ${fieldKey}`);
|
||||
|
||||
return newRow
|
||||
})
|
||||
}, [validateRow, validateUnique, validateTable])
|
||||
// For item_number updated via UPC validation, or direct UPC update, check both fields
|
||||
if (fieldKey === 'item_number' || fieldKey === 'upc' || fieldKey === 'barcode') {
|
||||
// Validate both item_number and UPC/barcode fields for uniqueness
|
||||
const itemNumberUniqueErrors = validateUniqueField(data, 'item_number');
|
||||
const upcUniqueErrors = validateUniqueField(data, fieldKey === 'item_number' ? 'upc' : fieldKey);
|
||||
|
||||
// Combine the errors
|
||||
itemNumberUniqueErrors.forEach((errors, rowIdx) => {
|
||||
if (!validationErrors.has(rowIdx)) {
|
||||
validationErrors.set(rowIdx, {});
|
||||
}
|
||||
Object.assign(validationErrors.get(rowIdx)!, errors);
|
||||
});
|
||||
|
||||
upcUniqueErrors.forEach((errors, rowIdx) => {
|
||||
if (!validationErrors.has(rowIdx)) {
|
||||
validationErrors.set(rowIdx, {});
|
||||
}
|
||||
Object.assign(validationErrors.get(rowIdx)!, errors);
|
||||
});
|
||||
} else {
|
||||
// Normal uniqueness validation for other fields
|
||||
const uniqueErrors = validateUniqueField(data, fieldKey);
|
||||
|
||||
// Add unique errors to validation errors
|
||||
uniqueErrors.forEach((errors, rowIdx) => {
|
||||
if (!validationErrors.has(rowIdx)) {
|
||||
validationErrors.set(rowIdx, {});
|
||||
}
|
||||
Object.assign(validationErrors.get(rowIdx)!, errors);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Full validation - all fields for all rows
|
||||
console.log('Running full validation for all fields and rows');
|
||||
|
||||
// Clear validation cache for full validation
|
||||
validationResultCache.clear();
|
||||
|
||||
// Process each row for field-level validations
|
||||
for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
|
||||
const row = data[rowIndex];
|
||||
let rowErrors: Record<string, InfoWithSource> = {};
|
||||
|
||||
// Validate all fields for this row
|
||||
fields.forEach(field => {
|
||||
const fieldKey = String(field.key);
|
||||
const value = row[fieldKey as keyof typeof row];
|
||||
const errors = validateField(value, field as Field<T>);
|
||||
|
||||
if (errors.length > 0) {
|
||||
rowErrors[fieldKey] = {
|
||||
message: errors[0].message,
|
||||
level: errors[0].level as 'info' | 'warning' | 'error',
|
||||
source: ErrorSources.Row,
|
||||
type: errors[0].type
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Add row to validationErrors if it has any errors
|
||||
if (Object.keys(rowErrors).length > 0) {
|
||||
validationErrors.set(rowIndex, rowErrors);
|
||||
}
|
||||
}
|
||||
|
||||
// Get fields requiring uniqueness validation
|
||||
const uniqueFields = fields.filter(field =>
|
||||
field.validations?.some(v => v.rule === 'unique')
|
||||
);
|
||||
|
||||
// Also add standard unique fields that might not be explicitly marked as unique
|
||||
const standardUniqueFields = ['item_number', 'upc', 'barcode', 'supplier_no', 'notions_no'];
|
||||
|
||||
// Combine all fields that need uniqueness validation
|
||||
const allUniqueFieldKeys = new Set([
|
||||
...uniqueFields.map(field => String(field.key)),
|
||||
...standardUniqueFields
|
||||
]);
|
||||
|
||||
// Log uniqueness validation fields
|
||||
console.log('Validating unique fields:', Array.from(allUniqueFieldKeys));
|
||||
|
||||
// Run uniqueness validation for each unique field
|
||||
allUniqueFieldKeys.forEach(fieldKey => {
|
||||
// Check if this field exists in the data
|
||||
const hasField = data.some(row => fieldKey in row);
|
||||
if (!hasField) return;
|
||||
|
||||
const uniqueErrors = validateUniqueField(data, fieldKey);
|
||||
|
||||
// Add unique errors to validation errors
|
||||
uniqueErrors.forEach((errors, rowIdx) => {
|
||||
if (!validationErrors.has(rowIdx)) {
|
||||
validationErrors.set(rowIdx, {});
|
||||
}
|
||||
Object.assign(validationErrors.get(rowIdx)!, errors);
|
||||
});
|
||||
});
|
||||
|
||||
console.log('Uniqueness validation complete');
|
||||
}
|
||||
|
||||
return {
|
||||
data,
|
||||
validationErrors
|
||||
};
|
||||
}, [fields, validateField, validateUniqueField]);
|
||||
|
||||
return {
|
||||
validateData,
|
||||
validateField,
|
||||
validateRow,
|
||||
validateTable,
|
||||
validateUnique
|
||||
validateUnique,
|
||||
validateUniqueField,
|
||||
clearValidationCacheForField,
|
||||
clearAllUniquenessCaches
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
import { InfoWithSource } from "../../types"
|
||||
|
||||
export type Meta = { __index: string; __errors?: Error | null }
|
||||
export type Meta = { __index: string }
|
||||
export type Error = { [key: string]: InfoWithSource }
|
||||
export type Errors = { [id: string]: Error }
|
||||
@@ -1,16 +1,17 @@
|
||||
import { InfoWithSource, ErrorLevel } from "../../../types"
|
||||
import { ErrorLevel, ErrorSources, ErrorType as ValidationErrorType } from "../../../types"
|
||||
|
||||
// Define our own Error type that's compatible with the original
|
||||
export interface ErrorType {
|
||||
message: string;
|
||||
level: ErrorLevel;
|
||||
source?: string;
|
||||
source?: ErrorSources;
|
||||
type: ValidationErrorType;
|
||||
}
|
||||
|
||||
// Export a namespace to make it accessible at runtime
|
||||
export const ErrorTypes = {
|
||||
createError: (message: string, level: ErrorLevel = 'error', source: string = 'row'): ErrorType => {
|
||||
return { message, level, source };
|
||||
createError: (message: string, level: ErrorLevel = 'error', source: ErrorSources = ErrorSources.Row, type: ValidationErrorType = ValidationErrorType.Custom): ErrorType => {
|
||||
return { message, level, source, type };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,5 +21,4 @@ export interface Errors { [id: string]: ErrorType[] }
|
||||
// Make our Meta type match the original for compatibility
|
||||
export interface Meta {
|
||||
__index?: string;
|
||||
__errors?: Record<string, ErrorType[] | ErrorType | InfoWithSource | InfoWithSource[] | null>;
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
import type { Data, Fields, Info, RowHook, TableHook } from "../../../types"
|
||||
import type { Meta, Error, Errors } from "../types"
|
||||
import type { Meta, Errors } from "../types"
|
||||
import { v4 } from "uuid"
|
||||
import { ErrorSources } from "../../../types"
|
||||
import { ErrorSources, ErrorType } from "../../../types"
|
||||
|
||||
|
||||
type DataWithMeta<T extends string> = Data<T> & Meta & {
|
||||
__index?: string;
|
||||
__errors?: Error | null;
|
||||
}
|
||||
|
||||
export const addErrorsAndRunHooks = async <T extends string>(
|
||||
@@ -18,10 +17,10 @@ export const addErrorsAndRunHooks = async <T extends string>(
|
||||
): Promise<DataWithMeta<T>[]> => {
|
||||
const errors: Errors = {}
|
||||
|
||||
const addError = (source: ErrorSources, rowIndex: number, fieldKey: string, error: Info) => {
|
||||
const addError = (source: ErrorSources, rowIndex: number, fieldKey: string, error: Info, type: ErrorType = ErrorType.Custom) => {
|
||||
errors[rowIndex] = {
|
||||
...errors[rowIndex],
|
||||
[fieldKey]: { ...error, source },
|
||||
[fieldKey]: { ...error, source, type },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +88,7 @@ export const addErrorsAndRunHooks = async <T extends string>(
|
||||
addError(ErrorSources.Table, index, fieldKey, {
|
||||
level: validation.level || "error",
|
||||
message: validation.errorMessage || "Field must be unique",
|
||||
})
|
||||
}, ErrorType.Unique)
|
||||
}
|
||||
})
|
||||
break
|
||||
@@ -103,7 +102,7 @@ export const addErrorsAndRunHooks = async <T extends string>(
|
||||
addError(ErrorSources.Row, realIndex, fieldKey, {
|
||||
level: validation.level || "error",
|
||||
message: validation.errorMessage || "Field is required",
|
||||
})
|
||||
}, ErrorType.Required)
|
||||
}
|
||||
})
|
||||
break
|
||||
@@ -120,7 +119,7 @@ export const addErrorsAndRunHooks = async <T extends string>(
|
||||
level: validation.level || "error",
|
||||
message:
|
||||
validation.errorMessage || `Field did not match the regex /${validation.value}/${validation.flags} `,
|
||||
})
|
||||
}, ErrorType.Regex)
|
||||
}
|
||||
})
|
||||
break
|
||||
@@ -129,48 +128,15 @@ export const addErrorsAndRunHooks = async <T extends string>(
|
||||
})
|
||||
})
|
||||
|
||||
return processedData.map((value, index) => {
|
||||
return processedData.map((value) => {
|
||||
// This is required only for table. Mutates to prevent needless rerenders
|
||||
const result: DataWithMeta<T> = { ...value }
|
||||
if (!result.__index) {
|
||||
result.__index = v4()
|
||||
}
|
||||
|
||||
// If we are validating all indexes, or we did full validation on this row - apply all errors
|
||||
if (!changedRowIndexes || changedRowIndexes.includes(index)) {
|
||||
if (errors[index]) {
|
||||
return { ...result, __errors: errors[index] }
|
||||
}
|
||||
|
||||
if (!errors[index] && result.__errors) {
|
||||
return { ...result, __errors: null }
|
||||
}
|
||||
}
|
||||
// if we have not validated this row, keep it's row errors but apply global error changes
|
||||
else {
|
||||
// at this point errors[index] contains only table source errors, previous row and table errors are in value.__errors
|
||||
const hasRowErrors =
|
||||
result.__errors && Object.values(result.__errors).some((error) => error.source === ErrorSources.Row)
|
||||
|
||||
if (!hasRowErrors) {
|
||||
if (errors[index]) {
|
||||
return { ...result, __errors: errors[index] }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const errorsWithoutTableError = Object.entries(result.__errors!).reduce((acc, [key, value]) => {
|
||||
if (value.source === ErrorSources.Row) {
|
||||
acc[key] = value
|
||||
}
|
||||
return acc
|
||||
}, {} as Error)
|
||||
|
||||
const newErrors = { ...errorsWithoutTableError, ...errors[index] }
|
||||
|
||||
return { ...result, __errors: newErrors }
|
||||
}
|
||||
|
||||
// We no longer store errors in the row data
|
||||
// The errors are now only stored in the validationErrors Map
|
||||
return result
|
||||
})
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Field, Data, ErrorSources } from '../../../types'
|
||||
import { ErrorType } from '../types/index'
|
||||
import { Field, Data, ErrorSources, ErrorType as ValidationErrorType } from '../../../types'
|
||||
import { ErrorType } from '../types'
|
||||
|
||||
/**
|
||||
* Formats a price value to a consistent format
|
||||
@@ -80,17 +80,20 @@ export const validateRegex = (value: any, regex: string, flags?: string): boolea
|
||||
* @param message Error message
|
||||
* @param level Error level
|
||||
* @param source Error source
|
||||
* @param type Error type
|
||||
* @returns Error object
|
||||
*/
|
||||
export const createError = (
|
||||
message: string,
|
||||
level: 'info' | 'warning' | 'error' = 'error',
|
||||
source: ErrorSources = ErrorSources.Row
|
||||
source: ErrorSources = ErrorSources.Row,
|
||||
type: ValidationErrorType = ValidationErrorType.Custom
|
||||
): ErrorType => {
|
||||
return {
|
||||
message,
|
||||
level,
|
||||
source
|
||||
source,
|
||||
type
|
||||
} as ErrorType
|
||||
}
|
||||
|
||||
@@ -136,7 +139,8 @@ export const validateSpecialFields = <T extends string>(row: Data<T>): Record<st
|
||||
errors['supplier'] = [{
|
||||
message: 'Supplier is required',
|
||||
level: 'error',
|
||||
source: ErrorSources.Row
|
||||
source: ErrorSources.Row,
|
||||
type: ValidationErrorType.Required
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -145,7 +149,8 @@ export const validateSpecialFields = <T extends string>(row: Data<T>): Record<st
|
||||
errors['company'] = [{
|
||||
message: 'Company is required',
|
||||
level: 'error',
|
||||
source: ErrorSources.Row
|
||||
source: ErrorSources.Row,
|
||||
type: ValidationErrorType.Required
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
@@ -163,18 +163,38 @@ export type Info = {
|
||||
}
|
||||
|
||||
export enum ErrorSources {
|
||||
Table = "table",
|
||||
Row = "row",
|
||||
Row = 'row',
|
||||
Table = 'table',
|
||||
Api = 'api',
|
||||
Upc = 'upc'
|
||||
}
|
||||
|
||||
// Add a standardized error type enum
|
||||
export enum ErrorType {
|
||||
Required = 'required',
|
||||
Regex = 'regex',
|
||||
Unique = 'unique',
|
||||
Custom = 'custom',
|
||||
Api = 'api'
|
||||
}
|
||||
|
||||
// Add a standardized error interface
|
||||
export interface ValidationError {
|
||||
message: string;
|
||||
level: 'info' | 'warning' | 'error';
|
||||
source?: ErrorSources;
|
||||
type: ErrorType;
|
||||
}
|
||||
|
||||
/*
|
||||
Source determines whether the error is from the full table or row validation
|
||||
Table validation is tableHook and "unique" validation
|
||||
Row validation is rowHook and all other validations
|
||||
it is used to determine if row.__errors should be updated or not depending on different validations
|
||||
It is used to determine how errors should be stored in the validationErrors Map
|
||||
*/
|
||||
export type InfoWithSource = Info & {
|
||||
source: ErrorSources
|
||||
source: ErrorSources;
|
||||
type: ErrorType;
|
||||
}
|
||||
|
||||
export type Result<T extends string> = {
|
||||
|
||||
@@ -40,7 +40,7 @@ const BASE_IMPORT_FIELDS = [
|
||||
description: "Product line",
|
||||
alternateMatches: ["collection"],
|
||||
fieldType: {
|
||||
type: "select",
|
||||
type: "select" as const,
|
||||
options: [], // Will be populated dynamically based on company selection
|
||||
},
|
||||
width: 220,
|
||||
@@ -51,7 +51,7 @@ const BASE_IMPORT_FIELDS = [
|
||||
key: "subline",
|
||||
description: "Product sub-line",
|
||||
fieldType: {
|
||||
type: "select",
|
||||
type: "select" as const,
|
||||
options: [], // Will be populated dynamically based on line selection
|
||||
},
|
||||
width: 220,
|
||||
|
||||
@@ -8,7 +8,6 @@ import config from "../config";
|
||||
import { Loader2, Box } from "lucide-react";
|
||||
import { motion } from "motion/react";
|
||||
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
|
||||
export function Login() {
|
||||
const [username, setUsername] = useState("");
|
||||
|
||||
339
package-lock.json
generated
339
package-lock.json
generated
@@ -8,6 +8,7 @@
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@modelcontextprotocol/server-sequential-thinking": "^0.6.2",
|
||||
"diff": "^7.0.0",
|
||||
"shadcn": "^1.0.0"
|
||||
},
|
||||
@@ -69,6 +70,31 @@
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/sdk": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-0.5.0.tgz",
|
||||
"integrity": "sha512-RXgulUX6ewvxjAG0kOpLMEdXXWkzWgaoCGaA2CwNW7cQCIphjpJhjpHSiaPdVCnisjRF/0Cm9KWHUuIoeiAblQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"content-type": "^1.0.5",
|
||||
"raw-body": "^3.0.0",
|
||||
"zod": "^3.23.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/server-sequential-thinking": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/server-sequential-thinking/-/server-sequential-thinking-0.6.2.tgz",
|
||||
"integrity": "sha512-CgYRG6PPPldPk60Oi/jmPNKQ8hUg1V2rqlBRWsRvB5/QIgb+kyd6dySh0WfEoWC5kT+7avM2qDD8SKEBBHRkOQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "0.5.0",
|
||||
"chalk": "^5.3.0",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"mcp-server-sequential-thinking": "dist/index.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/diff": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/diff/-/diff-7.0.1.tgz",
|
||||
@@ -76,6 +102,101 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
|
||||
"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/content-type": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz",
|
||||
@@ -85,6 +206,88 @@
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/http-errors": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
||||
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"depd": "2.0.0",
|
||||
"inherits": "2.0.4",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"toidentifier": "1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
|
||||
"integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.6.3",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
|
||||
@@ -108,6 +311,21 @@
|
||||
"react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
|
||||
@@ -115,12 +333,62 @@
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/shadcn": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shadcn/-/shadcn-1.0.0.tgz",
|
||||
"integrity": "sha512-kCxBIBiPS83WxrWkOQHamWpr9XlLtOtOlJM6QX90h9A5xZCBMhxu4ibcNT2ZnzZLdexkYbQrnijfPKdOsZxOpA==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-essentials": {
|
||||
"version": "10.0.4",
|
||||
"resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-10.0.4.tgz",
|
||||
@@ -141,6 +409,77 @@
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.24.2",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
|
||||
"integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@modelcontextprotocol/server-sequential-thinking": "^0.6.2",
|
||||
"diff": "^7.0.0",
|
||||
"shadcn": "^1.0.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { RowData } from '@tanstack/react-table';
|
||||
import { Field } from '@/types';
|
||||
import { MemoizedCell } from '@/components/MemoizedCell';
|
||||
|
||||
// Memoize field columns with stable handlers
|
||||
const fieldColumns = useMemo(() => fields.map((field): ColumnDef<RowData<T>, any> | null => {
|
||||
// Don't filter out disabled fields, just pass the disabled state to the cell component
|
||||
|
||||
const fieldWidth = field.width || (
|
||||
field.fieldType.type === "checkbox" ? 80 :
|
||||
field.fieldType.type === "select" ? 150 :
|
||||
field.fieldType.type === "multi-select" ? 200 :
|
||||
(field.fieldType.type === "input" || field.fieldType.type === "multi-input") &&
|
||||
(field.fieldType as any).multiline ? 300 :
|
||||
150
|
||||
);
|
||||
|
||||
const fieldKey = String(field.key);
|
||||
// Get cached options for this field
|
||||
const fieldOptions = optionsCache.get(fieldKey) || [];
|
||||
|
||||
return {
|
||||
accessorKey: fieldKey,
|
||||
header: field.label || fieldKey,
|
||||
size: fieldWidth,
|
||||
cell: ({ row }) => {
|
||||
// Get row-specific options for line and subline fields
|
||||
let options = fieldOptions;
|
||||
const rowId = row.original.__index;
|
||||
|
||||
if (fieldKey === 'line' && rowId && rowProductLines[rowId]) {
|
||||
options = rowProductLines[rowId];
|
||||
} else if (fieldKey === 'subline' && rowId && rowSublines[rowId]) {
|
||||
options = rowSublines[rowId];
|
||||
}
|
||||
|
||||
// Determine if this cell is in loading state - use a clear consistent approach
|
||||
let isLoading = false;
|
||||
|
||||
// Check the validatingCells Set first (for item_number and other fields)
|
||||
const cellLoadingKey = `${row.index}-${fieldKey}`;
|
||||
if (validatingCells.has(cellLoadingKey)) {
|
||||
isLoading = true;
|
||||
}
|
||||
// Add loading state for line/subline fields
|
||||
else if (fieldKey === 'line' && rowId && isLoadingLines[rowId]) {
|
||||
isLoading = true;
|
||||
}
|
||||
else if (fieldKey === 'subline' && rowId && isLoadingSublines[rowId]) {
|
||||
isLoading = true;
|
||||
}
|
||||
|
||||
// Get validation errors for this cell
|
||||
const cellErrors = validationErrors.get(row.index)?.[fieldKey] || [];
|
||||
|
||||
// Create a copy of the field with guaranteed field type for select fields
|
||||
let fieldWithType = field;
|
||||
|
||||
// Ensure line and subline fields always have the correct fieldType
|
||||
if (fieldKey === 'line' || fieldKey === 'subline') {
|
||||
fieldWithType = {
|
||||
...field,
|
||||
fieldType: {
|
||||
type: 'select',
|
||||
options: options
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<MemoizedCell
|
||||
field={fieldWithType as Field<string>}
|
||||
value={row.original[field.key as keyof typeof row.original]}
|
||||
onChange={(value) => handleFieldUpdate(row.index, field.key as T, value)}
|
||||
errors={cellErrors}
|
||||
isValidating={isLoading}
|
||||
fieldKey={fieldKey}
|
||||
options={options}
|
||||
itemNumber={itemNumbers.get(row.index)}
|
||||
width={fieldWidth}
|
||||
rowIndex={row.index}
|
||||
copyDown={(endRowIndex?: number) => handleCopyDown(row.index, field.key as string, endRowIndex)}
|
||||
totalRows={data.length}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
}).filter((col): col is ColumnDef<RowData<T>, any> => col !== null),
|
||||
[fields, validationErrors, validatingCells, itemNumbers, handleFieldUpdate, handleCopyDown, optionsCache, data.length, rowProductLines, rowSublines, isLoadingLines, isLoadingSublines]);
|
||||
Reference in New Issue
Block a user