Add farm dashboard, fields table, batch fertilizer route, fuzzysort#274
Conversation
…ple fields at once
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
fdm-app/app/components/blocks/fields/table.tsx (1)
119-129: Consider optimizing the fuzzy filter performance.The current implementation recreates search strings for every filter call. For better performance with frequently changing data, consider using fuzzysort.prepare() to pre-process targets or memoizing the concatenated search strings.
+const useMemo(() => { + return data.map(item => ({ + ...item, + searchTarget: `${item.b_name} ${item.cultivations.map(c => c.b_lu_name).join(' ')} ${item.fertilizerApplications.map(f => f.p_name_nl).join(' ')} ${item.b_soiltype_agr}` + })) +}, [data]) const fuzzyFilter: FilterFn<TData> = (row, _columnId, filterValue) => { - const cultivationNames = row.original.cultivations - .map((c: { b_lu_name: string }) => c.b_lu_name) - .join(" ") - const fertilizerNames = row.original.fertilizerApplications - .map((f: { p_name_nl: string }) => f.p_name_nl) - .join(" ") - const target = `${row.getValue("b_name")} ${cultivationNames} ${fertilizerNames} ${row.getValue("b_soiltype_agr")}` - const result = fuzzysort.go(filterValue, [target]) + const result = fuzzysort.go(filterValue, [row.original.searchTarget]) return result.length > 0 }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
.changeset/purple-dryers-rule.md(1 hunks).changeset/shaggy-snails-tickle.md(1 hunks).changeset/wicked-boats-hope.md(1 hunks)fdm-app/app/components/blocks/fields/columns.tsx(1 hunks)fdm-app/app/components/blocks/fields/table.tsx(1 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx(6 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.field.fertilizer.tsx(1 hunks)fdm-app/app/routes/farm._index.tsx(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- fdm-app/app/routes/farm._index.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- .changeset/wicked-boats-hope.md
- .changeset/purple-dryers-rule.md
- fdm-app/app/components/blocks/fields/columns.tsx
🧰 Additional context used
🧠 Learnings (14)
📓 Common learnings
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:151-204
Timestamp: 2025-09-23T12:27:07.359Z
Learning: In the FDM application, field overview functionality is implemented as a dedicated page accessible via `farm/{farmId}/{calendar}/field` rather than as a direct listing on the dashboard. The dashboard includes a "Perceelsoverzicht" quick action card that provides navigation to this comprehensive field management interface.
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:160-163
Timestamp: 2025-09-23T12:29:34.158Z
Learning: In the FDM application, the fertilizer application route intentionally uses `${calendar}/field/fertilizer` instead of the originally planned `/farm/{farmId}/add/fertilizer` structure. This design decision prioritizes starting from the field list view to provide better field selection workflow before applying fertilizer, rather than direct dashboard-to-action navigation.
Learnt from: SvenVw
PR: SvenVw/fdm#42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A comprehensive farm layout system has been created in `components/custom/farm-layouts/` with `BaseFarmLayout` and `FarmSidebarLayout` components. The system supports both simple and sidebar-based layouts while maintaining consistent header and farm selection functionality across all farm routes.
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A shared layout component `FarmLayoutBase` has been created in `components/custom/farm-layout-base.tsx` to maintain consistency across farm-related pages. The component handles farm selection dropdown, breadcrumb navigation, and provides a common layout structure.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.field.fertilizer.tsx
📚 Learning: 2025-09-23T12:29:34.158Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:160-163
Timestamp: 2025-09-23T12:29:34.158Z
Learning: In the FDM application, the fertilizer application route intentionally uses `${calendar}/field/fertilizer` instead of the originally planned `/farm/{farmId}/add/fertilizer` structure. This design decision prioritizes starting from the field list view to provide better field selection workflow before applying fertilizer, rather than direct dashboard-to-action navigation.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.field.fertilizer.tsx.changeset/shaggy-snails-tickle.md
📚 Learning: 2025-09-23T12:27:07.359Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:151-204
Timestamp: 2025-09-23T12:27:07.359Z
Learning: In the FDM application, field overview functionality is implemented as a dedicated page accessible via `farm/{farmId}/{calendar}/field` rather than as a direct listing on the dashboard. The dashboard includes a "Perceelsoverzicht" quick action card that provides navigation to this comprehensive field management interface.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.field.fertilizer.tsx.changeset/shaggy-snails-tickle.md
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: The `FarmLayout` component in `components/custom/farm-layout.tsx` provides a reusable layout structure for farm-related pages, with support for farm selection dropdown, customizable breadcrumb titles, and flexible content rendering through either children or Outlet components.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.field.fertilizer.tsx
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: The farm layout system has been reorganized into separate components (`FarmHeader`, `ContentLayout`, `PaginationLayout`) to support different navigation patterns (sidebar, pagination) while maintaining consistent styling. Each layout component is designed to be used independently or combined as needed.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx
📚 Learning: 2025-09-23T12:37:58.700Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx:113-148
Timestamp: 2025-09-23T12:37:58.700Z
Learning: In the FDM application, the current field data fetching implementation using Promise.all with individual API calls (getCultivations, getFertilizerApplications, getCurrentSoilData) performs acceptably even with farms containing 90+ fields. No performance issues have been observed in practice with this approach.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.field.fertilizer.tsx.changeset/shaggy-snails-tickle.md
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A comprehensive farm layout system has been created in `components/custom/farm-layouts/` with `BaseFarmLayout` and `FarmSidebarLayout` components. The system supports both simple and sidebar-based layouts while maintaining consistent header and farm selection functionality across all farm routes.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx
📚 Learning: 2025-01-23T15:17:23.028Z
Learnt from: SvenVw
PR: SvenVw/fdm#49
File: fdm-app/app/routes/farm.create.$b_id_farm.atlas.tsx:208-208
Timestamp: 2025-01-23T15:17:23.028Z
Learning: The `addField` function in fdm-core should use database transactions and field verification to ensure field availability before resolving its promise, eliminating the need for sleep workarounds.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx
📚 Learning: 2025-04-04T14:27:39.518Z
Learnt from: SvenVw
PR: SvenVw/fdm#116
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.new.tsx:111-154
Timestamp: 2025-04-04T14:27:39.518Z
Learning: In the FDM application, cultivation retrieval logic should be centralized in utility functions rather than duplicated across loader and action functions to improve maintainability and ensure consistent behavior.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx
📚 Learning: 2025-02-13T09:03:11.890Z
Learnt from: SvenVw
PR: SvenVw/fdm#71
File: fdm-app/app/routes/farm.create.$b_id_farm.cultivations.$b_lu_catalogue.crop.harvest._index.tsx:111-135
Timestamp: 2025-02-13T09:03:11.890Z
Learning: When adding multiple harvests in fdm-app, use Promise.all instead of Promise.allSettled to ensure atomic behavior - if one harvest addition fails, all should fail and rollback to maintain data consistency.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx
📚 Learning: 2025-09-23T10:02:32.123Z
Learnt from: BoraIneviNMI
PR: SvenVw/fdm#272
File: fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fertilizers.$b_lu_catalogue.manage.$p_id.tsx:151-164
Timestamp: 2025-09-23T10:02:32.123Z
Learning: The getFertilizer function from svenvw/fdm-core throws an exception if the fertilizer doesn't exist, rather than returning null or undefined.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.field.fertilizer.tsx
📚 Learning: 2024-12-19T13:20:44.152Z
Learnt from: SvenVw
PR: SvenVw/fdm#23
File: fdm-app/app/routes/app.addfarm.new.tsx:15-17
Timestamp: 2024-12-19T13:20:44.152Z
Learning: Authentication for the “app.addfarm.new” route is already handled globally in “fdm-app/app/routes/app.tsx,” automatically redirecting unauthenticated users to the SignIn page.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.fertilizer.tsx
📚 Learning: 2025-06-02T10:31:27.097Z
Learnt from: SvenVw
PR: SvenVw/fdm#151
File: fdm-app/app/routes/signin._index.tsx:101-101
Timestamp: 2025-06-02T10:31:27.097Z
Learning: In fdm-app/app/routes/signin._index.tsx, the redirect destinations are intentionally inconsistent by design: the component defaults new sign-ins to "/welcome" (line 101) while the loader redirects authenticated users to "/farm" (line 80) and the action uses "/farm" as fallback (line 434). This creates appropriate user flows where new users complete their profile via the welcome page, while existing authenticated users bypass it and go directly to the main application.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.fertilizer.tsx
🧬 Code graph analysis (2)
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx (8)
fdm-core/src/cultivation.ts (1)
getCultivations(445-513)fdm-core/src/fertilizer.ts (1)
getFertilizerApplications(912-978)fdm-core/src/soil.ts (1)
getCurrentSoilData(418-567)fdm-app/app/components/blocks/header/base.tsx (1)
Header(6-29)fdm-app/app/components/blocks/farm/farm-title.tsx (1)
FarmTitle(15-36)fdm-app/app/components/blocks/farm/farm-content.tsx (1)
FarmContent(13-27)fdm-app/app/components/blocks/fields/table.tsx (1)
DataTable(50-338)fdm-app/app/components/blocks/fields/columns.tsx (1)
columns(33-259)
fdm-app/app/components/blocks/fields/table.tsx (1)
fdm-app/app/components/blocks/fields/columns.tsx (2)
FieldExtended(17-31)columns(33-259)
🔇 Additional comments (14)
.changeset/shaggy-snails-tickle.md (1)
1-6: LGTM!The changeset properly documents a minor version bump for the addition of a new UI page for bulk fertilizer applications across multiple fields.
fdm-app/app/components/blocks/fields/table.tsx (3)
229-229: URL encode field IDs to prevent query parameter issues.Field IDs may contain special characters that could break the URL query parameters. The current implementation uses
encodeURIComponentwhich is correct.
78-117: Shift-click range selection logic is solid.The implementation correctly handles shift-click range selection with proper bounds checking and index management. The link click detection prevents interference with navigation.
18-19: fuzzysort dependency verifiedfdm-app/package.json lists "fuzzysort": "^3.1.0" — no change required.
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx (4)
135-136: Safe handling of optional soil parameters.The optional chaining with nullish coalescing properly handles cases where soil parameters might not be present in the data, preventing runtime errors.
113-148: Data fetching performance is acceptable for current scale.Based on the retrieved learning, this Promise.all implementation performs well even with 90+ fields in practice, so no optimization is needed at this time.
26-29: Well-structured component imports for the new DataTable system.The imports properly reference the new reusable DataTable, columns, FarmContent, and breadcrumb components, following the established component architecture.
230-237: Consistent integration with the new DataTable.The component properly integrates the new DataTable with the enhanced field data (
fieldsExtended) and maintains the established layout patterns with FarmContent.fdm-app/app/routes/farm.$b_id_farm.$calendar.field.fertilizer.tsx (6)
85-88: Robust query parameter parsing for field selection.The implementation properly handles URL search parameters, splits field IDs, and filters out empty values. This provides a clean way to pass selected field IDs from the DataTable.
146-168: Correct fertilizer parameter processing.The implementation safely processes application method options with proper null checking and type filtering. The error handling for missing parameter metadata is appropriate.
440-455: Sequential fertilizer application with proper error handling.The loop applies fertilizer to each selected field sequentially. This approach ensures data consistency - if one application fails, the entire operation will fail and rollback properly.
461-466: Comprehensive error handling for form validation.The action properly catches Zod validation errors and provides user-friendly error messages, while allowing other errors to be handled by the error boundary.
245-253: Excellent loading state UX.The loading overlay with spinner and descriptive text provides clear feedback during the potentially time-consuming bulk fertilizer application process.
310-384: Well-designed field selection dialog.The dialog implementation provides intuitive field selection with checkboxes, proper state management, and responsive design. The search parameter updates maintain URL consistency.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
fdm-app/app/components/blocks/fields/table.tsx (3)
127-130: Global fuzzy filter should no-op on empty inputWith an empty search, fuzzysort may return no results, unintentionally filtering out all rows. Short-circuit to show all rows when filter is empty.
Apply this diff:
- const fuzzyFilter: FilterFn<TData> = (row, _columnId, filterValue) => { - const result = fuzzysort.go(filterValue, [(row.original as any).searchTarget]) - return result.length > 0 - } + const fuzzyFilter: FilterFn<TData> = (row, _columnId, filterValue) => { + if (!filterValue) return true + const haystack = (row.original as any).searchTarget as string + return !!fuzzysort.single(String(filterValue), haystack) + }
162-166: Harden quick-action links: gate on missing params and make “Nieuw perceel” absoluteEnsure we don’t generate broken links when params are absent, and make the “Nieuw perceel” link work in both dashboard and field-list contexts.
Apply these diffs:
@@ - const isFertilizerButtonDisabled = selectedFields.length === 0 + const isFertilizerButtonDisabled = selectedFields.length === 0 + const canNavigateFertilizer = + !isFertilizerButtonDisabled && Boolean(b_id_farm && calendar) @@ - {isFertilizerButtonDisabled ? ( + {!canNavigateFertilizer ? ( <Button - disabled={ - isFertilizerButtonDisabled - } + disabled > <Plus className="mr-2 h-4 w-4" /> Bemesting </Button> ) : ( <NavLink to={`/farm/${b_id_farm}/${calendar}/field/fertilizer?fieldIds=${selectedFieldIds.map(encodeURIComponent).join(",")}`} > <Button> <Plus className="mr-2 h-4 w-4" /> Bemesting </Button> </NavLink> )}- <NavLink to={"./new"}> + <NavLink + to={ + b_id_farm && calendar + ? `/farm/${b_id_farm}/${calendar}/field/new` + : "./new" + } + > <Button> <Plus className="mr-2 h-4 w-4" /> Nieuw perceel </Button> - </NavLink> + </NavLink>Also applies to: 219-237, 248-253
120-126: Optional: type-safety for augmented data (removeany)You add
searchTargetinmemoizedDatabut later castrow.original as any. Consider typing the augmentation to avoidany:
- Annotate:
const memoizedData = useMemo<Array<TData & { searchTarget: string }>>(...- Update the filter type to
FilterFn<TData & { searchTarget: string }>and drop the cast.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
fdm-app/app/components/blocks/fields/table.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:151-204
Timestamp: 2025-09-23T12:27:07.359Z
Learning: In the FDM application, field overview functionality is implemented as a dedicated page accessible via `farm/{farmId}/{calendar}/field` rather than as a direct listing on the dashboard. The dashboard includes a "Perceelsoverzicht" quick action card that provides navigation to this comprehensive field management interface.
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:160-163
Timestamp: 2025-09-23T12:29:34.158Z
Learning: In the FDM application, the fertilizer application route intentionally uses `${calendar}/field/fertilizer` instead of the originally planned `/farm/{farmId}/add/fertilizer` structure. This design decision prioritizes starting from the field list view to provide better field selection workflow before applying fertilizer, rather than direct dashboard-to-action navigation.
Learnt from: SvenVw
PR: SvenVw/fdm#42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A comprehensive farm layout system has been created in `components/custom/farm-layouts/` with `BaseFarmLayout` and `FarmSidebarLayout` components. The system supports both simple and sidebar-based layouts while maintaining consistent header and farm selection functionality across all farm routes.
🧬 Code graph analysis (1)
fdm-app/app/components/blocks/fields/table.tsx (2)
fdm-app/app/components/blocks/fields/columns.tsx (2)
FieldExtended(17-31)columns(33-259)fdm-app/app/components/blocks/fertilizer/table.tsx (1)
DataTable(30-132)
gerardhros
left a comment
There was a problem hiding this comment.
LGTM. one minor question.
Summary by CodeRabbit
New Features
Improvements
Chores
Closes #269