Add nutrient advice app#164
Conversation
🦋 Changeset detectedLatest commit: 8b7ea60 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughThis update introduces a comprehensive "nutrient advice" feature, including new React components, route modules, and utility functions for nutrient management in a farm application. It expands nutrient dose calculations, updates domain models, adds integration with an external nutrient advice API, and revises related tests. Sidebar navigation and UI elements are also enhanced to support the new functionality. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Sidebar
participant Router
participant Loader
participant NMI_API
participant UI
User->>Sidebar: Clicks "Bemestingsadvies"
Sidebar->>Router: Navigates to /farm/{farmId}/{calendar}/nutrient_advice
Router->>Loader: Calls loader with farm and field params
Loader->>NMI_API: Fetches nutrient advice (soil data, land use, centroid)
NMI_API-->>Loader: Returns nutrient advice data
Loader-->>UI: Supplies nutrient advice, doses, applications, fields, etc.
UI->>User: Renders nutrient advice cards, KPIs, navigation
Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 300000ms (3)
✨ Finishing Touches
🧪 Generate Unit Tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## development #164 +/- ##
===============================================
+ Coverage 93.07% 93.11% +0.03%
===============================================
Files 68 68
Lines 8061 8101 +40
Branches 957 967 +10
===============================================
+ Hits 7503 7543 +40
Misses 556 556
Partials 2 2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…d-nutrient-advice-app
…d-nutrient-advice-app
There was a problem hiding this comment.
Actionable comments posted: 7
🔭 Outside diff range comments (2)
fdm-app/app/components/blocks/fertilizer-applications/cards.tsx (1)
116-130: 💡 Verification agent🧩 Analysis chain
Dose property switch may desynchronise unit / label — verify and rename accordingly
dose.p_dose_panddose.p_dose_know supply the numeric values, yet the card still shows the short-nameP2O5/K2Oand the unitkg/ha.
If the underlying calculator now returns elemental P and K (rather than P₂O₅ / K₂O), we will be displaying the wrong chemical form to the user.Action:
- shortname: "P2O5", - unit: "kg/ha", + shortname: "P", + unit: "kg P/ha",and similar for K →
K/kg K/ha.(If the calculator still returns P₂O₅ & K₂O but merely renamed the fields, ignore the diff but please leave a clarifying comment so future readers don’t have to reverse-engineer this.)
🏁 Script executed:
#!/bin/bash # Search for where p_dose_p and p_dose_k are defined or referenced rg "p_dose_p" -n -A3 -B3 rg "p_dose_k" -n -A3 -B3Length of output: 16419
Clarify that p_dose_p / p_dose_k denote oxide masses (P₂O₅ / K₂O)
The calculator’s types and tests confirm that
p_dose_pandp_dose_kstill return phosphate (P₂O₅) and potassium‐oxide (K₂O) masses in kg/ha. The current shortnames are therefore correct, and the generic"kg/ha"unit paired with “P2O5” / “K2O” remains unambiguous. To avoid future confusion, please add inline comments in the cards explaining exactly what each value represents.• File: fdm-app/app/components/blocks/fertilizer-applications/cards.tsx
• Around lines 116–121:
```diff
{
title: "Fosfaat, totaal",
shortname: "P2O5",
value: dose.p_dose_p,
unit: "kg/ha",
},// dose.p_dose_p is the mass of P₂O₅ (phosphate) in kg/ha limit: undefined, advice: undefined,• Around lines 123–129: ```diff { title: "Kalium, totaal", shortname: "K2O", value: dose.p_dose_k, unit: "kg/ha", },// dose.p_dose_k is the mass of K₂O (potassium oxide) in kg/ha limit: undefined, advice: undefined,fdm-calculator/src/doses/get-dose-field.test.ts (1)
20-28: 🛠️ Refactor suggestionClose the FDM server or clean DB between tests
beforeEachspins-up a fresh server but there is no matchingafterEach/afterAllto dispose connections or wipe the test schema. Orphaned connections easily exhaust the pool when the suite scales.
Add teardown logic (e.g.await fdm.close()or DB truncate) to keep tests hermetic.
🧹 Nitpick comments (14)
fdm-app/app/integrations/nmi.ts (2)
3-3: Remove unused import to avoid dead code warnings
numberis imported fromzodbut never used.
Lean imports keep the bundle smaller and ensure linters stay quiet.-import { number, z } from "zod" +import { z } from "zod"
206-208: Returning onlyresult.data.yearmay drop valuable information
getNutrientAdvicecollapses the full API response to a singleyearvalue.
If callers later need other properties (e.g. nutrient targets, metadata), you’ll have to re-touch this integration.Consider returning
result.data(or a typed subset) and letting callers pick what they need.fdm-app/package.json (1)
29-29: Check tree-shaking impact of@radix-ui/react-progressRadix components ship both JS and optional CSS.
Confirm that unused styles are purged in production to avoid bundle bloat.
No action required if Tailwind’s purge or an equivalent setup is already in place.fdm-app/app/components/blocks/fertilizer-applications/cards.tsx (1)
28-30: Gracefully handle unknown dose values
Math.round(value)will throwNaNwhenvalueisundefined(e.g. a yet-unsupported nutrient or a failed calculation), which renders the whole component as"NaN kg/ha".A small guard prevents silent UI breakage:
- <div className="text-2xl font-bold">{`${Math.round(value)} ${unit}`}</div> + <div className="text-2xl font-bold"> + {value != null ? `${Math.round(value)} ${unit}` : "-"} + </div>fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer.tsx (1)
112-123: Returningdose.dosedrops useful details – check downstream consumers
calculateDose()returns an object that (per the new API) contains:{ dose: Dose; perApplication: Dose[]; /* … */ }By stripping it down to
dose.doseyou lose per-application breakdown and any extra metadata.
Before committing to this change, verify that no current or near-future screen (e.g. the new nutrient-advice pages) needs those details.If you still want only the aggregate values, at least rename the local variable to avoid the stutter:
- const dose = calculateDose({ … }) - … - dose: dose.dose, + const { dose: totalDose } = calculateDose({ … }) + … + dose: totalDose,fdm-app/app/components/blocks/nutrient-advice/types.d.ts (1)
1-8: Minor style nit – semicolons keep TypeScript declarations tidyType literals favour semicolons for consistency with interfaces:
-export type NutrientDescription = { - name: string, - symbol: string - type: "primary" | "secondary" | "trace", - unit: string - adviceParameter: string - doseParameter: string -} +export interface NutrientDescription { + name: string; + symbol: string; + type: "primary" | "secondary" | "trace"; + unit: string; + adviceParameter: string; + doseParameter: string; +}Purely cosmetic – ignore if you prefer the current style.
fdm-app/app/components/blocks/sidebar/apps.tsx (1)
48-56: Repeated link-construction logic – extract helper to DRY up sidebarThe
atlasLink,nutrientBalanceLink, and the newly addednutrientAdviceLinkall follow identical conditional logic. A small utility will cut the boilerplate and reduce future merge conflicts:function buildFarmLink(path: string, isCreate: boolean, farmId?: string, cal?: string) { return !isCreate && farmId ? `/farm/${farmId}/${cal}/${path}` : undefined } const atlasLink = buildFarmLink("atlas", isCreateFarmWizard, farmId, selectedCalendar) const nutrientBalanceLink = buildFarmLink("balance", isCreateFarmWizard, farmId, selectedCalendar) const nutrientAdviceLink = buildFarmLink("nutrient_advice", isCreateFarmWizard, farmId, selectedCalendar)fdm-app/app/components/blocks/nutrient-advice/nutrients.ts (2)
1-4: Export a constant instead of recreating the same array on every call
getNutrientsDescription()returns a static list; turning it into aconstavoids needless allocations and enables tree-shaking:-export function getNutrientsDescription(): NutrientDescription[] { - const nutrientDescription: NutrientDescription[] = [ +export const nutrientDescriptions: readonly NutrientDescription[] = [ … - ] - return nutrientDescription -} +] as constIf you prefer keeping the function, at least wrap the array in
useMemoat the call site.
102-108: Inconsistent language – keep nutrient names either NL or ENMost entries use Dutch labels (
Mangaan,Fosfaat) butMolybdenumis English.
For a polished UI pick one language and stick to it (Molybdeenfor Dutch).fdm-calculator/src/doses/get-dose-field.test.ts (1)
128-169: PrefertoMatchObjectover deep equality to decouple from future dose fields
toEqualdemands exact structural equality. As theDoseinterface keeps expanding (this PR already added many nutrients), new harmless fields will break this test.
Use partial matching:-expect(await getDoseForField({ fdm, principal_id, b_id })).toEqual( - expectedResult, -) +await expect( + getDoseForField({ fdm, principal_id, b_id }), +).resolves.toMatchObject(expectedResult)This keeps the assertion robust while still verifying the values you care about.
fdm-app/app/components/blocks/header/nutrient-advice.tsx (1)
53-66: Dropdown link placement may swallow pointer events
DropdownMenuCheckboxItemrenders a focusable role. Nesting a<NavLink>inside violates a11y expectations and can interfere with Radix menu event handling. Prefer the Radix-recommendedasChildpattern:-<DropdownMenuCheckboxItem …> - <NavLink to={…}>{option.b_name}</NavLink> -</DropdownMenuCheckboxItem> +<DropdownMenuCheckboxItem … asChild> + <NavLink to={…}>{option.b_name}</NavLink> +</DropdownMenuCheckboxItem>fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx (2)
127-135: Component name misaligned with route purpose
export default function FarmBalanceNitrogenBlock()suggests a nitrogen balance view, yet the route serves nutrient advice. Rename for clarity and future discoverability, e.g.FarmNutrientAdviceLayout.
83-89: Float rounding silently loses precisionRounding
b_areato one decimal inside loader leaks presentation concerns into data-layer logic. Return the raw value and let the UI format it; this prevents accidental data loss when other consumers need higher precision.fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx (1)
162-162: Remove commented console.log- // console.log(primaryNutrients)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
fdm-app/app/components/ui/progress.tsxis excluded by!fdm-app/app/components/ui/**pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (23)
.changeset/calm-candies-mix.md(1 hunks).changeset/eager-mangos-shake.md(1 hunks).changeset/solid-planes-sell.md(1 hunks)fdm-app/app/components/blocks/fertilizer-applications/cards.tsx(1 hunks)fdm-app/app/components/blocks/header/nutrient-advice.tsx(1 hunks)fdm-app/app/components/blocks/nutrient-advice/cards.tsx(1 hunks)fdm-app/app/components/blocks/nutrient-advice/kpi.tsx(1 hunks)fdm-app/app/components/blocks/nutrient-advice/nutrients.ts(1 hunks)fdm-app/app/components/blocks/nutrient-advice/types.d.ts(1 hunks)fdm-app/app/components/blocks/sidebar/apps.tsx(3 hunks)fdm-app/app/integrations/nmi.ts(2 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer.tsx(1 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx(1 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx(1 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx(1 hunks)fdm-app/app/routes/farm.create.$b_id_farm.$calendar.cultivations.$b_lu_catalogue.fertilizers.tsx(1 hunks)fdm-app/package.json(1 hunks)fdm-calculator/src/doses/calculate-dose.test.ts(1 hunks)fdm-calculator/src/doses/calculate-dose.ts(1 hunks)fdm-calculator/src/doses/d.ts(1 hunks)fdm-calculator/src/doses/get-dose-field.test.ts(2 hunks)fdm-core/src/fertilizer.test.ts(7 hunks)fdm-core/src/fertilizer.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
.changeset/solid-planes-sell.md (1)
Learnt from: SvenVw
PR: SvenVw/fdm#75
File: fdm-app/app/routes/farm.$b_id_farm.field.$b_id.fertilizer.tsx:68-71
Timestamp: 2025-02-14T09:56:37.606Z
Learning: The `calculateDose` function in `@svenvw/fdm-calculator` is a synchronous function that includes built-in validation for negative application amounts and nutrient rates.
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx (1)
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.
🧬 Code Graph Analysis (7)
fdm-app/app/components/blocks/nutrient-advice/nutrients.ts (1)
fdm-app/app/components/blocks/nutrient-advice/types.d.ts (1)
NutrientDescription(1-8)
fdm-app/app/components/blocks/nutrient-advice/kpi.tsx (3)
fdm-calculator/src/doses/d.ts (1)
Dose(21-39)fdm-app/app/components/custom/loadingspinner.tsx (1)
LoadingSpinner(13-35)fdm-app/app/components/blocks/nutrient-advice/types.d.ts (1)
NutrientDescription(1-8)
fdm-calculator/src/doses/calculate-dose.ts (2)
fdm-calculator/src/doses/d.ts (1)
Dose(21-39)fdm-core/src/db/schema.ts (1)
fertilizers(112-120)
fdm-app/app/components/blocks/nutrient-advice/cards.tsx (3)
fdm-app/app/components/blocks/nutrient-advice/types.d.ts (1)
NutrientDescription(1-8)fdm-calculator/src/doses/d.ts (1)
Dose(21-39)fdm-core/src/db/schema.ts (2)
fertilizerApplication(154-171)fertilizers(112-120)
fdm-core/src/fertilizer.ts (1)
fdm-core/src/db/schema.ts (1)
fertilizersCatalogueTypeInsert(239-240)
fdm-calculator/src/doses/calculate-dose.test.ts (1)
fdm-calculator/src/doses/calculate-dose.ts (1)
calculateDose(37-135)
fdm-app/app/components/blocks/header/nutrient-advice.tsx (1)
fdm-app/app/store/calendar.tsx (1)
useCalendarStore(11-15)
🪛 Biome (1.9.4)
fdm-app/app/integrations/nmi.ts
[error] 148-148: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
⏰ Context from checks skipped due to timeout of 300000ms (1)
- GitHub Check: calculator (22)
🔇 Additional comments (21)
.changeset/eager-mangos-shake.md (1)
5-5: Patch description update approved.The changeset accurately describes the typo fix for
p_cr_rt, aligning with the implementation changes. Ready to merge.fdm-core/src/fertilizer.ts (1)
127-127: Typo correction in fertilizer properties parameter.Changed property key from
pr_cr_rttop_cr_rtmatches the schema and ensures consistency across the API.fdm-core/src/fertilizer.test.ts (7)
123-123: Corrected test property key top_cr_rt.Typo fix aligns test data with the updated implementation.
198-198: Corrected test property key top_cr_rt.Typo fix aligns test data with the updated implementation.
273-273: Corrected test property key top_cr_rt.Typo fix aligns test data with the updated implementation.
361-361: Corrected test property key top_cr_rt.Typo fix aligns test data with the updated implementation.
457-457: Corrected test property key top_cr_rt.Typo fix aligns test data with the updated implementation.
671-671: Corrected test property key top_cr_rt.Typo fix aligns test data with the updated implementation.
785-785: Corrected test property key top_cr_rt.Typo fix aligns test data with the updated implementation.
fdm-app/app/routes/farm.create.$b_id_farm.$calendar.cultivations.$b_lu_catalogue.fertilizers.tsx (1)
135-146: Verify downstream expectations after narrowing loader outputThe loader now exposes
dose: dose.dose.
Ensure that every consumer (hereFertilizerApplicationsCards) indeed expects the flattenedDoseobject and no longer relies on the per-application details that were previously available ondose.applications.If any component still expects the richer structure this change will silently break UI rendering.
.changeset/calm-candies-mix.md (1)
1-6: Changeset looks goodSemantic version bump and description are clear.
.changeset/solid-planes-sell.md (1)
1-6: Changeset looks goodMinor bump matches the API surface change in
calculateDose.fdm-app/app/components/blocks/nutrient-advice/nutrients.ts (1)
54-60: Unit mismatch: Calcium expressed askg Ca/hawhile most agronomic tables useCaODouble-check whether the advice engine returns Ca or CaO; if it is CaO the unit should read
kg CaO/hato avoid agronomist confusion.fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx (1)
37-64: Guard against missingprincipal_id
getSession(request)can legally return a session object without aprincipal_id(e.g. anonymous visitor, corrupt cookie).
BothgetFieldsand downstream services will crash with an opaque 500. Bail out early:const session = await getSession(request) -if (!session.principal_id) throw new Error("Unauthenticated") +if (!session?.principal_id) { + throw new Response("Unauthenticated", { status: 401 }) +}fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx (1)
1-8:⚠️ Potential issue
datais not exported byreact-router; usejson
react-routerv6.4+ exposesjsonfor constructing typedResponseobjects. Importingdatawill throw at compile time.-import { - type LoaderFunctionArgs, - type MetaFunction, - Outlet, - data, - useLoaderData, -} from "react-router" +import { + type LoaderFunctionArgs, + type MetaFunction, + Outlet, + json, + useLoaderData, +} from "react-router"Replace subsequent
data(calls withjson(.⛔ Skipped due to learnings
Learnt from: SvenVw PR: SvenVw/fdm#132 File: fdm-app/app/routes/farm.create.$b_id_farm.$calendar.access.tsx:54-68 Timestamp: 2025-04-29T11:28:44.181Z Learning: In React Router v7, the `json()` function has been replaced with `data()` for creating responses in loaders and actions.Learnt from: SvenVw PR: SvenVw/fdm#132 File: fdm-app/app/routes/farm.create.$b_id_farm.$calendar.access.tsx:54-68 Timestamp: 2025-04-29T11:28:44.181Z Learning: In React Router v7, the `json()` function has been deprecated and removed. Instead, either return plain JavaScript objects directly from loaders/actions, or use the `data()` function for responses with custom status codes and headers.Learnt from: SvenVw PR: SvenVw/fdm#16 File: fdm-app/app/routes/app.addfarm.$b_id_farm.cultivations.$b_lu_catalogue.fertilizers.tsx:1-1 Timestamp: 2024-12-16T10:56:07.561Z Learning: The project uses `react-router` v7, and the `data` function is exported and used for error handling in loaders and actions.fdm-calculator/src/doses/d.ts (2)
1-20: Excellent JSDoc documentation!The documentation clearly describes each nutrient dose property with proper units and explanations.
7-8: Note: Property naming convention changed from oxide to elemental notationThe properties have been renamed from
p_dose_p2o5andp_dose_k2otop_dose_pandp_dose_k. While the JSDoc still mentions P2O5 and K2O in the descriptions, the property names use elemental notation. Ensure this naming convention change is intentional and consistently applied throughout the codebase.fdm-calculator/src/doses/calculate-dose.test.ts (2)
24-90: Comprehensive test coverage for all nutrientsThe test properly validates calculations for all nutrient types including macro and micronutrients, with appropriate use of
toBeCloseTofor floating-point precision.
5-21: Good practice: Centralized initial dose baselineUsing a shared
initialDoseconstant ensures consistency across tests and makes it easy to maintain the expected zero-state structure.fdm-calculator/src/doses/calculate-dose.ts (2)
4-36: Excellent documentation with clear examplesThe JSDoc provides comprehensive parameter descriptions, return type details, error conditions, and a practical usage example.
97-121: Correct unit conversions for agricultural standardsThe dose calculations properly convert nutrient rates:
- Macro/secondary nutrients: g/kg → kg/kg (÷1000)
- Trace elements: mg/kg → kg/kg (÷1000000)
This aligns with standard agricultural measurement units.
There was a problem hiding this comment.
Actionable comments posted: 8
🔭 Outside diff range comments (3)
fdm-core/src/fertilizer.ts (1)
120-130: 💡 Verification agent🧩 Analysis chain
Typo fixed – double-check other call-sites
p_cr_rtis now correct, nice. Please grep the repo for the oldpr_cr_rtspelling to avoid silent runtimeundefinedvalues.
🏁 Script executed:
#!/bin/bash # Find any remaining occurrences of the old typo rg --line-number 'pr_cr_rt'Length of output: 195
Fix remaining
pr_cr_rttyposTwo more instances of the old typo were found. Please update them to
p_cr_rtto prevent runtimeundefinedvalues:• fdm-core/src/cultivation.test.ts:712
- pr_cr_rt: 350, + p_cr_rt: 350,• fdm-app/app/routes/farm.$b_id_farm.fertilizers.new.tsx:295
- pr_cr_rt: undefined, + p_cr_rt: undefined,fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer.tsx (1)
112-123:⚠️ Potential issueType mismatch risk between loader and UI
loader()now returnsdose: dose.dose, whereas<FertilizerApplicationsCards>expects a fullDoseobject (it accessesp_dose_n,p_dose_k, …).If
calculateDose()returns
{ dose: number }→ runtime error in the UI.
{ dose: Dose }→ OK.Please confirm the actual return type; otherwise pass the full object and let the component pick the fields it needs.
fdm-core/src/fertilizer.test.ts (1)
120-132: 🛠️ Refactor suggestionHeavy duplication – extract a reusable helper
Each test re-creates the same gigantic fertilizer object. This hurts readability and maintenance.
Create a
createTestFertilizer()factory in a test util and spread-override only the fields that vary:// test/utils/fertilizer.ts export function createTestFertilizer(overrides: Partial<FertilizerInput> = {}) { return { p_name_nl: "Test Fertilizer", /* … full default object … */ ...overrides, }; }Then in tests:
await addFertilizerToCatalogue(fdm, principal_id, b_id_farm, createTestFertilizer({ p_cr_rt: 350, }));Also applies to: 195-205, 270-280, 360-370, 455-465, 669-679
🧹 Nitpick comments (24)
fdm-calculator/src/doses/d.ts (2)
1-20: JSDoc no longer matches the renamed propertiesThe text still refers to “phosphate (P2O5)” and “potassium (K2O)” while the keys were renamed to
p_dose_pandp_dose_k.
Either update the wording (e.g. “elemental P”, “elemental K”) or revert to the original*_p2o5/*_k2okeys to avoid confusion in downstream consumers and generated docs.
22-23: Index signature is overly permissive
[key: string]: string | number | undefinedallows any string key with a string value, yet every declared nutrient dose is numeric.
Narrowing tonumber | undefinedprevents accidental string assignment and preserves type-safety.- [key: string]: string | number | undefined + [key: string]: number | undefined.changeset/calm-candies-mix.md (1)
5-5: Minor phrasing nit“Add nutrient advice as new application” → “Add Nutrient Advice application” for consistent casing with other changeset titles.
.changeset/eager-mangos-shake.md (1)
5-5: Clarify parameter name in descriptionConsider quoting the incorrect name as well for clarity:
“Fix typo:pr_cr_rt→p_cr_rtinaddFertilizerToCatalogueinput parameter.”.changeset/rich-eagles-rest.md (1)
5-5: Spelling“Expand number of nutrients in the output of
calculateDose”.changeset/solid-planes-sell.md (1)
1-6: Consider adding a short rationale to the changeset bodyThe summary only states what changed. A one-liner explaining why the extra per-application dose information is useful (e.g. UI needs, API contract) makes the changelog more helpful downstream.
fdm-app/app/components/blocks/fertilizer-applications/cards.tsx (1)
124-130: Verify that the newp_dose_k/p_dose_pfields are always definedIf
calculateDoseomits a property,Math.round(undefined)in the card will displayNaN kg/ha.
A tiny guard avoids leaking this to production:- value: dose.p_dose_k, + value: dose.p_dose_k ?? 0, // default to 0 when undefinedfdm-app/app/routes/farm.create.$b_id_farm.$calendar.cultivations.$b_lu_catalogue.fertilizers.tsx (1)
135-138: Minor perf / readability: consider aMapinstead of O(n²) duplicate detection
Array#findinside thereducecreates an O(n²) worst-case loop when many applications exist.
Using aMapkeyed by the composite signature (e.g.${p_id_catalogue}-${p_app_amount}-${p_app_method}-${p_app_date.getTime()}) removes the nested scan and simplifies the code.fdm-app/app/components/blocks/nutrient-advice/types.d.ts (1)
1-8: Nit: make the descriptor immutable for stronger type safety-export type NutrientDescription = { +export type NutrientDescription = { name: string, symbol: string type: "primary" | "secondary" | "trace", unit: string adviceParameter: string doseParameter: string -} +} & Readonly<Record<string, unknown>>Alternatively, declare the returned array in
nutrients.tsasas constso callers get literal string types instead of broadstring.fdm-app/app/components/blocks/nutrient-advice/nutrients.ts (1)
3-5: Return the arrayas constto preserve literal types- const nutrientDescription: NutrientDescription[] = [ + const nutrientDescription = [ … - ] - return nutrientDescription + ] as const satisfies readonly NutrientDescription[] + return nutrientDescriptionBenefits:
• Callers get exact literal types forsymbol,unit, … (better autocomplete / exhaustiveness checks).
• No extra variable annotation needed.fdm-app/app/components/blocks/sidebar/apps.tsx (2)
48-55: Reduce duplication when building navigation linksYou now have three nearly identical blocks (
atlasLink,nutrientBalanceLink,nutrientAdviceLink).
Consider a helper:function buildLink(base: string): string | undefined { if (isCreateFarmWizard) return undefined return farmId ? `/farm/${farmId}/${selectedCalendar}/${base}` : undefined }…and call
buildLink("nutrient_advice"), etc.
104-123: Accessibility: indicate disabled state witharia-disabledThe fallback
<span>variant visually mutes the item but does not expose disabled state to screen readers.
Addaria-disabled="true"(or drop‐intabIndex={-1}) to avoid confusing keyboard users.fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx (2)
37-64: Consistent error-handling style between loadersOther loaders (
fertilizers.tsx, etc.)return handleLoaderError(error)while this onethrow handleLoaderError(error).
Both work, but mixing patterns can confuse future maintainers and complicate test setups. Pick one style project-wide.
40-44: Edge-case: guard against empty but definedb_id_farm
if (!b_id_farm)rejects""andundefined, but not the string" ".
if (!b_id_farm?.trim())ensures the param contains a non-blank value.fdm-calculator/src/doses/get-dose-field.test.ts (2)
128-166: Assertion is brittle – use partial matching for dynamic objects
toEqualrequires an exact structural match, which makes the test fragile when extra properties are added by the implementation (e.g. future nutrients). PrefertoMatchObject(orexpect.objectContaining) to assert only the properties that matter for this scenario.- expect(await getDoseForField({ fdm, principal_id, b_id })).toEqual( - expectedResult, - ) + expect(await getDoseForField({ fdm, principal_id, b_id })).toMatchObject( + expectedResult, + )
203-225: Same brittleness in the “no applications” caseApply the same partial-matching strategy here for consistency and future-proofing.
fdm-app/app/components/blocks/header/nutrient-advice.tsx (1)
45-51: UX: show a fallback label whenb_nameis missingCurrently
undefinedwill render literally. Small guard avoids an empty menu item.- {option.b_name} + {option.b_name ?? "Onbekend perceel"}fdm-app/app/integrations/nmi.ts (2)
3-3: Remove unused import
numberis imported fromzodbut never used.
148-149:currentSoilDatatyped asanyDeclare a proper interface for the soil-measurement objects to regain type-safety and satisfy
noExplicitAny.interface SoilMeasurement { parameter: string value: number a_depth_lower: number } async function getNutrientAdvice( b_lu_catalogue: string, b_centroid: [number, number], - currentSoilData: any, + currentSoilData: SoilMeasurement[], )🧰 Tools
🪛 Biome (1.9.4)
[error] 148-148: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
fdm-app/app/components/blocks/nutrient-advice/cards.tsx (1)
95-109:percentagecan exceed 100% for trace nutrients – adjust colour logicTrace elements (e.g. Cu, Zn) may legitimately exceed 100 %. Instead of hard-coding EOC/others, consider parameterizing the threshold per nutrient or simply clamping the value.
Not urgent, but may avoid misleading orange/red bars for micronutrients.
fdm-calculator/src/doses/calculate-dose.test.ts (2)
69-86: Magic expected values – add inline explanationThe constants (e.g.
0.000006kg Na / ha) are not self-evident. Readers (and future maintainers) cannot verify correctness without manual recalculation.Add a short comment explaining the formula or intermediary steps for at least one micro-nutrient; this speeds up future test audits.
92-110:initialDoseduplication – expose from calculator package
initialDoseis re-declared in multiple test files. Export a helper (e.g.createZeroDose()) fromfdm-calculatorto keep tests DRY and synced with model changes.fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx (1)
127-131: Component name is misleading.
FarmBalanceNitrogenBlockno longer describes the nutrient-advice layout. Rename for clarity and easier grep-ability.fdm-app/app/components/blocks/nutrient-advice/kpi.tsx (1)
95-107: Zero advice values distort deficit detection.
percentage = advice ? … : 0marks nutrients withadvice === 0as 0 % applied → always deficit. Skip nutrients with a zero advice to avoid false warnings.-if (percentage < deficitThreshold) { +if (advice > 0 && percentage < deficitThreshold) {Apply similar guard in the excess card (
percentage >= …).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
fdm-app/app/components/ui/progress.tsxis excluded by!fdm-app/app/components/ui/**pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (24)
.changeset/calm-candies-mix.md(1 hunks).changeset/eager-mangos-shake.md(1 hunks).changeset/rich-eagles-rest.md(1 hunks).changeset/solid-planes-sell.md(1 hunks)fdm-app/app/components/blocks/fertilizer-applications/cards.tsx(1 hunks)fdm-app/app/components/blocks/header/nutrient-advice.tsx(1 hunks)fdm-app/app/components/blocks/nutrient-advice/cards.tsx(1 hunks)fdm-app/app/components/blocks/nutrient-advice/kpi.tsx(1 hunks)fdm-app/app/components/blocks/nutrient-advice/nutrients.ts(1 hunks)fdm-app/app/components/blocks/nutrient-advice/types.d.ts(1 hunks)fdm-app/app/components/blocks/sidebar/apps.tsx(3 hunks)fdm-app/app/integrations/nmi.ts(2 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer.tsx(1 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx(1 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx(1 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx(1 hunks)fdm-app/app/routes/farm.create.$b_id_farm.$calendar.cultivations.$b_lu_catalogue.fertilizers.tsx(1 hunks)fdm-app/package.json(1 hunks)fdm-calculator/src/doses/calculate-dose.test.ts(1 hunks)fdm-calculator/src/doses/calculate-dose.ts(1 hunks)fdm-calculator/src/doses/d.ts(1 hunks)fdm-calculator/src/doses/get-dose-field.test.ts(2 hunks)fdm-core/src/fertilizer.test.ts(7 hunks)fdm-core/src/fertilizer.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
.changeset/solid-planes-sell.md (1)
Learnt from: SvenVw
PR: SvenVw/fdm#75
File: fdm-app/app/routes/farm.$b_id_farm.field.$b_id.fertilizer.tsx:68-71
Timestamp: 2025-02-14T09:56:37.606Z
Learning: The `calculateDose` function in `@svenvw/fdm-calculator` is a synchronous function that includes built-in validation for negative application amounts and nutrient rates.
.changeset/rich-eagles-rest.md (1)
Learnt from: SvenVw
PR: SvenVw/fdm#75
File: fdm-app/app/routes/farm.$b_id_farm.field.$b_id.fertilizer.tsx:68-71
Timestamp: 2025-02-14T09:56:37.606Z
Learning: The `calculateDose` function in `@svenvw/fdm-calculator` is a synchronous function that includes built-in validation for negative application amounts and nutrient rates.
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx (1)
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.
fdm-calculator/src/doses/calculate-dose.ts (1)
Learnt from: SvenVw
PR: SvenVw/fdm#75
File: fdm-app/app/routes/farm.$b_id_farm.field.$b_id.fertilizer.tsx:68-71
Timestamp: 2025-02-14T09:56:37.606Z
Learning: The `calculateDose` function in `@svenvw/fdm-calculator` is a synchronous function that includes built-in validation for negative application amounts and nutrient rates.
🧬 Code Graph Analysis (5)
fdm-app/app/components/blocks/nutrient-advice/nutrients.ts (1)
fdm-app/app/components/blocks/nutrient-advice/types.d.ts (1)
NutrientDescription(1-8)
fdm-core/src/fertilizer.ts (1)
fdm-core/src/db/schema.ts (1)
fertilizersCatalogueTypeInsert(239-240)
fdm-app/app/components/blocks/header/nutrient-advice.tsx (1)
fdm-app/app/store/calendar.tsx (1)
useCalendarStore(11-15)
fdm-calculator/src/doses/calculate-dose.ts (2)
fdm-calculator/src/doses/d.ts (1)
Dose(21-39)fdm-core/src/db/schema.ts (1)
fertilizers(112-120)
fdm-app/app/components/blocks/nutrient-advice/kpi.tsx (3)
fdm-calculator/src/doses/d.ts (1)
Dose(21-39)fdm-app/app/components/custom/loadingspinner.tsx (1)
LoadingSpinner(13-35)fdm-app/app/components/blocks/nutrient-advice/types.d.ts (1)
NutrientDescription(1-8)
🪛 Biome (1.9.4)
fdm-app/app/integrations/nmi.ts
[error] 148-148: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
🔇 Additional comments (8)
fdm-app/app/routes/farm.create.$b_id_farm.$calendar.cultivations.$b_lu_catalogue.fertilizers.tsx (1)
145-146: Verify if only the scalardosevalue is sufficient downstreamThe loader now exposes
dose: dose.dose, discarding the rest of the object returned bycalculateDose.
Please confirm that:
<FertilizerApplicationsCards />consumes a scalar number and not the richer object that previously contained e.g. per-nutrient splits or meta-data.- All other loaders that supply
doseto shared components have been refactored identically, otherwise type mismatches will surface.If the full object is still required somewhere, re-expose it or rename the scalar (e.g.
totalDose) to avoid confusion.fdm-app/app/components/blocks/nutrient-advice/nutrients.ts (1)
70-76: Consistency: unit for trace elements should include the oxide form or not ‑ choose oneMost secondary nutrients use oxide units (
kg MgO/ha,kg K2O/ha), but trace elements list the element itself (kg Cu/ha).
Confirm this is intentional; agronomy tables often use oxides for P, K, Mg but not necessarily for Cu, Zn etc. If consistency is desirable adjust here.fdm-app/app/components/blocks/sidebar/apps.tsx (1)
5-6: VerifyBookOpenTextexists in currentlucide-reactversionSome Lucide releases only expose
BookOpen. Using a non-existing icon will crash at runtime.fdm-app/app/components/blocks/header/nutrient-advice.tsx (1)
1-3:⚠️ Potential issueImport should come from
react-router-dom(or Remix) – avoid the slimreact-routerentryUnless you explicitly add
react-routerto your bundle, import hooks & components fromreact-router-dom(@remix-run/reactin Remix). The thinreact-routerpackage excludes DOM bindings and may break at runtime.-import { NavLink, useLocation } from "react-router" +import { NavLink, useLocation } from "react-router-dom"⛔ Skipped due to learnings
Learnt from: SvenVw PR: SvenVw/fdm#124 File: fdm-app/app/components/custom/farm/farm-title.tsx:3-3 Timestamp: 2025-04-18T13:49:17.029Z Learning: In the fdm project, NavLink and other routing components can be imported from either "react-router" or "react-router-dom" as react-router-dom is included in react-router.Learnt from: SvenVw PR: SvenVw/fdm#45 File: fdm-app/app/routes/farm.$b_id_farm.settings._index.tsx:1-1 Timestamp: 2025-01-14T16:06:21.832Z Learning: In the fdm project, `redirect` and other routing utilities should be imported from `react-router` instead of `react-router-dom`.Learnt from: SvenVw PR: SvenVw/fdm#45 File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:1-1 Timestamp: 2025-01-14T16:06:24.294Z Learning: In the fdm-app codebase, the `redirect` function should be imported from `react-router`, not `react-router-dom`.Learnt from: SvenVw PR: SvenVw/fdm#138 File: fdm-app/app/components/custom/fertilizer-applications/form.tsx:6-6 Timestamp: 2025-05-09T14:41:43.484Z Learning: The project uses React Router v7 which exports a Form component directly from the "react-router" package, making importing from "@remix-run/react" unnecessary.fdm-app/app/components/blocks/nutrient-advice/cards.tsx (1)
160-172: Date formatting assumesDateobject
p_app_datemay arrive as ISO string from the API. Wrap innew Date(...)or ensure type isDateupstream to avoid “Invalid Date” in Safari.- format(fertilizerApplication?.p_app_date, "PP", { locale: nl }) + format(new Date(fertilizerApplication.p_app_date), "PP", { locale: nl })fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx (2)
91-99: Guard againstgetFieldsreturningundefined.
getFieldsmight yieldundefinedor an empty array; calling.mapwithout a check will crash. Consider:-const fields = await getFields(...) -const fieldOptions = fields.map(...) +const fields = (await getFields(...)) ?? [] +if (fields.length === 0) { + throw json("not found: fields", { status: 404 }) +} +const fieldOptions = fields.map(...)
1-8:⚠️ Potential issueReplace non-existent
data()withjson()(or plainResponse).
react-routerexportsjson,defer,redirect, but notdata. Importing and callingdata()will throw instantly in the loader, so the route can never resolve.-import { - type LoaderFunctionArgs, - type MetaFunction, - Outlet, - data, - useLoaderData, -} from "react-router" +import { + type LoaderFunctionArgs, + type MetaFunction, + Outlet, + json, + useLoaderData, +} from "react-router" ... - throw data("invalid: b_id_farm", { status: 400 }) + throw json("invalid: b_id_farm", { status: 400 })Repeat for the two other
data()calls.Also applies to: 50-54, 68-72
⛔ Skipped due to learnings
Learnt from: SvenVw PR: SvenVw/fdm#132 File: fdm-app/app/routes/farm.create.$b_id_farm.$calendar.access.tsx:54-68 Timestamp: 2025-04-29T11:28:44.181Z Learning: In React Router v7, the `json()` function has been replaced with `data()` for creating responses in loaders and actions.Learnt from: SvenVw PR: SvenVw/fdm#16 File: fdm-app/app/routes/app.addfarm.$b_id_farm.cultivations.$b_lu_catalogue.fertilizers.tsx:1-1 Timestamp: 2024-12-16T10:56:07.561Z Learning: The project uses `react-router` v7, and the `data` function is exported and used for error handling in loaders and actions.fdm-calculator/src/doses/calculate-dose.ts (1)
48-67: Property list likely missesp_eoc_rtand silently ignores unknown keys.The validation array contains
"p_eoc"while later you readfertilizer.p_eoc.
If the database field is actuallyp_eoc_rt(keeping the_rtsuffix like other nutrients) the current guard won’t catch negative values and downstream math will always multiply byundefined → 0. Verify the correct key and keep naming consistent.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
fdm-app/app/components/blocks/nutrient-advice/kpi.tsx (1)
268-272: (Duplicate) No loading state style for excess-card icon containerThe icon container of the excess KPI does not handle
navigation.state === "loading", unlike the deficit card.
This was mentioned previously and marked “as intended”; re-flagging only for completeness.
🧹 Nitpick comments (3)
fdm-calculator/src/doses/calculate-dose.ts (3)
65-70: False negatives in the non-negative-rate check
fert[rate] ? fert[rate] < 0 : falseskips validation when the value is0or explicitly set tonull.
A simpler, safer guard:- nutrientRates.some((rate) => (fert[rate] ? fert[rate] < 0 : false)), + nutrientRates.some((rate) => fert[rate] !== undefined && fert[rate]! < 0),This still allows
0, but no longer swallowsnull.
100-102:if (fertilizer)is redundantThe preceding
throwguaranteesfertilizeris defined – the extra guard and indentation can be dropped to reduce nesting.
129-134: Minor:p_app_idcheck is unnecessary
totalDosenever containsp_app_id, so theif (key !== "p_app_id")branch costs CPU without benefit.
Either remove the key from the iteration list up-front or drop the conditional.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
fdm-app/app/components/blocks/header/nutrient-advice.tsx(1 hunks)fdm-app/app/components/blocks/nutrient-advice/cards.tsx(1 hunks)fdm-app/app/components/blocks/nutrient-advice/kpi.tsx(1 hunks)fdm-app/app/integrations/nmi.ts(2 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx(1 hunks)fdm-calculator/src/doses/calculate-dose.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- fdm-app/app/integrations/nmi.ts
- fdm-app/app/components/blocks/nutrient-advice/cards.tsx
- fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
- fdm-app/app/components/blocks/header/nutrient-advice.tsx
🧰 Additional context used
🧠 Learnings (1)
fdm-calculator/src/doses/calculate-dose.ts (1)
Learnt from: SvenVw
PR: SvenVw/fdm#75
File: fdm-app/app/routes/farm.$b_id_farm.field.$b_id.fertilizer.tsx:68-71
Timestamp: 2025-02-14T09:56:37.606Z
Learning: The `calculateDose` function in `@svenvw/fdm-calculator` is a synchronous function that includes built-in validation for negative application amounts and nutrient rates.
🧬 Code Graph Analysis (1)
fdm-calculator/src/doses/calculate-dose.ts (2)
fdm-calculator/src/doses/d.ts (1)
Dose(21-39)fdm-core/src/db/schema.ts (1)
fertilizers(112-120)
🪛 GitHub Check: calculator (22)
fdm-calculator/src/doses/calculate-dose.ts
[failure] 96-96: src/doses/calculate-dose.test.ts > calculateDose > should handle empty fertilizers array
Error: Fertilizer fert1 not found for application app1
❯ calculateDose src/doses/calculate-dose.ts:96:19
❯ src/doses/calculate-dose.test.ts:158:50
[failure] 96-96: src/doses/calculate-dose.test.ts > calculateDose > should handle missing fertilizers by returning zero doses
Error: Fertilizer fert_missing not found for application app1
❯ calculateDose src/doses/calculate-dose.ts:96:19
❯ src/doses/calculate-dose.test.ts:137:50
🔇 Additional comments (1)
fdm-app/app/components/blocks/nutrient-advice/kpi.tsx (1)
7-7:⚠️ Potential issueImport
useNavigationfromreact-router-dominstead ofreact-routerThe hook is exported by
react-router-dom; importing fromreact-routerworks only in monorepo builds where both packages are re-exported, which is brittle.-import { useNavigation } from "react-router" +import { useNavigation } from "react-router-dom"⛔ Skipped due to learnings
Learnt from: SvenVw PR: SvenVw/fdm#45 File: fdm-app/app/routes/farm.$b_id_farm.settings._index.tsx:1-1 Timestamp: 2025-01-14T16:06:21.832Z Learning: In the fdm project, `redirect` and other routing utilities should be imported from `react-router` instead of `react-router-dom`.Learnt from: SvenVw PR: SvenVw/fdm#45 File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:1-1 Timestamp: 2025-01-14T16:06:24.294Z Learning: In the fdm-app codebase, the `redirect` function should be imported from `react-router`, not `react-router-dom`.
| }: NutrientKPICardForNutrientExcessProps) { | ||
| const navigation = useNavigation() | ||
| const excessThreshold = 105 | ||
|
|
There was a problem hiding this comment.
is thre threshold fixed? is a 5% deviation not "acceptable deviation or uncertainty"?
There was a problem hiding this comment.
It is now hardcoded, but we can adjust the value if needed
| }, | ||
| { | ||
| name: "Organische koolstof", | ||
| symbol: "EOC", |
There was a problem hiding this comment.
oke. we might check use of EOM and EOC for use in the srm list.
There was a problem hiding this comment.
The NMI API returns an advice for EOC, if am a correct, so I would suggest we use the parameter returnded by NMI API
| }, | ||
| { | ||
| name: "Boor", | ||
| symbol: "B", |
There was a problem hiding this comment.
Can be used both, but Wikipedia uses Boor as first name so I thought to use that one: https://nl.wikipedia.org/wiki/Boor_(element)
| a_nmin_cc_d30 = item.value | ||
| } else if (item.a_depth_lower <= 60) { | ||
| a_nmin_cc_d60 = item.value | ||
| } |
There was a problem hiding this comment.
note that a_nmin_cc_d30 and a_nmin_cc_d60 are also paramters in pandex. the new SoilReader package is using the new variable names a_nh4_cc, a_no3_cc and a_nmin_cc with separate depth.
There was a problem hiding this comment.
Yes, but as the NMI API uses A_NMIN_CC_D30 and A_NMIN_CC_D60 a conversion has to be made
| * @param {LoaderFunctionArgs} args - The arguments passed to the loader function, including the request and parameters. | ||
| * @returns {Promise<{ field: Field }>} - A promise that resolves to an object containing the fetched field data. | ||
| * @throws {Error} - Throws an error if the `b_id_farm` or `b_id` parameter is missing. | ||
| * @throws {Error} - Throws an error if any error occurs during the process, handled by `handleLoaderError`. |
There was a problem hiding this comment.
throws has two outputs/error messages
There was a problem hiding this comment.
Yes, both errors are possible.
| { | ||
| p_id: "fert1", | ||
| p_n_rt: 100, | ||
| p_p_rt: 50, |
There was a problem hiding this comment.
its correct that n_effective not in?
There was a problem hiding this comment.
Can you please explain? This is just regulat total nitrogen as that is the definition of p_n_rt
gerardhros
left a comment
There was a problem hiding this comment.
nice update. please note that soilReader output has changed as requested.
Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Tests
Chores